/* ══════════════════════════════════════════════════════════════════════════
   Refonte design DRM, lot D1 (2026-09-17)
   ══════════════════════════════════════════════════════════════════════════
   Fondations et composants du nouveau système visuel (maquettes Claude
   Design : « DRM Systeme Visuel », « DRM Header », « DRM Footer »,
   « DRM Carte Produit », « DRM Ecrans C1-C2 »), transposées en CSS pur.

   Chargé APRÈS design-system.css et APRÈS le thème actif (style_*.css) dans
   templates/base.html.twig, sur tous les sites et tous les thèmes, jamais de
   couleur de marque en dur ici : --ds-accent / --ds-accent-light /
   --ds-on-accent / --ds-primary-bg / --ds-on-primary sont dérivés côté serveur
   de --theme-active-color / --theme-color / --color-on-accent (déjà résolus
   par site, voir SiteContext + Setting::getFromGroup('DESIGN')) et de la règle
   du bouton principal (ColorContrast::primaryBgFor()). Un fallback pur CSS est
   posé ci-dessous pour le cas où le tenant n'a encore aucune couleur DESIGN en
   base (site de test sans surcharge) : la valeur calculée côté serveur dans
   base.html.twig (bloc <style> après ce fichier) prend le dessus dès qu'elle
   existe.

   Volontairement additif : ne renomme aucun token existant de
   design-system.css (--ds-space-*, --ds-radius-*, --ds-shadow-card*,
   --ds-focus-ring-*, --ds-font-size-*), les redéfinit seulement quand la
   maquette l'exige explicitement (ombres de carte notamment, voir note de
   transposition du système visuel), et les réutilise partout ailleurs.

   Interdit gardé : ni police externe (Inter/Space Grotesk déjà vendorisées via
   --font-text/--font-display, voir style_*.css), ni image d'ambiance, ni
   couleur codée en dur hors des tokens ci-dessous et des couleurs sémantiques
   (stock, erreur, information) autorisées par le brief. */

:root {
    /* ── Neutres (six gris nommés, sans teinte bleutée) ── */
    --ds-grey-00: #ffffff;
    --ds-grey-05: #f6f6f7;
    --ds-grey-15: #e8e8ea;
    --ds-grey-25: #d6d6da;
    --ds-grey-40: #a8a8ae;
    --ds-grey-60: #6b6b72;
    --ds-grey-95: #1c1c1e;

    /* Bordure de champ de saisie : 3,4:1 sur blanc (WCAG 1.4.11, 3:1 minimum). --ds-grey-25 (1,4:1) reste la bordure
       décorative des cartes et filets. Appliqué pour l'instant au seul formulaire d'inscription professionnelle
       (.ds-auth-bloc), pas à toute l'interface : l'étendre se décide écran par écran. */
    --ds-champ-bord: #8a8a91;

    /* ── Accent du site : dérivé de --theme-active-color / --theme-color
       (voir base.html.twig). Fallback pur CSS ici, écrasé par la valeur
       calculée serveur dès qu'un tenant a une couleur DESIGN. ── */
    --ds-accent: var(--theme-active-color, var(--theme-color, #1c1c1e));
    --ds-accent-light: var(--theme-active-color2, var(--theme-color-light, #f6f6f7));
    --ds-on-accent: var(--color-on-accent, #ffffff);
    --ds-on-accent-light: var(--ds-grey-95);
    --ds-primary-bg: var(--ds-accent);
    --ds-on-primary: var(--ds-on-accent);

    /* ── Rayon dédié aux champs/boutons (8px, distinct du --ds-radius-sm
       existant à 4px, voir note de transposition du système visuel) ── */
    --ds-radius-control: 8px;

    /* ── Ombres du registre « produit de travail » (presque invisibles),
       distinctes de --ds-shadow-card/-hover existants (plus marquées,
       gardées pour ne rien casser ailleurs) ── */
    --ds-shadow-1: 0 1px 2px rgba(16, 16, 20, 0.05);
    --ds-shadow-2: 0 6px 20px rgba(16, 16, 20, 0.08);

    /* ── Densité de tableau (44px front, 36px si .ds-dense) ── */
    --ds-row-h: 44px;

    /* ── Couleurs sémantiques (texte / fond pâle / bordure), jamais pour
       une action ── */
    --ds-ok-fg: #16794c;
    --ds-ok-bg: #eaf5ef;
    --ds-ok-bd: #bfe0ce;
    --ds-warn-fg: #8a5a00;
    --ds-warn-bg: #fdf4e3;
    --ds-warn-bd: #efd9a8;
    --ds-err-fg: #b3261e;
    --ds-err-bg: #fdecea;
    --ds-err-bd: #f3c9c5;
    --ds-info-fg: #1b4e8f;
    --ds-info-bg: #edf3fb;
    --ds-info-bd: #c6d9f0;
    --ds-mute-fg: #6b6b72;
    --ds-mute-bg: #f6f6f7;
    --ds-mute-bd: #e8e8ea;

    /* ── Passe signature (F4) : durees, courbes et rythme vertical.
       Trois durees d'etat, une courbe de sortie, une courbe symetrique, et
       trois espacements verticaux, les seuls autorises sur le front. ── */
    --ds-dur-etat: 150ms;
    --ds-dur-compo: 200ms;
    --ds-dur-page: 180ms;
    --ds-dur-media: 400ms;
    --ds-ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
    --ds-ease-inout: cubic-bezier(0.4, 0, 0.2, 1);
    --ds-rythme-bloc: 24px;
    --ds-rythme-section: 56px;
    --ds-rythme-chapitre: 88px;
}

@media (max-width: 767.98px) {
    :root {
        --ds-rythme-bloc: 16px;
        --ds-rythme-section: 40px;
        --ds-rythme-chapitre: 64px;
    }
}

/* ══════════════════════════════════════════════════
   Typographie, Inter seule, pas de seconde police de titre sur le front
   (brief bloc A). style_sun.css utilise --font-display (Space Grotesk) sur
   les titres publics : on le neutralise ici sur les sélecteurs du front
   habillés par ce lot, sans toucher --font-display lui-même (utilisé
   ailleurs, notamment en back-office, hors périmètre de ce lot).
   ══════════════════════════════════════════════════ */
.drm-h1,
.drm-h2,
h1.title-h1-category,
.titre-page,
.white-box-shad-titre {
    font-family: var(--font-text), -apple-system, "Helvetica Neue", Arial, sans-serif;
    letter-spacing: -0.01em;
}

/* ══════════════════════════════════════════════════
   Composant : boutons (principal / secondaire / discret / destructif)
   Trois tailles : 36 / 44 / 52px. Un seul bouton plein par écran (règle du
   brief) : les classes ci-dessous n'imposent pas la couleur d'un bouton
   existant, elles posent la forme du composant. La couleur reste celle déjà
   pilotée par --ds-primary-bg (bouton principal) ou le contour neutre.
   ══════════════════════════════════════════════════ */
.ds-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-space-2, 8px);
    height: 44px;
    padding: 0 20px;
    border-radius: var(--ds-radius-control);
    border: 1px solid transparent;
    font: 600 15px/1 var(--font-text), -apple-system, sans-serif;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease, opacity 0.15s ease;
    text-decoration: none;
    min-height: 44px;
}
.ds-btn--sm { height: 36px; min-height: 36px; padding: 0 14px; font-size: 14px; }
.ds-btn--lg { height: 52px; min-height: 52px; padding: 0 24px; font-size: 17px; }

.ds-btn--primary {
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
}
/* Survol/appui du bouton principal : une seule definition, plus bas dans ce
   fichier (lot D7, puis F4 : assombrir, jamais eclaircir). Ici, seulement la
   couleur de texte et l'absence de soulignement. */
.ds-btn--primary:hover,
.ds-btn--primary:focus-visible { color: var(--ds-on-primary); text-decoration: none; }
.ds-btn--primary:disabled,
.ds-btn--primary.disabled {
    background: var(--ds-grey-05);
    color: var(--ds-grey-40);
    border-color: var(--ds-grey-15);
    cursor: not-allowed;
}

.ds-btn--secondary {
    background: #fff;
    color: var(--ds-grey-95);
    border-color: var(--ds-grey-25);
}
.ds-btn--secondary:hover,
.ds-btn--secondary:focus-visible { background: var(--ds-grey-05); color: var(--ds-grey-95); text-decoration: none; }

.ds-btn--discret {
    background: transparent;
    color: var(--ds-accent-texte, var(--ds-accent));
    padding: 0 12px;
}
.ds-btn--discret:hover,
.ds-btn--discret:focus-visible { background: var(--ds-accent-light); text-decoration: none; }

.ds-btn--destructif {
    height: 36px;
    padding: 0 14px;
    background: #fff;
    color: var(--ds-err-fg);
    border-color: var(--ds-err-bd);
    font-size: 14px;
    font-weight: 500;
}
.ds-btn--destructif:hover,
.ds-btn--destructif:focus-visible { background: var(--ds-err-bg); color: var(--ds-err-fg); }

.ds-btn:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: var(--ds-focus-ring-offset, 2px);
}

/* ══════════════════════════════════════════════════
   Composant : champs, sélecteur, case à cocher, sélecteur de quantité
   ══════════════════════════════════════════════════ */
.ds-field { display: flex; flex-direction: column; gap: 6px; }
.ds-field > label,
.ds-form-label {
    font-size: 14px;
    font-weight: 500;
    color: var(--ds-grey-95);
}
.ds-field input[type="text"],
.ds-field input[type="email"],
.ds-field input[type="search"],
.ds-field input[type="number"],
.ds-field input[type="password"],
.ds-field select,
.ds-field textarea {
    height: 44px;
    padding: 0 12px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    font: 400 16px/1 var(--font-text), sans-serif;
    color: var(--ds-grey-95);
    background: #fff;
}
.ds-field input:disabled {
    color: var(--ds-grey-40);
    background: var(--ds-grey-05);
    border-color: var(--ds-grey-15);
}
.ds-field input[type="checkbox"],
.ds-field input[type="radio"] {
    width: 20px;
    height: 20px;
    accent-color: var(--ds-accent);
}

/* Sélecteur de quantité (moins / champ / plus), respecte le multiple de
   vente déjà géré par le JS existant (.js-change-qte-box, .btn-qty*) : on
   habille sans toucher ni aux classes ni aux attributs data-*. */
.js-change-qte-box .btn-qty,
.js-change-qte-box .input-group-btn .btn {
    width: 44px;
    height: 44px;
    border: 1px solid var(--ds-grey-25);
    background: #fff;
    color: var(--ds-grey-95);
    border-radius: 0;
}
.js-change-qte-box .btn-qty:hover { background: var(--ds-grey-05); }
.js-change-qte-box .form-control.input-number {
    height: 44px;
    border-top: 1px solid var(--ds-grey-25);
    border-bottom: 1px solid var(--ds-grey-25);
    border-left: 0;
    border-right: 0;
    font: 600 16px/1 var(--font-text), sans-serif;
    font-variant-numeric: tabular-nums;
}

/* ══════════════════════════════════════════════════
   Composant : badges (stock / commande / réception / confiance)
   Réutilise .badge-dispo/.badge-stock-inline déjà posés par le lot E (design-
   system.css leur donne déjà le rayon pilule) : on ajoute ici les couleurs
   sémantiques du nouveau système visuel sur les trois états de stock utilisés
   par la carte produit (commander-article-block-description.html.twig).
   ══════════════════════════════════════════════════ */
.ds-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 22px;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    padding: 0 8px;
    border-radius: var(--ds-radius-sm, 4px);
    border: 1px solid transparent;
}
/* F24 : pastille de 6px au trait plein, couleur semantique heritee, jamais
   d'icone dans un badge de statut. */
.ds-badge--ok::before,
.ds-badge--warn::before,
.ds-badge--err::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: currentColor;
}
.ds-badge--ok,
.badge-stock-inline--ok { background: var(--ds-ok-bg); color: var(--ds-ok-fg); border-color: var(--ds-ok-bd); }
.ds-badge--warn { background: var(--ds-warn-bg); color: var(--ds-warn-fg); border-color: var(--ds-warn-bd); }
.ds-badge--err,
.badge-stock-inline--ko { background: var(--ds-err-bg); color: var(--ds-err-fg); border-color: var(--ds-err-bd); }
.ds-badge--info { background: var(--ds-info-bg); color: var(--ds-info-fg); border-color: var(--ds-info-bd); }
.ds-badge--mute { background: var(--ds-mute-bg); color: var(--ds-mute-fg); border-color: var(--ds-mute-bd); }

.badge-stock-inline {
    font-size: 13px;
    font-weight: 600;
    padding: 4px 10px;
    border: 1px solid transparent;
}
.badge-stock-inline i.fa-circle { font-size: 6px; margin-right: 6px; vertical-align: middle; }

/* ══════════════════════════════════════════════════
   Composant : fil d'Ariane, pagination, chips de filtre
   ══════════════════════════════════════════════════ */
.breadcrumb,
.ariane-box {
    background: transparent !important;
    padding: 0 !important;
    margin: 0 0 var(--ds-space-3, 12px) !important;
    font-size: 14px;
}
.breadcrumb-item a,
.ariane-box a { color: var(--ds-grey-60); text-decoration: none; }
.breadcrumb-item a:hover,
.ariane-box a:hover { color: var(--ds-grey-95); text-decoration: underline; }
.breadcrumb-item + .breadcrumb-item::before { color: var(--ds-grey-25); }
.breadcrumb-item.active,
.breadcrumb-item.font-weight-bold { color: var(--ds-grey-95); }

.pagination-category .pagination,
.pagination .page-item .page-link {
    gap: 8px;
}
.pagination .page-item .page-link {
    min-width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--ds-radius-control);
    border: 1px solid var(--ds-grey-25);
    color: var(--ds-grey-95);
    font-size: 15px;
}
.pagination .page-item.active .page-link {
    background: var(--ds-accent);
    border-color: var(--ds-accent);
    color: var(--ds-on-accent);
}

.ds-filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 12px;
    border-radius: var(--ds-radius-pill, 20px);
    background: var(--ds-accent-light);
    border: 1px solid var(--ds-accent);
    font-size: 14px;
    font-weight: 500;
    color: var(--ds-grey-95);
}
.ds-filter-chip button {
    border: 0;
    background: transparent;
    font-size: 16px;
    line-height: 1;
    color: var(--ds-grey-60);
    cursor: pointer;
    padding: 0;
}

/* ══════════════════════════════════════════════════
   Composant : état vide (catalogue filtré, panier, recherche)
   ══════════════════════════════════════════════════ */
.ds-empty-state {
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 56px 24px;
    text-align: center;
}
.ds-empty-state__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border: 0;
    margin-bottom: 16px;
    color: var(--ds-grey-40);
    font-size: 20px;
}
.ds-empty-state__title { margin: 0 0 8px; font-size: 20px; font-weight: 600; color: var(--ds-grey-95); }
.ds-empty-state__text { margin: 0 0 20px; font-size: 16px; color: var(--ds-grey-60); }
.ds-empty-state__actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

/* ══════════════════════════════════════════════════
   Composant : squelette de chargement
   ══════════════════════════════════════════════════ */
@keyframes dsSkeleton { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } }
.ds-skeleton-line {
    display: block;
    height: 14px;
    border-radius: 4px;
    background: linear-gradient(90deg, #f0f0f2 25%, #e6e6e9 37%, #f0f0f2 63%);
    background-size: 400% 100%;
    animation: dsSkeleton 1.4s linear infinite;
}

/* ══════════════════════════════════════════════════
   Composant : en-tête de section (H2 + action)
   ══════════════════════════════════════════════════ */
.ds-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
    margin-bottom: 24px;
    flex-wrap: wrap;
}
.ds-section-head h2 { margin: 0; }

/* ══════════════════════════════════════════════════
   Header du site de vente
   ══════════════════════════════════════════════════
   Réutilise les sélecteurs réels (header sticky, recherche, panier), sans
   toucher aux ids/classes dont dépend le JS (voir INVENTAIRE-ECRANS-
   COMPOSANTS.md §4) : #header, #header-sticky-sentinel, .top-header,
   #bottom-header, .search-form-content, #search-products[-fixed],
   .header-panier, #menu-nav-mobile. */
#header {
    background: #fff;
    box-shadow: none;
    border-bottom: 1px solid var(--ds-grey-15);
}
.top-bar-brand {
    background: var(--ds-accent-light);
    color: var(--ds-grey-95);
    font-size: 13px;
}
.top-bar-brand a { color: var(--ds-grey-95); }
.top-header {
    background: var(--ds-accent-light);
    border-bottom: 1px solid var(--ds-grey-15);
    font-size: 13px;
}
.top-header a { color: var(--ds-grey-95); }
#bottom-header { background: #fff; }
.logo-header,
.logo-header-center { max-height: 44px; width: auto; }

.search-form-content,
#search-products-fixed-wrapper .form-search-bg {
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    background: #fff;
}
.search-form-content input.js-search-products-input,
#search-products-fixed {
    font: 400 15px/1 var(--font-text), sans-serif;
    color: var(--ds-grey-95);
}

.header-connexion-link,
.account-link {
    color: var(--ds-grey-95);
    font-weight: 500;
}
.header-panier.cart-link {
    color: var(--ds-grey-95);
    font-weight: 600;
}
.header-paniers-nbr {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.navigation-site .nav-link,
.navigation-site a.nav-link {
    font-size: 15px;
    font-weight: 500;
    color: var(--ds-grey-95);
    text-transform: none;
}
.navigation-site .nav-link:hover { color: var(--ds-accent-texte, var(--ds-accent)); }

/* Bandeau de rattachement (bShowUserRattachement) : une seule ligne, accent
   du site, jamais empilé sur mobile (déjà géré par le CSS existant lot F1,
   on n'y touche pas ici : uniquement la couleur). */
#header-top-rattachement-col a,
#header-top-rattachement-col strong { color: var(--ds-grey-95); }

/* Mini-panier anonyme (drawer), déjà fonctionnel : habillage seul. */
.mini-panier-anon-panel { border-radius: 0; box-shadow: var(--ds-shadow-2); }
.mini-panier-anon-titre { font: 600 20px var(--font-text), sans-serif; color: var(--ds-grey-95); }
.mini-panier-anon-btn-cde {
    height: 48px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-size: 16px;
    font-weight: 600;
}
.mini-panier-empty-link {
    display: inline-flex;
    align-items: center;
    height: 44px;
    padding: 0 18px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-size: 15px;
    font-weight: 600;
}

/* ══════════════════════════════════════════════════
   Pied de page
   ══════════════════════════════════════════════════ */
#footer { background: var(--ds-grey-05); border-top: 1px solid var(--ds-grey-15); }
#footer .footer-title-menu-t {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.08em;
    color: var(--ds-grey-60);
}
#footer .content-menu-footer a,
#footer .content-menu-footer-tel a {
    color: var(--ds-grey-95);
    font-size: 15px;
}
#footer .content-menu-footer-tel a { font-weight: 400; }
.ds-footer-legal { display: flex; flex-direction: column; gap: 8px; }
.ds-footer-legal a { font-size: 15px; color: var(--ds-grey-95); }
.ds-footer-mention {
    max-width: 1200px;
    margin: 0 auto;
    padding: 12px 16px 0;
    font-size: 14px;
    color: var(--ds-grey-60);
}

/* ══════════════════════════════════════════════════
   Carte produit
   ══════════════════════════════════════════════════
   Réutilise .product-card-item / .article-img-zone / .product-block-name /
   .product-block-price / .product-cart-btn déjà en place (voir
   commander-article-block.html.twig et commander-article-block-
   description.html.twig) : image 1:1, nom sur 2 lignes, prix + CTA visibles
   sans onglet, bouton pleine largeur. */
.product-card-item {
    border: 1px solid var(--ds-grey-15);
    background: #fff;
}
.article-img-zone {
    aspect-ratio: 1;
    background: repeating-linear-gradient(135deg, #ededef 0 8px, #f6f6f7 8px 16px);
    display: flex;
    overflow: hidden;
}
.article-img-real { width: 100%; height: 100%; object-fit: contain; }
.product-block-name a {
    font-size: 15px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ds-grey-95);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.product-block-price {
    font-size: 18px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ds-grey-95);
}
.product-cart-btn {
    width: 100%;
    height: 44px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    border: 0;
}
.product-cart-btn:hover,
.product-cart-btn:focus-visible { filter: brightness(1.12); color: var(--ds-on-primary); }

/* ══════════════════════════════════════════════════
   Accueil (bandeau H1, univers, nouveautés, promotions, qui sommes-nous)
   ══════════════════════════════════════════════════ */
.ds-hero {
    background: var(--ds-accent-light);
    border-bottom: 1px solid var(--ds-grey-15);
    padding: var(--ds-rythme-section) 24px;
}
.ds-hero__inner {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    gap: 32px;
    align-items: center;
    flex-wrap: wrap;
}
.drm-h1 {
    margin: 0;
    font-size: 32px;
    line-height: 1.15;
    letter-spacing: -0.021em;
    font-weight: 600;
    color: var(--ds-grey-95);
    max-width: 26ch;
    text-wrap: balance;
}
.ds-hero__lead { margin: 16px 0 20px; font-size: 17px; line-height: 1.55; color: var(--ds-grey-60); max-width: 56ch; }

.drm-h2,
.category-dashboard-items ~ .titre-page,
.titre-page {
    font-size: 24px;
    line-height: 1.25;
    letter-spacing: -0.014em;
    font-weight: 600;
    color: var(--ds-grey-95);
    text-transform: none;
    text-wrap: balance;
}

.ds-page-section { max-width: 1200px; margin: 0 auto; padding: var(--ds-rythme-section) 24px; }
.ds-two-col { display: grid; gap: 40px; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--ds-grey-15); padding-top: 40px; }
@media (max-width: 900px) { .ds-two-col { grid-template-columns: 1fr; } }
.ds-contact-grid { display: grid; gap: 16px; grid-template-columns: 1fr 1fr; font-size: 15px; line-height: 1.6; color: var(--ds-grey-60); }
.ds-contact-grid dt {
    display: block;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
    margin-bottom: 4px;
}
.ds-contact-grid dd { margin: 0; }

/* ══════════════════════════════════════════════════
   Catégorie / catalogue complet, fil d'Ariane, filtres, grille, tri
   ══════════════════════════════════════════════════ */
.category-page .title-h1-category {
    font-size: 32px;
    line-height: 1.2;
    font-weight: 600;
    color: var(--ds-grey-95);
    text-transform: none;
}
.category-menu-left-title {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
}
.categ-btn-affichage-type {
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    color: var(--ds-grey-60);
}
.categ-btn-affichage-type.active { background: var(--ds-accent-light); color: var(--ds-grey-95); border-color: var(--ds-accent); }

/* ══════════════════════════════════════════════════════════════════════════
   Refonte design DRM, lot D1, REPRISE v2 (2026-09-17)
   ══════════════════════════════════════════════════════════════════════════
   Tout ce qui suit est scopé à `body.ds-page` (posé uniquement par les
   templates redessinés, voir templates/base.html.twig bloc `bodyAttr`) :
   ces pages ont débranché le thème historique (bloc `stylesheetsTheme`
   surchargé, style_*.css et design-system.css ne sont plus chargés). Une
   page NON redessinée n'a pas la classe `ds-page` sur <body> : aucune règle
   ci-dessous ne peut donc l'atteindre, garantie structurelle de non-
   régression (plutôt qu'une simple promesse de ne pas y toucher).

   Restent chargés sur une page ds-page (voir base.html.twig) : Font
   Awesome, jQuery UI (autocomplétion), Bootstrap 4 (grille .container/.row/
   .col-*, utilitaires d-none/d-flex, modale du panier), et ce fichier seul
   en plus. Polices Inter locales ci-dessous (@font-face), jamais Google
   Fonts. Points de rupture réels : 390, 768, 1024, 1440 (brief bloc D). */

@font-face {
    font-family: "Inter";
    src: url("../fonts/Inter-Variable.woff2") format("woff2-variations"), url("../fonts/Inter-Variable.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Inter";
    src: url("../fonts/Inter-Italic-Variable.woff2") format("woff2-variations"), url("../fonts/Inter-Italic-Variable.woff2") format("woff2");
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
}
:root {
    --ds-font: "Inter", -apple-system, "Helvetica Neue", Arial, sans-serif;
}

/* Garde-fou anti-débordement horizontal (repris de style_sun.css
   #page-content-wrapper, ligne ~1226, débranché sur les pages ds-page comme
   le reste du thème) : plusieurs `.row` Bootstrap existants (grille du pied
   de page notamment) portent des marges négatives -15px non compensées à
   cet endroit précis, invisibles quand ce garde-fou existe, provoquant sinon
   un débordement horizontal réel mesuré (document.documentElement.scrollWidth
   > innerWidth) à toutes les largeurs. `overflow: clip` plutôt que `hidden`
   (raison déjà documentée par l'équipe précédente : hidden fait de l'élément
   un conteneur de défilement CSS, ce qui casse le sticky de ses descendants ;
   clip ne crée pas ce conteneur). */
#page-content-wrapper { overflow: clip; }

body.ds-page {
    background: #fff;
    color: var(--ds-grey-95);
    font-family: var(--ds-font);
    font-size: 16px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}
body.ds-page a:not(.ds-btn) { color: var(--ds-accent-texte, var(--ds-accent)); text-decoration: none; }
body.ds-page a:not(.ds-btn):hover { color: var(--ds-grey-95); text-decoration: underline; }
/* .ds-btn (lien ou bouton) garde sa propre couleur pilotée par variante
   (voir .ds-btn--primary/--secondary/--discret plus haut dans ce fichier) :
   sans ce :not(), "body.ds-page a" (plus spécifique que ".ds-btn--primary"
   seul) écrasait le blanc du bouton principal par l'accent du site, bug
   constaté à la vérification navigateur de cette reprise (CTA "Nos
   produits" illisible, texte de la même couleur que le fond). */
body.ds-page a.ds-btn { text-decoration: none; }
body.ds-page a.ds-btn:hover { text-decoration: none; }
body.ds-page .drm-h1,
body.ds-page .drm-h2,
body.ds-page h1,
body.ds-page h2,
body.ds-page h3,
body.ds-page .titre-page,
body.ds-page .title-h1-category {
    font-family: var(--ds-font);
}
body.ds-page .ds-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}


/* ══════════════════════════════════════════════════════════════════════════
   Header redessiné (lot D1a, 2026-09-17)
   ══════════════════════════════════════════════════════════════════════════
   Transposition en classes des styles en ligne de la maquette
   « DRM Header.dc.html » (valeurs reprises telles quelles : 44px de hauteur de
   champ, 520px de largeur maximale de recherche, 8px de rayon, 22/16px pour le
   nom du site, pastille 22px). Aucune couleur en dur : accent via --ds-accent,
   fond et texte de bouton via --ds-primary-bg / --ds-on-primary, neutres via
   les six gris nommés.

   Ces règles ne s'appliquent qu'aux pages redessinées : le markup .ds-header-*
   n'existe que dans _partials/ds-header.html.twig. Elles sont malgré tout
   scopées body.ds-page, comme le reste du fichier, pour que rien ne puisse
   fuiter vers une page non retouchée.
   ══════════════════════════════════════════════════════════════════════════ */

/* WCAG 2.2, 2.4.11 « Focus Not Obscured » : le header est collant, une ancre ou
   un focus clavier ne doit jamais se retrouver caché dessous. */
html { scroll-padding-top: 160px; }

body.ds-page .ds-header {
    position: sticky;
    top: 0;
    z-index: 1000;
    background: var(--ds-grey-00);
    font-family: var(--ds-font);
}
body.ds-page #header-sticky-sentinel { display: block; height: 0; }
/* .headerFixed est posée par scripts_global.js (IntersectionObserver sur la
   sentinelle) une fois le header réellement collé : habillage seul, jamais de
   positionnement, le collage est fait par position:sticky ci-dessus. */
body.ds-page .ds-header.headerFixed { box-shadow: var(--ds-shadow-1); }

body.ds-page .ds-header a { text-decoration: none; }
/* R8 : plus de soulignement generique au survol (il doublait le trait de
   marque sous le wordmark et soulignait les liens qui ne sont que des icones).
   Survol cible : le texte passe de --ds-grey-60 a --ds-grey-95 en 150ms. */
body.ds-page .ds-header a:hover { text-decoration: none; }
body.ds-page .ds-header .ds-header-sections__lien,
body.ds-page .ds-header .ds-header-menu__item,
body.ds-page .ds-header .ds-header-utility a { transition: color var(--ds-dur-etat) var(--ds-ease-out); }
body.ds-page .ds-header .ds-header-sections__lien:hover,
body.ds-page .ds-header .ds-header-menu__item:hover,
body.ds-page .ds-header .ds-header-utility a:hover { color: var(--ds-grey-95); }
body.ds-page .ds-header :focus-visible,
body.ds-page .ds-header-drawer :focus-visible {
    outline: 2px solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: 2px;
    border-radius: 4px;
}

body.ds-page .ds-header-message {
    padding: 8px 32px;
    background: var(--ds-accent);
    color: var(--ds-on-accent);
    font-size: 14px;
    text-align: center;
}

/* ── Bandeau de rattachement : une seule ligne (maquette) ── */
body.ds-page .ds-header-utility {
    display: flex;
    gap: 12px;
    align-items: center;
    justify-content: space-between;
    flex-wrap: nowrap;
    padding: 8px 32px;
    background: var(--ds-accent-light);
    font-size: 14px;
    color: var(--ds-on-accent-light);
    min-width: 0;
}
body.ds-page .ds-header-utility__label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.ds-page .ds-header-utility__label strong { font-weight: 600; }
body.ds-page .ds-header-utility__code { color: var(--ds-on-accent-light); opacity: 0.75; }
body.ds-page .ds-header-utility__link {
    flex: none;
    font-weight: 500;
    color: var(--ds-on-accent-light);
    text-decoration: underline;
}
body.ds-page .ds-header-utility__version { flex: none; font-size: 12px; color: var(--ds-on-accent-light); opacity: 0.8; }

/* ── Ligne 1 : nom ou logo, recherche, compte, panier ── */
body.ds-page .ds-header-main {
    --ds-header-pad-y: 16px;
    display: flex;
    gap: 20px;
    align-items: center;
    padding: var(--ds-header-pad-y) 32px;
    border-bottom: 1px solid var(--ds-grey-15);
    min-width: 0;
}

body.ds-page .ds-header-brand {
    display: inline-flex;
    align-items: center;
    flex: none;
    min-width: 0;
    max-width: 40%;
}
body.ds-page .ds-header-brand:hover { text-decoration: none; }
/* F1 : le trait de marque. Un motif n'existe que s'il est rare : ce trait de
   2px est pose ici, sous le mot, et une seule autre fois dans tout le produit
   (onglet de section actif du header, F2). Il est en CSS, donc il survit a
   l'absence de logo. Aucun dedoublement possible avec un logo qui porterait
   deja un trait : le gabarit rend soit l'image, soit ce mot, jamais les deux
   (ds-header.html.twig lignes 172 a 178). */
body.ds-page .ds-header-brand__nom {
    position: relative;
    padding-bottom: 5px;
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.015em;
    color: var(--ds-accent-texte, var(--ds-accent));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.ds-page .ds-header-brand__nom::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: currentColor;
    border-radius: 1px;
}
body.ds-page .ds-header-brand__logo {
    display: block;
    height: 44px;
    width: auto;
    max-width: 100%;
    object-fit: contain;
}

body.ds-page .ds-header-search {
    position: relative; /* jQuery UI pose la liste d'autocomplétion dans ce formulaire */
    flex: 1 1 200px;
    margin-left: auto;
    min-width: 0;
    max-width: 520px;
    display: flex;
    align-items: center;
    gap: 10px;
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    background: var(--ds-grey-00);
}
/* F7-3 (2026-09-18), retour 3 de Martin : au clic, le champ montrait un double
   contour vert desaligne (la bordure du conteneur passait a l'accent ET la regle
   generique du header posait un anneau rectangulaire, offset 2px, rayon 4px, sur
   l'input a l'interieur). Un seul anneau desormais, porte par le conteneur, qui
   epouse le rayon du champ (l'outline suit le border-radius du conteneur) ; l'input
   ne porte plus aucun anneau. Meme token de focus que les autres champs (F18). */
body.ds-page .ds-header-search:focus-within {
    border-color: var(--ds-accent);
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
}
/* Loupe au trait fin, à gauche dans le champ (Portail). Elle n'est plus un
   bouton : le formulaire ne porte qu'un seul champ, la touche Entrée le soumet
   (soumission implicite HTML), et rien ne vient rogner la largeur utile. */
body.ds-page .ds-header-search__loupe {
    display: inline-flex;
    flex: none;
    color: var(--ds-grey-60);
}
body.ds-page .ds-header-search__input {
    flex: 1;
    min-width: 0;
    height: 44px;
    border: 0;
    background: transparent;
    font: 400 15px/1 var(--ds-font);
    color: var(--ds-grey-95);
}
body.ds-page .ds-header-search__input::placeholder { color: var(--ds-grey-60); }
/* L'anneau vit sur le conteneur (:focus-within ci-dessus) : l'input n'en porte
   aucun. Specificite (0,4,1) volontaire : elle doit battre la regle chapeau
   « body.ds-page .ds-header :focus-visible » (F18, plus bas dans ce fichier) qui,
   sinon, reposait un anneau rectangulaire sur l'input a l'interieur du conteneur
   (le second contour desaligne constate par Martin). */
body.ds-page .ds-header-search .ds-header-search__input:focus,
body.ds-page .ds-header-search .ds-header-search__input:focus-visible { outline: none; }

/* F7-3 : un seul etat de focus pour tous les champs du front. Sur une page
   redessinee, Bootstrap reste charge (globalement, hors du bloc de theme) et sa
   regle .form-control:focus repose un halo bleu (box-shadow .2rem rgba(0,123,255)).
   Cette regle, chargee apres (drm.css est le dernier CSS), le neutralise et pose
   l'anneau du systeme (meme token que les autres champs). Constate sur #inputLogin
   a la connexion (AUDIT-RESPONSIVE-FRONT.md §5). */
body.ds-page .form-control:focus,
body.ds-page input.form-control:focus,
body.ds-page select.form-control:focus,
body.ds-page textarea.form-control:focus {
    box-shadow: none;
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: 1px;
    border-color: var(--ds-focus-ring-color, var(--ds-accent));
}
/* Icônes SVG inline (macros _partials/ds-icones.html.twig) : tracé seul, jamais
   de police d'icônes ni d'emoji de secours. Le trait suit la couleur du texte. */
body.ds-page .ds-icone { display: block; flex: none; }

body.ds-page .ds-header-actions {
    display: flex;
    gap: 4px;
    align-items: center;
    white-space: nowrap;
    margin-left: auto;
    flex: none;
}

body.ds-page .ds-header-connexion,
body.ds-page .ds-header-compte {
    font-size: 15px;
    font-weight: 500;
    color: var(--ds-grey-95);
}
body.ds-page .ds-header-compte {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 44px;
    padding: 0 8px 0 6px;
    border: 0;
    border-radius: var(--ds-radius-control);
    background: transparent;
    font-family: var(--ds-font);
    cursor: pointer;
}
body.ds-page .ds-header-compte:hover { background: var(--ds-grey-05); }
body.ds-page .ds-header-compte__chevron { display: inline-flex; color: var(--ds-grey-60); }
body.ds-page .ds-header-connexion { display: inline-flex; align-items: center; min-height: 44px; }

body.ds-page .ds-header-menu { position: relative; }
body.ds-page .ds-header-menu__panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 1100;
    min-width: 240px;
    max-height: 70vh;
    overflow-y: auto;
    padding: 8px;
    background: var(--ds-grey-00);
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-control);
    box-shadow: var(--ds-shadow-2);
    display: flex;
    flex-direction: column;
}
body.ds-page .ds-header-menu__panel[hidden] { display: none; }
body.ds-page .ds-header-menu__nom {
    padding: 8px 10px;
    font-size: 14px;
    font-weight: 600;
    color: var(--ds-grey-95);
    border-bottom: 1px solid var(--ds-grey-15);
    margin-bottom: 4px;
}
body.ds-page .ds-header-menu__titre {
    padding: 10px 10px 4px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
}
body.ds-page .ds-header-menu__item {
    display: flex;
    align-items: center;
    min-height: 40px;
    padding: 8px 10px;
    border-radius: var(--ds-radius-control);
    font-size: 14px;
    color: var(--ds-grey-95);
}
body.ds-page .ds-header-menu__item:hover { background: var(--ds-grey-05); text-decoration: none; }
body.ds-page .ds-header-menu__item--deconnexion {
    margin-top: 4px;
    border-top: 1px solid var(--ds-grey-15);
    border-radius: 0 0 var(--ds-radius-control) var(--ds-radius-control);
    color: var(--ds-err-fg);
}
/* F7-7 : survol coherent des trois sorties (texte destructif, fond pale). Le
   qualificateur « a. » est necessaire pour battre la regle chapeau
   « body.ds-page a:not(.ds-btn) » (line 724, specificite (0,2,2) a cause du :not)
   qui sinon reteintait la sortie en accent, pas en rouge. */
body.ds-page a.ds-header-menu__item--deconnexion,
body.ds-page a.ds-header-menu__item--deconnexion:hover { color: var(--ds-err-fg); }
body.ds-page a.ds-header-menu__item--deconnexion:hover { background: var(--ds-err-bg); }

body.ds-page .ds-header-prix {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-header-prix label { margin: 0 8px 0 0; cursor: pointer; }

/* Panier (Portail) : pastille de fond gris clair, icône au trait, compteur rond
   en couleur de bouton principal. Plus de mot « Panier » à l'écran, le libellé
   est en aria-label et tenu à jour par ds-header.js après un ajout ajax. */
body.ds-page .ds-header-panier {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    flex: none;
    height: 44px;
    padding: 0 12px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-grey-05);
    color: var(--ds-grey-95);
}
body.ds-page .ds-header-panier:hover { background: var(--ds-grey-15); text-decoration: none; color: var(--ds-grey-95); }
body.ds-page .ds-header-panier__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* ── Liens de section, sur la ligne unique (Portail Coiffinéa) ──
   Les huit catégories ne sont plus dans le header : elles vivent dans la colonne
   de filtres du catalogue. Restent quatre liens courts, qui ne débordent pas. */
body.ds-page .ds-header-sections {
    display: flex;
    gap: 20px;
    align-items: center;
    flex: none;
    min-width: 0;
}
/* Retour de Martin (lot D7) : l'element actif ne porte plus un filet colle sous
   son texte, qui se lisait comme un simple lien souligne. Il porte une barre de
   2px en accent posee sur le bord BAS du header, comme la barre sous
   « Catalogue » du Portail. Le survol n'ajoute jamais de soulignement : il pose
   un fond leger. */
/* Le selecteur porte .ds-header en plus : sans lui, la regle generique
   body.ds-page a:not(.ds-btn) (specificite superieure a cause du :not) reprenait
   la main et repeignait ces liens en accent. */
body.ds-page .ds-header .ds-header-sections__lien {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 10px;
    border-radius: var(--ds-radius-control, 8px);
    font-size: 15px;
    font-weight: 500;
    color: var(--ds-grey-95);
    white-space: nowrap;
    text-decoration: none;
}
body.ds-page .ds-header a.ds-header-sections__lien:hover {
    background: var(--ds-grey-05);
    color: var(--ds-grey-95);
    text-decoration: none;
}
body.ds-page .ds-header .ds-header-sections__lien--actif { font-weight: 600; color: var(--ds-grey-95); }
/* F2 : le second et dernier emploi du trait. Meme epaisseur, meme rayon, meme
   couleur que le texte qu'il souligne ; aucune transition, le trait suit la
   page, il ne glisse pas d'un onglet a l'autre. */
body.ds-page .ds-header .ds-header-sections__lien--actif::after {
    content: "";
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: -10px;
    height: 2px;
    background: currentColor;
    border-radius: 1px;
    transition: none;
}

/* Favoris : cœur au trait (SVG inline), zone tactile de 44px, libellé texte
   associé en ds-sr-only. */
body.ds-page a.ds-header-favoris,
body.ds-page .ds-header-favoris {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: none;
    border-radius: var(--ds-radius-control);
    color: var(--ds-grey-95);
}
body.ds-page .ds-header-favoris:hover { background: var(--ds-grey-05); text-decoration: none; }

/* Pastille d'initiales du compte (Portail) : fond accent pâle, texte calculé
   côté serveur pour rester lisible quel que soit le tenant. */
body.ds-page .ds-header-compte__initiales {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex: none;
    border-radius: 50%;
    background: var(--ds-accent-light);
    /* Le brief demandait « texte --ds-accent sur fond --ds-accent-light ». Sur ce
       socle, --ds-accent-light n'est PAS une teinte pâle : elle est calculée
       serveur (ici #1f6e52 pour un accent #0b3d2e), et la paire demandée tombe à
       1,98:1, illisible. On garde --ds-on-accent-light, l'encre calculée serveur
       pour ce fond (mesurée à 5,9:1), plutôt qu'un contraste cassé par tenant. */
    color: var(--ds-on-accent-light);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
}
body.ds-page .ds-header-compte__nom {
    font-size: 14px;
    font-weight: 600;
    max-width: 12ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Autocomplétion de la recherche (jQuery UI, appendTo le formulaire) ──
   Vignette, nom, référence et prix rendus par searchProductAutocomplete()
   (fonctions_global.js, inchangé) : seul l'habillage change ici. */
body.ds-page .search-products-autocomplete {
    width: 100% !important;
    left: 0 !important;
    top: 46px !important;
    z-index: 1200;
    max-height: 60vh;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 6px;
    background: var(--ds-grey-00);
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-control);
    box-shadow: var(--ds-shadow-2);
    list-style: none;
    margin: 0;
}
body.ds-page .search-products-autocomplete li {
    height: auto !important;
    margin: 0 !important;
    border: 0 !important;
    border-radius: var(--ds-radius-control);
}
body.ds-page .search-products-autocomplete li + li { border-top: 1px solid var(--ds-grey-15) !important; }
body.ds-page .search-products-autocomplete a {
    display: flex !important;
    align-items: center;
    gap: 12px;
    padding: 10px !important;
    margin: 0 !important;
    border: 0 !important;
    color: var(--ds-grey-95) !important;
    background: transparent !important;
    font-size: 14px;
}
body.ds-page .search-products-autocomplete a:hover,
body.ds-page .search-products-autocomplete a:focus,
body.ds-page .search-products-autocomplete .ui-state-active a { background: var(--ds-grey-05) !important; text-decoration: none; }
body.ds-page .search-products-autocomplete .image_autocomplete {
    width: 44px;
    height: 44px;
    object-fit: contain;
    border: 1px solid var(--ds-grey-15) !important;
    border-radius: var(--ds-radius-sm, 4px);
    margin: 0 !important;
    background: var(--ds-grey-05);
}
body.ds-page .search-products-autocomplete .text_autocomplete { font-size: 13px; color: var(--ds-grey-60); }

/* ── Entre 1024 et 1279px : quatre liens de section, un logo, les actions et la
   recherche sur la même ligne ne tiennent qu'en resserrant tout. Sans ce palier,
   le champ de recherche tombait à 30px de large pour un compte disposant des
   quatre sections (mesuré à 1024px). ── */
@media (min-width: 1024px) and (max-width: 1279.98px) {
    body.ds-page .ds-header-main { --ds-header-pad-y: 12px; padding: var(--ds-header-pad-y) 16px; gap: 12px; }
    body.ds-page .ds-header-brand { max-width: 20%; }
    body.ds-page .ds-header-sections { gap: 14px; }
    body.ds-page .ds-header .ds-header-sections__lien { font-size: 14px; }
    body.ds-page .ds-header-search { flex: 1 1 170px; min-width: 150px; max-width: 320px; }
    body.ds-page .ds-header-compte__nom { max-width: 8ch; }
    body.ds-page .ds-header-panier { padding: 0 10px; }
}

/* ── Mobile et tablette (< 1024px) : hamburger, nom, panier carré, puis
   recherche pleine largeur en dessous (maquette) ── */
body.ds-page .ds-header-burger { display: none; }
body.ds-page .ds-header-search-mobile { display: none; }

@media (max-width: 1023.98px) {
    html { scroll-padding-top: 130px; }

    body.ds-page .ds-header-utility { padding: 8px 16px; font-size: 13px; }
    body.ds-page .ds-header-message { padding: 8px 16px; }

    /* Barre de 56px : 6px + 44px de contrôles + 6px, puis la recherche pleine
       largeur sur la ligne suivante (Portail, écran « Mobile »). */
    /* F7-10 + F7-5 (item 9) : padding vertical symetrique (etait 6px en haut,
       10px en bas), la respiration au-dessus et au-dessous de la ligne est egale
       et le champ de recherche descend d'un cran. */
    body.ds-page .ds-header-main {
        flex-wrap: wrap;
        align-items: center;
        gap: 0 8px;
        padding: 12px 16px;
    }
    body.ds-page .ds-header-brand,
    body.ds-page .ds-header-actions { height: 44px; }
    /* F7-9 : bouton de menu, cible de 44px, icone au trait centree (macro
       ds-icones), au lieu des trois barres CSS. */
    body.ds-page .ds-header-burger {
        display: flex;
        align-items: center;
        justify-content: center;
        flex: none;
        width: 44px;
        height: 44px;
        padding: 0;
        border: 1px solid var(--ds-grey-25);
        border-radius: var(--ds-radius-control);
        background: var(--ds-grey-00);
        color: var(--ds-grey-95);
        cursor: pointer;
    }
    body.ds-page .ds-header-brand { flex: 1 1 auto; max-width: none; }
    body.ds-page .ds-header-brand__nom { font-size: 16px; letter-spacing: -0.01em; line-height: 1.2; }
    body.ds-page .ds-header-brand__logo { height: 36px; }

    /* Recherche : une seule ligne pleine largeur sous la première, le champ
       desktop est retiré du rendu (jamais deux champs visibles). */
    body.ds-page #form-search-products { display: none; }
    /* F7-10 (2026-09-18), retour 10 de Martin : sur mobile la recherche prenait une
       ligne pleine largeur et dominait le haut. La maquette « Portail Coiffinea »,
       ecran Mobile, garde bien la recherche sur sa propre ligne sous le header, mais
       posee sur un fond recesse (gris clair) plutot qu'une barre blanche saillante :
       elle se lit comme un champ secondaire, sans dominer. Disposition prescrite par
       la maquette, appliquee telle quelle. Route et fonctionnement inchanges. */
    body.ds-page .ds-header-search-mobile { display: block; flex: 0 0 100%; order: 5; margin-top: 10px; }
    body.ds-page .ds-header-search-mobile .ds-header-search {
        max-width: none;
        background: var(--ds-grey-05);
        border-color: var(--ds-grey-15);
    }

    body.ds-page .ds-header-actions { gap: 2px; }
    /* Le menu du compte vit dans le tiroir en mobile, mais « Connexion » reste
       dans la barre : sans lui, un visiteur anonyme n'avait plus aucune porte
       d'entrée visible sans ouvrir le tiroir (constaté en capture à 390px). */
    body.ds-page .ds-header-menu { display: none; }
    body.ds-page .ds-header-connexion { height: 44px; padding: 0 10px; font-size: 14px; font-weight: 600; }
    /* Même pastille qu'en desktop, juste plus compacte : l'icône et le compteur
       restent lisibles, rien ne change de nature entre les deux largeurs. */
    body.ds-page .ds-header-panier { padding: 0 8px; gap: 4px; }
    body.ds-page .ds-header-sections { display: none; }
}

/* ── Tiroir latéral mobile ── */
body.ds-page .ds-header-drawer-overlay {
    position: fixed;
    inset: 0;
    z-index: 1190;
    background: rgba(16, 16, 20, 0.45);
    opacity: 0;
    transition: opacity 0.2s ease;
}
body.ds-page .ds-header-drawer-overlay--visible { opacity: 1; }
body.ds-page .ds-header-drawer-overlay[hidden] { display: none; }

body.ds-page .ds-header-drawer {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 1200;
    width: min(320px, 88vw);
    display: flex;
    flex-direction: column;
    background: var(--ds-grey-00);
    box-shadow: var(--ds-shadow-2);
    transform: translateX(-100%);
    transition: transform 0.2s ease;
}
body.ds-page .ds-header-drawer[hidden] { display: none; }
body.ds-page .ds-header-drawer--ouvert { transform: translateX(0); }
body.ds-page .ds-header-drawer__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border-bottom: 1px solid var(--ds-grey-15);
    flex: none;
}
body.ds-page .ds-header-drawer__titre { font-size: 16px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-header-drawer__close {
    width: 44px;
    height: 44px;
    border: 0;
    background: transparent;
    font-size: 24px;
    line-height: 1;
    color: var(--ds-grey-60);
    cursor: pointer;
}
body.ds-page .ds-header-drawer__body {
    flex: 1;
    overflow-y: auto;
    padding: 12px 16px 24px;
    display: flex;
    flex-direction: column;
}
body.ds-page .ds-header-drawer__rattachement {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 10px 12px;
    margin-bottom: 12px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-accent-light);
    color: var(--ds-on-accent-light);
    font-size: 14px;
}
body.ds-page .ds-header-drawer__rattachement a { color: var(--ds-on-accent-light); text-decoration: underline; }
body.ds-page .ds-header-drawer__cta { width: 100%; margin-bottom: 12px; }
body.ds-page .ds-header-drawer__titre-section {
    padding: 16px 0 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
}
body.ds-page .ds-header-drawer__lien {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 6px 0;
    font-size: 15px;
    color: var(--ds-grey-95);
    border-bottom: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-header-drawer__lien--enfant { padding-left: 14px; font-size: 14px; color: var(--ds-grey-60); }
body.ds-page .ds-header-drawer__lien--petit-enfant { padding-left: 28px; font-size: 14px; color: var(--ds-grey-60); }
body.ds-page .ds-header-drawer__lien--deconnexion { border-bottom: 0; }
/* « a. » pour battre body.ds-page a:not(.ds-btn) (line 724) et teindre en rouge. */
body.ds-page a.ds-header-drawer__lien--deconnexion,
body.ds-page a.ds-header-drawer__lien--deconnexion:hover { color: var(--ds-err-fg); }
body.ds-page.ds-drawer-ouvert { overflow: hidden; }

@media (min-width: 1024px) {
    /* Le tiroir n'existe qu'en mobile et tablette : en desktop tout est déjà
       atteignable dans le header (nav des catégories, menu du compte). */
    body.ds-page .ds-header-drawer,
    body.ds-page .ds-header-drawer-overlay { display: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Pied de page redessiné (lot D1a, 2026-09-17)
   ══════════════════════════════════════════════════════════════════════════
   Transposition de « DRM Footer.dc.html » : grille auto-fit de colonnes de
   180px minimum, largeur utile 1200px, ligne finale séparée par un filet.
   ══════════════════════════════════════════════════════════════════════════ */
body.ds-page .ds-footer {
    background: var(--ds-grey-05);
    border-top: 1px solid var(--ds-grey-15);
    padding: 40px 32px 28px;
    font-family: var(--ds-font);
}
body.ds-page .ds-footer__grid {
    display: grid;
    gap: 32px;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    max-width: 1200px;
    margin: 0 auto;
}
body.ds-page .ds-footer__titre {
    margin: 0 0 14px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
    font-family: var(--ds-font);
}
body.ds-page .ds-footer__liens,
body.ds-page .ds-footer__contact {
    display: flex;
    flex-direction: column;
    gap: 10px;
    font-size: 15px;
    line-height: 1.6;
}
body.ds-page .ds-footer__liens a { color: var(--ds-grey-95); text-decoration: none; }
body.ds-page .ds-footer__liens a:hover { text-decoration: underline; }
body.ds-page .ds-footer__contact { color: var(--ds-grey-60); }
body.ds-page .ds-footer__contact a { color: var(--ds-grey-95); text-decoration: none; }
body.ds-page .ds-footer__contact a:hover { text-decoration: underline; }
body.ds-page .ds-footer__entreprise { color: var(--ds-grey-95); font-weight: 600; }
body.ds-page .ds-footer__horaires { font-size: 15px; line-height: 1.6; color: var(--ds-grey-60); }
body.ds-page .ds-footer__mention {
    max-width: 1200px;
    margin: 28px auto 0;
    padding-top: 20px;
    border-top: 1px solid var(--ds-grey-15);
    font-size: 14px;
    color: var(--ds-grey-60);
}

@media (max-width: 767.98px) {
    body.ds-page .ds-footer { padding: 32px 16px 24px; }
    body.ds-page .ds-footer__grid { gap: 32px; }
}


/* Mini-panier anonyme (drawer) : positionnement hors-écran repris de
   style_sun.css (§14 « MINI-PANIER ANONYME »), débranché comme le reste du
   thème. Sans ce bloc, le drawer restait visible en flux normal en haut de
   page au lieu d'être masqué (bug constaté à la vérification navigateur de
   cette reprise, même famille que le tiroir mobile #menu-nav-mobile). JS
   inchangé (mini-panier-anon--open, aria-hidden). */
body.ds-page .mini-panier-anon {
    position: fixed;
    inset: 0;
    z-index: 2100;
    pointer-events: none;
    visibility: hidden;
}
body.ds-page .mini-panier-anon--open { pointer-events: auto; visibility: visible; }
body.ds-page .mini-panier-anon-overlay {
    position: absolute;
    inset: 0;
    background: rgba(16, 16, 20, 0.45);
    opacity: 0;
    transition: opacity 0.2s ease;
}
body.ds-page .mini-panier-anon--open .mini-panier-anon-overlay { opacity: 1; }
body.ds-page .mini-panier-anon-panel {
    position: absolute;
    top: 0;
    right: 0;
    width: 100%;
    max-width: 480px;
    height: 100%;
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.25s cubic-bezier(0.32, 0, 0, 1);
}
body.ds-page .mini-panier-anon--open .mini-panier-anon-panel { transform: translateX(0); }
body.ds-page .mini-panier-anon-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    background: var(--ds-primary-bg);
    flex-shrink: 0;
}
body.ds-page .mini-panier-anon-close {
    background: transparent;
    border: none;
    color: var(--ds-on-primary);
    font-size: 18px;
    cursor: pointer;
    padding: 6px 10px;
}
body.ds-page .mini-panier-anon-body {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 12px 16px;
}
body.ds-page .mini-panier-anon-footer {
    padding: 14px 16px;
    border-top: 1px solid var(--ds-grey-15);
    flex-shrink: 0;
    background: #fff;
}
body.ds-page .mini-panier-anon-panel { border-radius: 0; box-shadow: var(--ds-shadow-2); background: #fff; }
body.ds-page .mini-panier-anon-titre { font: 600 20px var(--ds-font); color: var(--ds-grey-95); }
body.ds-page .mini-panier-anon-btn-cde {
    height: 48px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-size: 16px;
    font-weight: 600;
}
body.ds-page .mini-panier-empty-link {
    display: inline-flex;
    align-items: center;
    height: 44px;
    padding: 0 18px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-size: 15px;
    font-weight: 600;
}

/* ══════════════════════════════════════════════════
   Catégorie / catalogue, reprise v2 : fil d'Ariane, en-tête, filtres,
   grille, tri, tiroir mobile
   ══════════════════════════════════════════════════ */
body.ds-page .ds-category-inner { max-width: 1200px; margin: 0 auto; padding: 20px 24px 56px; }
body.ds-page .ds-category-topbar { margin-bottom: 4px; }
body.ds-page .ds-category-head { margin: 8px 0 12px; }
body.ds-page .title-h1-category {
    font-size: 36px;
    line-height: 1.15;
    font-weight: 600;
    letter-spacing: -0.025em;
    color: var(--ds-grey-95);
    text-transform: none;
    margin: 0;
}
body.ds-page .ds-category-desc {
    font-size: 17px;
    line-height: 1.6;
    color: var(--ds-grey-60);
    max-width: 70ch;
    margin-bottom: 24px;
}
body.ds-page .ds-category-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px 16px;
    flex-wrap: wrap;
    margin: 16px 0 24px;
}
body.ds-page .ds-category-toolbar__count {
    margin: 0;
    font-size: 24px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ds-grey-95);
}
body.ds-page .ds-category-toolbar__actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* « Filtrer », le sélecteur par page et la bascule d'affichage partagent la même
   hauteur : sans ça les trois contrôles se décalaient les uns des autres dès que
   la barre passait sur deux lignes (constaté à 390 et 768px). */
/* F7-4 (2026-09-18), retour 4 de Martin : « Affichage », le selecteur du nombre
   par page et les deux bascules liste/grille etaient a des hauteurs qui ne se
   repondaient pas. Ils partagent desormais la meme hauteur de controle (44px,
   cible tactile du systeme), centres sur une meme ligne ; les bascules de vue
   sont des cibles carrees de cette hauteur. */
body.ds-page .ds-category-toolbar__filtrer,
body.ds-page .ds-category-toolbar__actions .ds-select,
body.ds-page .ds-category-toolbar__actions .article-nbr-par-page,
body.ds-page .ds-category-toolbar__actions .ds-affichage-switch__btn {
    height: 44px;
    min-height: 44px;
}
body.ds-page .ds-category-toolbar__actions .ds-affichage-switch__btn { width: 44px; }
body.ds-page .ds-category-toolbar__actions { align-items: center; }
body.ds-page .ds-category-toolbar__affichage { display: flex; align-items: center; gap: 4px; margin: 0; }
body.ds-page .article-nbr-par-page {
    height: 44px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    font: 400 14px/1 var(--ds-font);
    padding: 0 10px;
}
body.ds-page .ds-category-toolbar__filtrer { display: none; }
body.ds-page .ds-category-toolbar__label { display: inline-flex; align-items: center; height: 44px; }

body.ds-page .ds-category-layout { display: block; }
body.ds-page .ds-category-content { min-width: 0; }

/* Filtres : colonne desktop, tiroir mobile. Même contenu affiché deux fois
   (colonne + tiroir), jamais deux formulaires actifs en même temps : l'un
   des deux est toujours display:none selon la largeur. */
body.ds-page .ds-category-filters { background: #fff; }
body.ds-page .ds-filtres-drawer__head,
body.ds-page .ds-filtres-drawer__close,
body.ds-page .ds-filtres-drawer__overlay { display: none; }

@media (min-width: 1024px) {
    body.ds-page .ds-category-layout--with-filters {
        display: grid;
        grid-template-columns: 190px minmax(0, 1fr);
        gap: 24px;
        align-items: start;
    }
    /* F7-2 (2026-09-18), retour 2 de Martin : la colonne collante se figeait trop
       haut, « Nos categories » passait sous le header colle. L'offset reprend
       desormais la hauteur REELLE du header (publiee dans --ds-header-h par
       ds-header.js, mesuree a chaque largeur et selon les bandeaux presents) plus
       une respiration de 16px, au lieu d'un 92px en dur trop court. Repli 120px si
       le script n'a pas encore mesure (le titre reste alors sous le header, pas
       au-dessus). */
    body.ds-page .ds-category-filters { position: sticky; top: calc(var(--ds-header-h, 120px) + 16px); }
}

@media (max-width: 1023.98px) {
    body.ds-page .ds-category-toolbar__filtrer { display: inline-flex; }
    body.ds-page .ds-category-layout--with-filters .ds-category-filters {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        width: min(340px, 88vw);
        transform: translateX(100%);
        transition: transform 0.2s ease;
        overflow-y: auto;
        z-index: 1050;
        padding: 20px;
        box-shadow: var(--ds-shadow-2);
    }
    body.ds-page .ds-category-layout--with-filters .ds-category-filters.ds-filtres-drawer--open {
        transform: translateX(0);
    }
    body.ds-page .ds-filtres-drawer__head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 16px;
        padding-bottom: 12px;
        border-bottom: 1px solid var(--ds-grey-15);
    }
    body.ds-page .ds-filtres-drawer__title { font-size: 18px; font-weight: 600; }
    body.ds-page .ds-filtres-drawer__close {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        border: 0;
        background: transparent;
        font-size: 18px;
        color: var(--ds-grey-60);
        cursor: pointer;
    }
    body.ds-page .ds-filtres-drawer__overlay {
        display: none;
        position: fixed;
        inset: 0;
        background: rgba(16, 16, 20, 0.4);
        border: 0;
        padding: 0;
        z-index: 1040;
    }
    body.ds-page .ds-filtres-drawer__overlay--visible { display: block; }
}

/* Grille produit : 4 colonnes desktop, 3 en tablette, 2 en mobile (jamais
   Bootstrap col-*, la maquette impose des points de rupture propres). */
body.ds-page .ds-product-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}
@media (min-width: 768px) {
    body.ds-page .ds-product-grid { grid-template-columns: repeat(2, 1fr); gap: 16px; }
}
@media (min-width: 1440px) {
    body.ds-page .ds-product-grid { grid-template-columns: repeat(3, 1fr); gap: 20px; }
}
body.ds-page .ds-product-grid__item { min-width: 0; }

/* Carrousel « Articles associés » (fiche produit, front-cartes 2026-09-23) :
   une seule rangée, jamais de retour à la ligne. Le défilement horizontal
   natif (molette, tactile) fonctionne dès qu'il y a débordement ; sans
   débordement, .ds-carousel__track tient dans sa largeur et se comporte comme
   une rangée simple, sans qu'aucune règle supplémentaire soit nécessaire.
   public/assets/js/ds-carousel.js se contente d'afficher/masquer les deux
   flèches selon une mesure réelle (scrollWidth > clientWidth) et de faire
   défiler d'un écran par clic. */
body.ds-page .ds-carousel { position: relative; display: flex; align-items: center; gap: 8px; }
body.ds-page .ds-carousel__track {
    display: flex;
    flex-wrap: nowrap;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 2px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    scroll-behavior: smooth;
    flex: 1;
    min-width: 0;
}
body.ds-page .ds-carousel__track::-webkit-scrollbar { display: none; height: 0; }
/* Carte à ~80% de large avec aperçu de la suivante sur mobile (demande
   explicite), 2 par écran de 768 à 1439px (comme la grille catalogue avant
   1440px), 3 par écran à partir de 1440px (comme la grille catalogue). */
body.ds-page .ds-carousel__track > .ds-carte {
    flex: 0 0 80%;
    scroll-snap-align: start;
}
@media (min-width: 768px) {
    body.ds-page .ds-carousel__track { gap: 16px; }
    body.ds-page .ds-carousel__track > .ds-carte { flex-basis: calc(50% - 8px); }
}
@media (min-width: 1440px) {
    body.ds-page .ds-carousel__track { gap: 20px; }
    body.ds-page .ds-carousel__track > .ds-carte { flex-basis: calc(33.333% - 14px); }
}
/* Cachées par défaut (attribut hidden) : ds-carousel.js ne les révèle que si
   la mesure réelle du débordement le justifie. Cible tactile >= 24x24 (WCAG
   2.5.8), 44x44 déjà en place sur le cœur de favori de la carte pour la même
   norme maison. */
body.ds-page .ds-carousel__fleche {
    flex: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--ds-grey-15);
    border-radius: 50%;
    background: #fff;
    color: var(--ds-grey-95);
    cursor: pointer;
}
body.ds-page .ds-carousel__fleche:not([hidden]) { display: inline-flex; }
body.ds-page .ds-carousel__fleche:hover:not([aria-disabled="true"]) { border-color: var(--ds-accent); color: var(--ds-accent); }
body.ds-page .ds-carousel__fleche:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }
body.ds-page .ds-carousel__fleche[aria-disabled="true"] { opacity: 0.35; cursor: default; }
body.ds-page .ds-carousel__fleche--prev .ds-icone { transform: rotate(90deg); }
body.ds-page .ds-carousel__fleche--next .ds-icone { transform: rotate(-90deg); }

/* Carte produit : reprend .product-card-item / .article-img-zone /
   .product-block-name / .product-block-price / .product-cart-btn déjà en
   place (commander-article-block-description.html.twig), inchangés côté
   JS. Layout en colonne pleine hauteur, bouton pleine largeur en bas. */
body.ds-page .product-card-item {
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    background: #fff;
    padding: 0 !important;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
body.ds-page .product-card-item .card-body { padding: 14px !important; flex: 1; display: flex; flex-direction: column; gap: 8px; }
body.ds-page .product-card-item .row.mt-2 { display: flex; flex-direction: column; gap: 8px; flex: 1; margin: 0 !important; }
body.ds-page .product-block-name a {
    font-size: 15px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ds-grey-95);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
body.ds-page .product-block-price {
    font-size: 18px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ds-grey-95);
}
body.ds-page .product-cart-btn {
    width: 100%;
    height: 44px;
    border-radius: var(--ds-radius-control);
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    border: 0;
    margin-top: auto;
}
body.ds-page .product-cart-btn:hover,
body.ds-page .product-cart-btn:focus-visible { filter: brightness(1.12); color: var(--ds-on-primary); }
body.ds-page .js-change-qte-box { width: 100%; }

/* F7-5 (AUDIT-RESPONSIVE-FRONT.md item 5) : marge laterale mobile 16px
   (SPEC-SIGNATURE F3), des 768px et non seulement sous 390px. */
@media (max-width: 767.98px) {
    body.ds-page .ds-category-inner,
    body.ds-page .ds-page-section { padding-left: 16px; padding-right: 16px; }
}

/* ══════════════════════════════════════════════════
   Accueil, reprise v2 : sections en grille propre (univers/nouveautés/
   promotions déjà en HTML.container Bootstrap, ok, on ajoute juste la
   grille des cartes univers en dur pour matcher la maquette : 3 colonnes
   desktop, cartes horizontales empilées mobile).
   ══════════════════════════════════════════════════ */
body.ds-page .category-dashboard-items { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin: 0; }
@media (max-width: 1023.98px) { body.ds-page .category-dashboard-items { grid-template-columns: repeat(2, 1fr); gap: 12px; } }
@media (max-width: 389.98px) { body.ds-page .category-dashboard-items { grid-template-columns: 1fr; gap: 10px; } }
body.ds-page .category-dashboard-items .column-5 { padding: 0; }
body.ds-page .category-item-index {
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
    background: #fff;
}
body.ds-page .category-item-name {
    position: static;
    background: transparent;
    color: var(--ds-grey-95);
    font-family: var(--ds-font);
    font-size: 17px;
    font-weight: 600;
    padding: 16px 12px;
}
/* F4 : aucun titre de section centre sur le front. Les H2 « Nos nouveautes »
   et « Promotions du moment » partageaient la colonne avec « Actualites » et
   « Commander par univers », alignes a gauche : deux alignements dans une meme
   colonne cassent la ligne de lecture. */
body.ds-page .titre-page,
body.ds-page .articles-top-title,
body.ds-page .ds-page-section h2,
body.ds-page .ds-section-head h2 { text-align: left; }
body.ds-page .articles-top-title { font-size: 24px; font-weight: 600; color: var(--ds-grey-95); text-transform: none; }

/* ══════════════════════════════════════════════════════════════════════════
   Carte produit (lot D1c, 2026-09-17), d'après l'écran « Catalogue » du
   Portail Coiffinéa
   ══════════════════════════════════════════════════════════════════════════
   Image 1:1, cœur de favori en surimpression, nom sur deux lignes, ligne
   « format · Réf. », prix, badge de stock, sélecteur de quantité et bouton
   « Ajouter ». Aucune couleur en dur : accent du site par --ds-accent, bouton
   principal par --ds-primary-bg (calculé serveur, ColorContrast::primaryBgFor),
   états de stock par les couleurs sémantiques du système.
   ══════════════════════════════════════════════════════════════════════════ */
body.ds-page .ds-carte {
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
    transition: border-color 0.15s ease;
}
body.ds-page .ds-carte:hover { border-color: var(--ds-grey-25); }

body.ds-page .ds-carte__media {
    position: relative;
    aspect-ratio: 1 / 1;
    background: var(--ds-grey-05);
}
body.ds-page .ds-carte__media-lien {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}
body.ds-page .ds-carte__img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    padding: 10px;
}
body.ds-page .ds-carte__media-lien--vide { color: var(--ds-grey-40); font-size: 32px; }
body.ds-page .ds-carte__etiquette {
    position: absolute;
    top: 10px;
    left: 10px;
    padding: 2px 8px;
    border-radius: 4px;
    background: var(--ds-grey-95);
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
/* F7-5 (2026-09-18, AUDIT-RESPONSIVE-FRONT.md item 3) : cible tactile portee a
   44x44px (norme maison), au lieu de 36px, sur toutes les cartes et toutes les
   largeurs. Un seul composant corrige. */
body.ds-page .ds-carte__favori {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-sm, 4px);
    background: rgba(255, 255, 255, 0.92);
    color: var(--ds-accent-texte, var(--ds-accent));
    cursor: pointer;
}
body.ds-page .ds-carte__favori:hover { background: #fff; border-color: var(--ds-accent); }
/* Cœur plein une fois le produit en favori : l'état vient d'aria-pressed, mis à
   jour par scripts_wishlist.js sans rechargement (JS inchangé). */
body.ds-page .ds-carte__favori { color: var(--ds-grey-40); }
body.ds-page .ds-carte__favori:hover { color: var(--ds-accent-texte, var(--ds-accent)); }
body.ds-page .ds-carte__favori[aria-pressed="true"] { color: var(--ds-accent-texte, var(--ds-accent)); }
/* Cœur plein une fois en favori : porté par CSS (fill) et non par le rendu
   serveur, pour suivre aria-pressed que scripts_wishlist.js bascule sans
   rechargement. La propriété CSS l'emporte sur l'attribut fill du SVG. */
body.ds-page .ds-carte__favori[aria-pressed="true"] .ds-icone { fill: currentColor; }

body.ds-page .ds-carte__corps {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
    padding: 14px;
}
body.ds-page .ds-carte__nom {
    font-size: 15px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--ds-grey-95);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 39px;
}
body.ds-page .ds-carte__nom:hover { color: var(--ds-accent-texte, var(--ds-accent)); }
body.ds-page .ds-carte__ref,
body.ds-page .ds-carte__segment,
body.ds-page .ds-carte__unite,
body.ds-page .ds-carte__decline { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-carte__prix-ligne {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 2px;
}
body.ds-page .ds-carte__prix {
    font-size: 20px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ds-grey-95);
    letter-spacing: -0.008em;
}
/* F6 : l'unite est en retrait du chiffre, jamais dans la meme graisse. */
body.ds-page .ds-carte__prix small {
    font-size: 13px;
    font-weight: 500;
    color: var(--ds-grey-60);
    margin-left: 4px;
    vertical-align: baseline;
}
body.ds-page .ds-carte__prix-ancien {
    font-size: 14px;
    font-weight: 400;
    color: var(--ds-grey-60);
    font-variant-numeric: tabular-nums;
    text-decoration-thickness: 1px;
}
body.ds-page .ds-carte__prix-indispo { font-size: 14px; color: var(--ds-grey-60); }
body.ds-page .ds-carte__stock { align-self: flex-start; }
/* F24 : le cas normal se lit sans couleur, la couleur reste rare donc forte. */
body.ds-page .ds-carte__stock--normal {
    font-size: 13px;
    color: var(--ds-grey-60);
    display: inline-flex;
    align-items: center;
    min-height: 22px;
}

/* Achat : quantité puis « Ajouter », collés en bas de carte pour que toutes les
   cartes d'une ligne alignent leur bouton quelles que soient leurs hauteurs. */
body.ds-page .ds-carte__achat {
    display: flex;
    gap: 8px;
    margin-top: auto;
    padding-top: 10px;
}
/* front-cartes (2026-09-23) : le bouton d'action d'un parent de gamme
   (« Voir le produit ») et celui d'un article non commandable ne passent PAS
   par .ds-carte__achat (aucun sélecteur de quantité à côté) : ils sont posés
   en enfant direct de .ds-carte__corps, sans margin-top:auto, donc collés au
   texte au-dessus au lieu du bas de carte. Résultat mesuré : sur une même
   rangée, une carte « Tarif selon déclinaison » (peu de contenu) affichait son
   bouton bien plus haut que le bouton « Ajouter » d'une carte voisine en
   stock (plus de contenu), la carte étant pourtant déjà étirée à la même
   hauteur par la grille (align-items:stretch par défaut). Cette règle cible
   uniquement les .ds-carte__action posés SEUL, jamais ceux dans .ds-carte__achat
   (spécificité : ce sélecteur d'enfant direct ne matche pas un descendant plus
   profond, la règle .ds-carte__achat .ds-carte__action ci-dessous continue de
   s'appliquer telle quelle). */
body.ds-page .ds-carte__corps > .ds-carte__action { margin-top: auto; }
body.ds-page .ds-carte__action { width: 100%; height: 40px; min-height: 40px; padding: 0 12px; }
/* min-width:0 obligatoire : sans lui le bouton garde sa largeur de contenu plus
   ses 20px de padding hérités de .ds-btn et déborde de la carte (constaté en
   capture à 1440, bouton rogné au bord droit). */
body.ds-page .ds-carte__achat .ds-carte__action { flex: 1 1 0; width: auto; min-width: 0; padding: 0 8px; }
body.ds-page .ds-carte__action--indispo {
    background: var(--ds-grey-05);
    color: var(--ds-grey-60);
    border-color: var(--ds-grey-15);
    cursor: not-allowed;
}

/* Sélecteur de quantité : structure imposée par le JS existant
   (.js-change-qte-box + .input-group, .input-number, .js-quantity-*). */
/* width:auto explicite : « body.ds-page .js-change-qte-box { width: 100% } »
   (habillage de l'ancienne carte, plus haut dans ce fichier) l'emporterait sinon
   et le sélecteur prendrait toute la ligne, poussant « Ajouter » hors de la
   carte (mesuré : bouton large de 16px, débordant de 9px à toutes les largeurs). */
body.ds-page .ds-carte .ds-qte,
body.ds-page .ds-qte {
    display: inline-flex;
    /* .input-group est une classe Bootstrap 4, toujours chargée sur une page
       ds-page, et elle pose flex-wrap:wrap : sans ce nowrap le « + » passait à la
       ligne et sortait du cadre (mesuré à 390px, champ large de 168px dans un
       conteneur de 139px). */
    flex-wrap: nowrap;
    align-items: stretch;
    width: auto;
    flex: none;
    /* F7-5 (AUDIT-RESPONSIVE-FRONT.md item 2) : hauteur de controle 44px et
       boutons +/- carres de 44px, comme le panier (seul endroit deja conforme).
       Les trois segments de la pastille stretchent a la hauteur du conteneur. */
    height: 44px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    overflow: hidden;
    background: #fff;
}
body.ds-page .ds-qte__btn {
    flex: none;
    width: 44px;
    padding: 0;
    border: 0;
    background: #fff;
    color: var(--ds-grey-95);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
}
body.ds-page .ds-qte__btn:hover { background: var(--ds-grey-05); }
body.ds-page .ds-qte__champ {
    width: 40px;
    min-width: 0;
    padding: 0;
    border: 0;
    border-left: 1px solid var(--ds-grey-15);
    border-right: 1px solid var(--ds-grey-15);
    text-align: center;
    font: 600 14px/1 var(--ds-font);
    font-variant-numeric: tabular-nums;
    color: var(--ds-grey-95);
    background: #fff;
}
body.ds-page .ds-qte__champ:focus { outline: 2px solid var(--ds-accent); outline-offset: -2px; }

/* ══════════════════════════════════════════════════════════════════════════
   Catalogue (lot D1c, 2026-09-17), d'après l'écran « Catalogue » du Portail
   ══════════════════════════════════════════════════════════════════════════
   Fil d'Ariane, H1 avec le nombre de produits en suffixe discret, barre
   d'affichage grille/liste, colonne de filtres, pagination en liens, état vide.
   ══════════════════════════════════════════════════════════════════════════ */
body.ds-page .ds-category-inner {
    max-width: 1280px;
    margin: 0 auto;
    padding: 20px 24px 64px;
}
/* Dette D7-4 reprise au lot D6 : bandeau de catégorie sous le H1, 120 px au
   maximum, coins du système, jamais au-dessus du fil d'Ariane. */
body.ds-page .ds-category-banner {
    margin: 0 0 20px;
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
    background: var(--ds-grey-05);
}
body.ds-page .ds-category-banner img { display: block; width: 100%; max-height: 120px; height: auto; object-fit: cover; }

body.ds-page .ds-ariane { margin-bottom: 10px; font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-ariane__liste {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}
body.ds-page .ds-ariane__item { display: inline-flex; align-items: center; gap: 6px; }
body.ds-page .ds-ariane__item a { color: var(--ds-grey-60); }
body.ds-page .ds-ariane__item a:hover { color: var(--ds-grey-95); }
body.ds-page .ds-ariane__item--actif { color: var(--ds-grey-95); }
body.ds-page .ds-ariane__sep { color: var(--ds-grey-40); }

body.ds-page .ds-category-h1 {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0 0 6px;
    font-size: 26px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ds-grey-95);
}
body.ds-page .ds-category-h1__compte {
    font-size: 15px;
    font-weight: 500;
    color: var(--ds-grey-60);
    white-space: nowrap;
}
body.ds-page .ds-category-desc {
    margin: 0 0 16px;
    max-width: 75ch;
    font-size: 15px;
    color: var(--ds-grey-60);
}

body.ds-page .ds-category-toolbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
body.ds-page .ds-category-toolbar__label { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-affichage-switch { display: flex; gap: 4px; margin: 0; }
body.ds-page .ds-affichage-switch__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    background: #fff;
    color: var(--ds-grey-60);
    cursor: pointer;
}
body.ds-page .ds-affichage-switch__btn:hover { background: var(--ds-grey-05); }
body.ds-page .ds-affichage-switch__btn--actif {
    background: var(--ds-accent-light);
    border-color: var(--ds-accent);
    color: var(--ds-on-accent-light);
}
body.ds-page .ds-select {
    height: 36px;
    padding: 0 10px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    background: #fff;
    font: 400 14px/1 var(--ds-font);
    color: var(--ds-grey-95);
}

/* Colonne de filtres : groupes titrés, liens verticaux, sous-niveaux indentés. */
body.ds-page .ds-filtres-groupe { font-size: 13px; }
body.ds-page .ds-filtres-groupe__titre {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ds-grey-95);
}
body.ds-page .ds-filtres-liste { list-style: none; margin: 0; padding: 0; }
body.ds-page .ds-filtres-liste--sous { margin-left: 12px; border-left: 1px solid var(--ds-grey-15); padding-left: 8px; }
/* F7-5 (AUDIT-RESPONSIVE-FRONT.md item 8) : lien de filtre a 30px de haut, sous
   la cible tactile. Zone cliquable portee a 44px, texte centre verticalement. */
body.ds-page .ds-filtres-lien {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 6px 0;
    font-size: 13px;
    line-height: 1.35;
    color: var(--ds-grey-95);
}
body.ds-page .ds-filtres-lien:hover { color: var(--ds-accent-texte, var(--ds-accent)); }
body.ds-page .ds-filtres-lien--actif { font-weight: 600; color: var(--ds-accent-texte, var(--ds-accent)); }
body.ds-page .ds-filtres-lien--sous { color: var(--ds-grey-60); }
body.ds-page .ds-filtres-effacer { display: inline-block; margin-top: 14px; font-size: 13px; font-weight: 600; }
body.ds-page .ds-filtres-panier-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
body.ds-page .ds-no-scroll { overflow: hidden; }

/* Bandeau « panier en cours » : information, jamais une alerte rouge. */
body.ds-page .ds-bandeau-info {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 16px;
    padding: 14px 16px;
    border: 1px solid var(--ds-info-bd);
    border-radius: var(--ds-radius-lg, 12px);
    background: var(--ds-info-bg);
}
body.ds-page .ds-bandeau-info__texte { margin: 0; font-size: 14px; color: var(--ds-info-fg); }
body.ds-page .ds-bandeau-info__alerte { font-weight: 600; color: var(--ds-err-fg); }
body.ds-page .ds-bandeau-info__actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Pagination : de vrais liens, cible pointer 36px (WCAG 2.2, 2.5.8). */
body.ds-page .ds-pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 28px;
}
body.ds-page .ds-pagination__lien,
body.ds-page .ds-pagination__saut,
body.ds-page .ds-pagination__ecart {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding: 0 10px;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-control);
    font-size: 14px;
    color: var(--ds-grey-95);
    background: #fff;
}
body.ds-page .ds-pagination__ecart { border-color: transparent; color: var(--ds-grey-40); }
body.ds-page .ds-pagination__lien:hover,
body.ds-page .ds-pagination__saut:hover { background: var(--ds-grey-05); text-decoration: none; }
body.ds-page .ds-pagination__lien--actif {
    background: var(--ds-primary-bg);
    border-color: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-weight: 600;
}

/* État vide : cadre en pointillés, deux portes de sortie. */
body.ds-page .ds-vide-zone { padding: 8px 0; }
body.ds-page .ds-vide-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
body.ds-page .ds-vide-zone .ds-empty-state {
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    background: #fff;
    padding: var(--ds-rythme-section) 24px;
    text-align: center;
}
body.ds-page .ds-empty-state__icon { font-size: 28px; color: var(--ds-grey-40); display: block; margin-bottom: 10px; }

@media (max-width: 1023.98px) {
    body.ds-page .ds-category-inner { padding: 16px 20px 48px; }
    body.ds-page .ds-category-h1 { font-size: 22px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Accueil connecté (lot D1c, 2026-09-17), d'après l'écran « Accueil connecté »
   du Portail : entête au nom de la personne, deux portes d'entrée à droite.
   ══════════════════════════════════════════════════════════════════════════ */
body.ds-page .ds-accueil-entete { padding: 28px 0 4px; }
body.ds-page .ds-accueil-entete__inner {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    /* Lot F6 (2026-09-18), retour 5 de Martin : le bloc de titre etait le seul
       conteneur de l'accueil borne a 1280 px quand tout le reste du design est
       borne a 1200 (grille de cartes, produits habituels, compte, catalogue,
       fiche, panier, tunnel). Mesure a 1280 px de fenetre : titre a gauche a
       24 px contre 64 px pour la premiere carte, dernier bouton a droite a
       1256 px contre 1216 px pour la derniere carte, soit 40 px d'ecart des
       deux cotes. */
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 24px;
}
body.ds-page .ds-accueil-entete__titre {
    margin: 0;
    font-size: 32px;
    line-height: 1.15;
    font-weight: 600;
    letter-spacing: -0.021em;
    color: var(--ds-grey-95);
    text-wrap: balance;
}
/* F7-5, retour 5 de Martin : le sous-titre « Prix affiches hors taxes... »
   collait au titre. Respiration reprise de l'echelle (8px). */
body.ds-page .ds-accueil-entete__sous-titre { margin: 8px 0 0; font-size: 15px; color: var(--ds-grey-60); }
body.ds-page .ds-accueil-entete__actions { display: flex; gap: 10px; flex-wrap: wrap; }
@media (max-width: 767.98px) {
    body.ds-page .ds-accueil-entete { padding: 20px 0 0; }
    body.ds-page .ds-accueil-entete__inner { padding: 0 16px; }
    body.ds-page .ds-accueil-entete__titre { font-size: 26px; }
    /* F7-5, retour 5 : les deux portes d'entree passaient en cote a cote et se
       coupaient sur deux lignes de hauteurs inegales (« Parcourir le catalogue »
       vs « Produits habituels »). Empilees pleine largeur, chacune sur une ligne,
       meme hauteur de controle (44px du .ds-btn). Respiration au-dessus. */
    body.ds-page .ds-accueil-entete__actions {
        width: 100%;
        flex-direction: column;
        gap: 10px;
        margin-top: 16px;
    }
    body.ds-page .ds-accueil-entete__actions .ds-btn { width: 100%; }
}

/* Pied de page (lot D7) : la colonne Catalogue reste sur une seule colonne,
   comme les trois autres colonnes du pied de page. La règle « deux colonnes »
   du lot D1c est retirée, gabarit et feuille ensemble. */

/* Carte produit sous 768px : deux colonnes de cartes de ~170px, la quantité et
   « Ajouter » ne tiennent plus côte à côte (bouton mesuré à 30px, libellé rogné).
   Ils s'empilent, la quantité prenant toute la largeur. */
@media (max-width: 767.98px) {
    body.ds-page .ds-carte__achat { flex-direction: column; align-items: stretch; gap: 8px; }
    /* Empilés, mais chacun sur une vraie ligne de 44px : à 390px deux colonnes de
       cartes ne laissent pas la place d'aligner la quantité et « Ajouter ». */
    body.ds-page .ds-carte .ds-qte { width: 100%; height: 44px; justify-content: space-between; }
    body.ds-page .ds-carte .ds-qte__btn { width: 44px; }
    body.ds-page .ds-carte .ds-qte__champ { flex: 1; width: auto; }
    body.ds-page .ds-carte__achat .ds-carte__action { flex: none; width: 100%; height: 44px; min-height: 44px; }
}

/* =========================================================================
   Lot D2 (2026-09-17) : fiche produit, mini-panier, panier.
   Écrit d'après les écrans « Fiche produit », « Panier » et le drawer de
   l'écran « Mobile » du Portail Coiffinéa. Aucune couleur du Portail n'est
   reprise en dur : l'accent vient de --ds-accent, le bouton principal de
   --ds-primary-bg, tous deux calculés côté serveur par tenant.
   ========================================================================= */

/* Toastr : la feuille de style vendor (toastr.min.css) fait partie du bloc de
   thème débranché sur les pages redessinées. Sans ces règles, le toast d'ajout
   au panier était rendu en texte brut en haut du document. Position haute
   droite, sous le header collant, jamais au-dessus d'un bouton d'action. */
body.ds-page #toast-container {
    position: fixed;
    top: calc(var(--ds-header-h, 80px) + 12px);
    right: 16px;
    z-index: 1080;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: min(380px, calc(100vw - 32px));
    pointer-events: none;
}
body.ds-page #toast-container > div {
    pointer-events: auto;
    background: var(--ds-grey-95);
    color: #fff;
    border-radius: var(--ds-radius-control, 8px);
    padding: 12px 14px;
    font-size: 14px;
    line-height: 1.4;
    box-shadow: var(--ds-shadow-2);
    cursor: pointer;
    /* Bootstrap pose .toast { opacity: 0 } (le composant s'affiche avec .show) et la feuille
       toastr, qui donnait .8, n'est plus chargée ici : le fadeIn de jQuery vise l'opacité
       calculée, donc 0, et tout toast restait invisible. */
    opacity: 1;
    /* .toast { flex-basis: 350px } deviendrait la hauteur dans cette colonne flex. */
    flex: 0 0 auto;
}
body.ds-page #toast-container a { color: #fff; text-decoration: underline; font-weight: 600; }
body.ds-page #toast-container > div.toast-error { background: var(--ds-err-fg); }
body.ds-page #toast-container > div.toast-warning { background: var(--ds-warn-fg); }
body.ds-page #toast-container .toast-title { font-weight: 600; }
body.ds-page #toast-container .toast-close-button {
    float: right;
    border: 0;
    background: none;
    color: #fff;
    opacity: 0.7;
    font-size: 18px;
    line-height: 1;
    padding: 0 0 0 10px;
    cursor: pointer;
}
body.ds-page #toast-container .toast-progress { display: none; }

/* ── Fiche produit ───────────────────────────────────────────────────── */

body.ds-page .ds-fiche-page { background: var(--ds-grey-05); padding-bottom: 48px; }
body.ds-page .ds-fiche-inner { max-width: 1200px; margin: 0 auto; padding: 0 24px; }

body.ds-page .ds-fiche__haut {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 32px;
    align-items: start;
}

body.ds-page .ds-fiche__galerie { position: sticky; top: calc(var(--ds-header-h, 80px) + 16px); }
body.ds-page .ds-fiche__visuel {
    aspect-ratio: 1;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
body.ds-page .ds-fiche__image { width: 100%; height: 100%; object-fit: contain; padding: 16px; }
body.ds-page .ds-fiche__visuel--vide {
    flex-direction: column;
    gap: 10px;
    color: var(--ds-grey-40);
    font-size: 14px;
}
body.ds-page .ds-fiche__visuel--vide .fa { font-size: 40px; }

body.ds-page .ds-fiche__vignettes {
    list-style: none;
    margin: 10px 0 0;
    padding: 0;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
body.ds-page .ds-fiche__vignette {
    width: 64px;
    height: 64px;
    padding: 2px;
    border: 1px solid var(--ds-grey-25);
    border-radius: 8px;
    background: #fff;
    cursor: pointer;
    overflow: hidden;
}
body.ds-page .ds-fiche__vignette img { width: 100%; height: 100%; object-fit: contain; }
body.ds-page .ds-fiche__vignette--active { border: 2px solid var(--ds-accent); padding: 1px; }
body.ds-page .ds-fiche__vignette:focus-visible {
    outline: 2px solid var(--ds-accent);
    outline-offset: 2px;
}

body.ds-page .ds-fiche__colonne { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
body.ds-page .ds-fiche__titre {
    margin: 0;
    font-size: 32px;
    font-weight: 600;
    line-height: 1.15;
    color: var(--ds-grey-95);
    letter-spacing: -0.021em;
    text-wrap: balance;
}
body.ds-page .ds-fiche__meta {
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    font-size: 14px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-fiche__mono { font-variant-numeric: tabular-nums; color: var(--ds-grey-95); }

body.ds-page .ds-fiche__carte {
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 18px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* ── Sélecteur de déclinaisons (fiche produit) ───────────────────────────
   Front-declinaisons (2026-09-23). Premier bloc de .ds-fiche__carte, juste
   sous le titre/référence. Moins de 8 valeurs : pastilles (.ds-pastille,
   cibles tactiles 44px). Au-delà (jusqu'à 84 teintes) : select natif habillé
   (.ds-declinaisons__select), recherche au clavier fournie par le navigateur. */
body.ds-page .ds-declinaisons {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-declinaisons__groupe { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
body.ds-page .ds-declinaisons__label { font-size: 13px; font-weight: 500; color: var(--ds-grey-60); }

body.ds-page .ds-declinaisons__pastilles { display: flex; flex-wrap: wrap; gap: 8px; }
body.ds-page .ds-pastille {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    min-width: 44px;
    padding: 0 14px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    color: var(--ds-grey-95);
    font: 500 14px/1 var(--font-text), sans-serif;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
body.ds-page .ds-pastille:hover { background: var(--ds-grey-05); }
body.ds-page .ds-pastille:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: var(--ds-focus-ring-offset, 2px);
}
body.ds-page .ds-pastille--active {
    border-color: var(--ds-accent);
    box-shadow: inset 0 0 0 1px var(--ds-accent);
    font-weight: 600;
}
/* Rupture : grisée, JAMAIS masquée (mandat) — reste sélectionnable, la fiche
   qui s'affiche explique alors elle-même la rupture (bloc achat existant). */
body.ds-page .ds-pastille--rupture { color: var(--ds-grey-40); background: var(--ds-grey-05); }
body.ds-page .ds-pastille--rupture.ds-pastille--active { border-color: var(--ds-grey-40); box-shadow: inset 0 0 0 1px var(--ds-grey-40); }

body.ds-page .ds-declinaisons__select-wrap { position: relative; max-width: 360px; }
body.ds-page .ds-declinaisons__select {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    height: 44px;
    padding: 0 36px 0 12px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    color: var(--ds-grey-95);
    font: 400 15px/1 var(--font-text), sans-serif;
    cursor: pointer;
}
body.ds-page .ds-declinaisons__select:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: var(--ds-focus-ring-offset, 2px);
}
body.ds-page .ds-declinaisons__select-wrap .ds-icone {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--ds-grey-60);
    pointer-events: none;
}
body.ds-page .ds-declinaisons__erreur:not(.ds-sr-only) {
    font-size: 13px;
    color: var(--ds-err-fg);
}

body.ds-page .ds-fiche__prix-ligne {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    flex-wrap: wrap;
}
body.ds-page .ds-fiche__prix-bloc { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.ds-page .ds-fiche__prix-libelle { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-fiche__prix {
    margin: 0;
    font-size: 24px;
    font-weight: 600;
    color: var(--ds-grey-95);
    letter-spacing: -0.014em;
    font-variant-numeric: tabular-nums;
}
body.ds-page .ds-fiche__prix small,
body.ds-page .ds-fiche__prix .ds-unite {
    font-size: 13px;
    font-weight: 500;
    color: var(--ds-grey-60);
    margin-left: 4px;
    vertical-align: baseline;
}
body.ds-page .ds-fiche__prix--indispo { font-size: 20px; color: var(--ds-grey-60); font-weight: 600; }
body.ds-page .ds-fiche__prix-mention { font-size: 13px; font-weight: 500; color: var(--ds-grey-60); }
body.ds-page .ds-fiche__prix-public { font-size: 14px; color: var(--ds-grey-60); }
body.ds-page .ds-fiche__prix-ttc { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-fiche__remise {
    align-self: flex-start;
    margin-top: 4px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ds-ok-fg);
}
body.ds-page .ds-fiche__dispo { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
body.ds-page .ds-fiche__dispo-qte { font-size: 12px; color: var(--ds-grey-60); }
body.ds-page .ds-fiche__multiple { margin: -6px 0 0; font-size: 13px; color: var(--ds-grey-60); }

body.ds-page .ds-fiche__achat { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
body.ds-page .ds-fiche__achat .ds-qte { flex: none; }
body.ds-page .ds-fiche__ajout { flex: 1 1 200px; min-width: 180px; }
body.ds-page .ds-fiche__favori { flex: none; gap: 8px; }
body.ds-page .ds-fiche__favori[aria-pressed="true"] .ds-icone { fill: currentColor; }

body.ds-page .ds-fiche__livraison {
    margin: 0;
    padding-top: 10px;
    border-top: 1px solid var(--ds-grey-15);
    font-size: 12px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-fiche__liens { margin: 0; font-size: 14px; }
/* F7-5 (AUDIT-RESPONSIVE-FRONT.md item 7) : « Demander un devis » reste un lien
   texte discret (et non un second CTA), mais seul dans son paragraphe il devient
   une cible autonome : zone cliquable portee a 44px. */
body.ds-page .ds-fiche__liens a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}
body.ds-page .ds-fiche__message { margin: 0; font-size: 14px; }
body.ds-page .ds-fiche__admin { margin: 0; font-size: 13px; display: flex; gap: 14px; flex-wrap: wrap; }

body.ds-page .ds-encart {
    border-radius: var(--ds-radius-control, 8px);
    padding: 12px 14px;
    font-size: 14px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
}
body.ds-page .ds-encart p { margin: 0; }
body.ds-page .ds-encart--info { background: var(--ds-info-bg); color: var(--ds-info-fg); }
body.ds-page .ds-encart--err { background: var(--ds-err-bg); color: var(--ds-err-fg); }
/* Lot D5 (2026-09-17) : ces deux variantes étaient posées dans dix gabarits
   depuis les lots D3 et D4, sans aucune règle correspondante. Les messages de
   succès et d'avertissement sortaient donc sur fond transparent, indiscernables
   du texte courant (constaté en capture sur la confirmation du tunnel). */
body.ds-page .ds-encart--ok { background: var(--ds-ok-bg); color: var(--ds-ok-fg); }
body.ds-page .ds-encart--warn { background: var(--ds-warn-bg); color: var(--ds-warn-fg); }

body.ds-page .ds-fiche__sections { margin-top: var(--ds-rythme-section); display: flex; flex-direction: column; gap: var(--ds-rythme-section); }
/* front-cartes (2026-09-23) : « Articles associés » (commander-article-assos.html.twig)
   est un .ds-fiche__section rendu APRÈS .ds-fiche, pas un enfant de
   .ds-fiche__sections (le contrôleur le sert dans un include séparé, potentiellement
   vide) : il n'héritait donc d'aucun espacement de section et collait directement
   sous Caractéristiques/Documents. Même rythme vertical que le reste de la fiche. */
body.ds-page .ds-fiche__assos { margin-top: var(--ds-rythme-section); }
body.ds-page .ds-fiche__section > h2 {
    margin: 0 0 var(--ds-rythme-bloc);
    font-size: 24px;
    line-height: 1.25;
    letter-spacing: -0.014em;
    font-weight: 600;
    color: var(--ds-grey-95);
    text-wrap: balance;
}
body.ds-page .ds-fiche__texte {
    margin: 0;
    color: var(--ds-grey-95);
    line-height: 1.55;
    letter-spacing: 0;
    max-width: 68ch;
    font-size: 16px;
    text-wrap: pretty;
}
body.ds-page .ds-fiche__texte--vide { color: var(--ds-grey-60); }

/* F7-1 (2026-09-18), retour 1 de Martin : la section Caracteristiques etait une
   table plate (fond blanc, border:0) posee sur le fond gris de la page, quand le
   reste de la fiche met ses blocs dans une carte (.ds-fiche__carte : bordure,
   rayon lg). La table vit desormais dans le meme patron de carte, aligne sur les
   blocs voisins de la page. Le contenu et l'ordre des lignes ne changent pas. */
body.ds-page .ds-fiche__carac-carte {
    max-width: 720px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    box-shadow: var(--ds-shadow-1);
    padding: 6px 20px;
    overflow: hidden;
}
body.ds-page .ds-fiche__carac {
    width: 100%;
    border-collapse: collapse;
    background: transparent;
    border: 0;
    font-size: 15px;
}
body.ds-page .ds-fiche__carac th,
body.ds-page .ds-fiche__carac td {
    height: 44px;
    padding: 8px 12px 8px 0;
    text-align: left;
    border-bottom: 1px solid var(--ds-grey-15);
    vertical-align: middle;
}
body.ds-page .ds-fiche__carac tr:last-child th,
body.ds-page .ds-fiche__carac tr:last-child td { border-bottom: 0; }
body.ds-page .ds-fiche__carac th { width: 45%; font-weight: 500; color: var(--ds-grey-60); }
body.ds-page .ds-fiche__carac td { color: var(--ds-grey-95); }

body.ds-page .ds-fiche__declinaisons {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
body.ds-page .ds-fiche__declinaison {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    min-height: 44px;
    padding: 10px 14px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    color: var(--ds-grey-95);
    font-size: 14px;
}
body.ds-page .ds-fiche__declinaison:hover { background: var(--ds-grey-05); text-decoration: none; }
body.ds-page .ds-fiche__declinaison--active {
    border-color: var(--ds-accent);
    box-shadow: inset 0 0 0 1px var(--ds-accent);
}
body.ds-page .ds-fiche__declinaison-nom { font-weight: 600; }
body.ds-page .ds-fiche__declinaison-prix { color: var(--ds-grey-60); font-size: 13px; }

body.ds-page .ds-fiche__documents { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
body.ds-page .ds-fiche__document {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 10px 14px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    color: var(--ds-grey-95);
    font-size: 14px;
    font-weight: 500;
}
body.ds-page .ds-fiche__document:hover { background: var(--ds-grey-05); text-decoration: none; }

@media (max-width: 1023.98px) {
    body.ds-page .ds-fiche__haut { grid-template-columns: 1fr; gap: 24px; }
    body.ds-page .ds-fiche__galerie { position: static; }
    body.ds-page .ds-fiche__visuel { max-width: 420px; margin: 0 auto; }
}
@media (max-width: 767.98px) {
    body.ds-page .ds-fiche-inner { padding: 0 16px; }
    body.ds-page .ds-fiche__titre { font-size: 22px; }
    body.ds-page .ds-fiche__prix { font-size: 24px; }
    body.ds-page .ds-fiche__titre { font-size: 26px; }
    body.ds-page .ds-fiche__dispo { align-items: flex-start; }
    body.ds-page .ds-fiche__achat { flex-direction: column; align-items: stretch; }
    body.ds-page .ds-fiche__achat .ds-qte { width: 100%; height: 44px; justify-content: space-between; }
    body.ds-page .ds-fiche__achat .ds-qte__champ { flex: 1; width: auto; }
    /* F7-5 (AUDIT-RESPONSIVE-FRONT.md item 6) : en colonne (< 768px),
       flex: 1 1 200px faisait de la base de 200px une HAUTEUR, le bouton
       d'ajout montait a 200px. On neutralise le flex herite de la ligne. */
    body.ds-page .ds-fiche__ajout,
    body.ds-page .ds-fiche__favori { width: 100%; min-width: 0; flex: 0 0 auto; }
    body.ds-page .ds-fiche__carac th { width: 50%; }
    body.ds-page #toast-container { right: 12px; left: 12px; max-width: none; }
    /* Front-declinaisons : le select des teintes prend toute la largeur
       disponible sous 768px (au lieu du max-width: 360px desktop), les
       pastilles restent en grille via flex-wrap déjà posé plus haut. */
    body.ds-page .ds-declinaisons__select-wrap { max-width: none; }
    body.ds-page .ds-pastille { flex: 1 1 calc(50% - 4px); }
}

/* ── Mini-panier : un seul habillage pour les deux tiroirs ───────────────
   Le tiroir du compte connecté (#ds-mini-panier) et celui du visiteur anonyme
   (#mini-panier-anon, rendu par base-header.html.twig) partagent la même
   géométrie et le même style. Les règles du tiroir anonyme sont plus haut dans
   ce fichier (lot D1), celles-ci les complètent. */

body.ds-page .ds-drawer-panier {
    position: fixed;
    inset: 0;
    z-index: 1070;
    visibility: hidden;
    pointer-events: none;
}
body.ds-page .ds-drawer-panier--ouvert { visibility: visible; pointer-events: auto; }
body.ds-page .ds-drawer-panier__overlay {
    position: absolute;
    inset: 0;
    background: rgba(16, 16, 20, 0.34);
    opacity: 0;
    transition: opacity 0.18s ease;
}
body.ds-page .ds-drawer-panier--ouvert .ds-drawer-panier__overlay { opacity: 1; }
body.ds-page .ds-drawer-panier__panneau {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(400px, 100vw);
    background: #fff;
    box-shadow: var(--ds-shadow-2);
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.2s ease;
}
body.ds-page .ds-drawer-panier--ouvert .ds-drawer-panier__panneau { transform: translateX(0); }
body.ds-page .ds-drawer-panier__tete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-drawer-panier__titre { margin: 0; font-size: 18px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-drawer-panier__fermer {
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: var(--ds-radius-control, 8px);
    background: none;
    color: var(--ds-grey-60);
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
}
body.ds-page .ds-drawer-panier__fermer:hover { background: var(--ds-grey-05); color: var(--ds-grey-95); }
body.ds-page .ds-drawer-panier__corps { flex: 1; overflow: auto; padding: 4px 20px; }
body.ds-page .ds-drawer-panier__chargement { display: flex; flex-direction: column; gap: 14px; padding: 16px 0; }
body.ds-page .ds-drawer-panier__vide { padding: 40px 0; text-align: center; color: var(--ds-grey-60); }
body.ds-page .ds-drawer-panier__liste { list-style: none; margin: 0; padding: 0; }
body.ds-page .ds-drawer-panier__ligne {
    display: grid;
    grid-template-columns: 48px minmax(0, 1fr) 44px;
    gap: 12px;
    align-items: center;
    padding: 12px 0;
    border-bottom: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-drawer-panier__vignette {
    width: 48px;
    height: 48px;
    border-radius: var(--ds-radius-sm, 4px);
    background: var(--ds-grey-05);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
body.ds-page .ds-drawer-panier__vignette img { width: 100%; height: 100%; object-fit: contain; }
body.ds-page .ds-drawer-panier__infos { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.ds-page .ds-drawer-panier__nom {
    font-weight: 600;
    font-size: 14px;
    color: var(--ds-grey-95);
    line-height: 1.3;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
body.ds-page .ds-drawer-panier__detail { font-size: 13px; color: var(--ds-grey-60); }
/* JT-7 : « quantité × prix unitaire » à gauche, montant de la ligne à droite, sur une même ligne. */
body.ds-page .ds-drawer-panier__bas { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
body.ds-page .ds-drawer-panier__montant-ligne { font-size: 14px; font-weight: 600; color: var(--ds-grey-95); white-space: nowrap; font-variant-numeric: tabular-nums; }
body.ds-page .ds-drawer-panier__suppr {
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: var(--ds-radius-control, 8px);
    background: none;
    color: var(--ds-grey-60);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}
body.ds-page .ds-drawer-panier__suppr:hover { background: var(--ds-err-bg); color: var(--ds-err-fg); }
body.ds-page .ds-drawer-panier__pied {
    padding: 16px 20px;
    border-top: 1px solid var(--ds-grey-15);
    display: flex;
    flex-direction: column;
    gap: 10px;
}
body.ds-page .ds-drawer-panier__total {
    display: flex;
    justify-content: space-between;
    font-size: 15px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-drawer-panier__total strong { color: var(--ds-grey-95); }
body.ds-page .ds-drawer-panier__action { width: 100%; }
body.ds-page.ds-drawer-ouvert { overflow: hidden; }

/* Tiroir du visiteur anonyme : mêmes actions empilées en pied. */
body.ds-page .mini-panier-anon-btn-continuer { width: 100%; }

/* ── Page panier ─────────────────────────────────────────────────────── */

body.ds-page .ds-panier-page { background: var(--ds-grey-05); padding-bottom: 48px; }
body.ds-page .ds-panier-inner { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
body.ds-page .ds-panier-h1 { margin: 0 0 16px; font-size: 24px; font-weight: 600; }

body.ds-page .ds-etapes {
    list-style: none;
    margin: 0 0 16px;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    font-size: 14px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-etapes__item { display: flex; align-items: center; gap: 8px; }
body.ds-page .ds-etapes__item--actif { color: var(--ds-grey-95); font-weight: 600; }
body.ds-page .ds-etapes__puce {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 1px solid var(--ds-grey-25);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
}
body.ds-page .ds-etapes__item--actif .ds-etapes__puce {
    background: var(--ds-primary-bg);
    border-color: var(--ds-primary-bg);
    color: var(--ds-on-primary);
}

body.ds-page .ds-panier-grille {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 24px;
    align-items: start;
}
body.ds-page .ds-panier-colonne { min-width: 0; display: flex; flex-direction: column; gap: 16px; }

body.ds-page .ds-panier-lignes {
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
}
body.ds-page .ds-panier-lignes__entete,
body.ds-page .ds-panier-ligne {
    display: grid;
    grid-template-columns: 56px minmax(140px, 1fr) 110px 128px 110px 92px;
    gap: 12px;
    align-items: center;
}
body.ds-page .ds-panier-lignes__entete {
    padding: 10px 16px;
    background: var(--ds-grey-05);
    border-bottom: 1px solid var(--ds-grey-15);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
}
body.ds-page .ds-panier-ligne { padding: 14px 16px; border-bottom: 1px solid var(--ds-grey-15); }
body.ds-page .ds-panier-lignes__col-prix,
body.ds-page .ds-panier-lignes__col-total { text-align: right; }
body.ds-page .ds-panier-lignes__col-qte { text-align: center; }

body.ds-page .ds-panier-ligne__visuel {
    width: 56px;
    height: 56px;
    border-radius: var(--ds-radius-sm, 4px);
    background: var(--ds-grey-05);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
body.ds-page .ds-panier-ligne__visuel img { width: 100%; height: 100%; object-fit: contain; }
body.ds-page .ds-panier-ligne__visuel-vide { color: var(--ds-grey-40); }
body.ds-page .ds-panier-ligne__produit { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.ds-page .ds-panier-ligne__nom { font-weight: 600; color: var(--ds-grey-95); font-size: 15px; }
body.ds-page .ds-panier-ligne__ref { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-panier-ligne__alerte { font-size: 13px; color: var(--ds-err-fg); }
body.ds-page .ds-panier-ligne__prix { font-size: 14px; color: var(--ds-grey-95); font-variant-numeric: tabular-nums; }
body.ds-page .ds-panier-ligne__qte { display: flex; justify-content: center; }
body.ds-page .ds-panier-ligne__total { font-weight: 700; color: var(--ds-grey-95); font-variant-numeric: tabular-nums; }
body.ds-page .ds-panier-ligne__action { display: flex; justify-content: flex-end; }
body.ds-page .ds-panier-ligne__suppr {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 0 10px;
    border-radius: var(--ds-radius-control, 8px);
    color: var(--ds-grey-60);
    font-size: 13px;
}
body.ds-page .ds-panier-ligne__suppr:hover { background: var(--ds-err-bg); color: var(--ds-err-fg); text-decoration: none; }
body.ds-page .ds-panier-ligne__suppr > span[aria-hidden="true"] { font-size: 18px; line-height: 1; }
body.ds-page .ds-panier-ligne__libelle-mobile { display: none; }
body.ds-page .ds-panier-lignes__soustotal {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 16px;
    background: var(--ds-grey-05);
    font-size: 15px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-panier-lignes__soustotal strong { color: var(--ds-grey-95); }

/* Dette D2-4, reprise au lot D3 : commentaire et documents par ligne, repliés
   sous la carte. <details> natif, donc pas de JS d'ouverture. La ligne occupe
   toute la largeur de la grille, au-dessous des colonnes. */
body.ds-page .ds-panier-ligne__notes {
    grid-column: 1 / -1;
    margin-top: 6px;
    border-top: 1px solid var(--ds-grey-15);
    padding-top: 8px;
}
body.ds-page .ds-panier-ligne__notes-resume {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 24px;
    padding: 4px 2px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ds-grey-60);
    cursor: pointer;
    list-style: none;
}
body.ds-page .ds-panier-ligne__notes-resume::-webkit-details-marker { display: none; }
body.ds-page .ds-panier-ligne__notes-resume::before {
    content: "";
    width: 8px;
    height: 8px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(-45deg);
    transition: transform 0.15s ease;
}
body.ds-page .ds-panier-ligne__notes[open] > .ds-panier-ligne__notes-resume::before { transform: rotate(45deg); }
body.ds-page .ds-panier-ligne__notes-resume:hover { color: var(--ds-grey-95); }
body.ds-page .ds-panier-ligne__notes-resume:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
    border-radius: var(--ds-radius-sm, 6px);
}
body.ds-page .ds-panier-ligne__notes-corps {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px 0 4px;
    max-width: 640px;
}
body.ds-page .ds-panier-ligne__notes-champ { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
body.ds-page .ds-panier-ligne__notes-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--ds-grey-95);
}
body.ds-page .ds-panier-ligne__notes-aide { font-size: 12px; color: var(--ds-grey-60); }
body.ds-page .ds-panier-ligne__notes textarea.ds-textarea {
    width: 100%;
    min-height: 76px;
    padding: 10px 12px;
    font: inherit;
    font-size: 14px;
    color: var(--ds-grey-95);
    background: #fff;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-sm, 6px);
    resize: vertical;
}
body.ds-page .ds-panier-ligne__notes textarea.ds-textarea:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
    border-color: var(--ds-accent);
}
/* is-valid : retour de succes pose par initCdeLigneCommentaireAjax pendant 900 ms. */
body.ds-page .ds-panier-ligne__notes textarea.ds-textarea.is-valid { border-color: var(--ds-ok-fg, #1b7a4b); }
body.ds-page .ds-panier-ligne__notes textarea.ds-textarea.is-invalid { border-color: var(--ds-err-fg); }
body.ds-page .ds-panier-ligne__docs { list-style: none; margin: 0; padding: 0; width: 100%; }
body.ds-page .ds-panier-ligne__docs li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 0;
    font-size: 14px;
    border-bottom: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-panier-ligne__docs li:last-child { border-bottom: 0; }
body.ds-page .ds-panier-ligne__doc-suppr {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    line-height: 1;
    color: var(--ds-grey-60);
    background: none;
    border: 0;
    border-radius: var(--ds-radius-sm, 6px);
    cursor: pointer;
}
body.ds-page .ds-panier-ligne__doc-suppr:hover { color: var(--ds-err-fg); background: var(--ds-err-bg); }
body.ds-page .ds-panier-ligne__doc-ajout { cursor: pointer; margin: 0; }

body.ds-page .ds-panier-sous-lignes {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    font-size: 14px;
}
body.ds-page .ds-panier-date { color: var(--ds-grey-60); }
body.ds-page .ds-panier-lien-secondaire { align-self: flex-start; font-size: 14px; }
body.ds-page .ds-panier-lien-secondaire--danger { color: var(--ds-err-fg); }
body.ds-page .ds-panier-habituels { margin-top: 16px; }
body.ds-page .ds-panier-habituels > h2 { margin: 0 0 12px; font-size: 18px; font-weight: 600; }

body.ds-page .ds-panier-recap {
    position: sticky;
    top: calc(var(--ds-header-h, 80px) + 16px);
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 18px 20px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    font-size: 14px;
}
body.ds-page .ds-panier-recap__titre { margin: 0 0 4px; font-size: 16px; font-weight: 600; }
body.ds-page .ds-panier-recap__ligne { display: flex; justify-content: space-between; gap: 12px; }
body.ds-page .ds-panier-recap__ligne > span { color: var(--ds-grey-60); }
body.ds-page .ds-panier-recap__ligne > strong { color: var(--ds-grey-95); text-align: right; }
body.ds-page .ds-panier-recap__ligne--detail { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-panier-recap__ligne--total {
    border-top: 1px solid var(--ds-grey-15);
    padding-top: 10px;
    font-size: 16px;
}
body.ds-page .ds-panier-recap__ligne--total > span,
body.ds-page .ds-panier-recap__ligne--total > strong { color: var(--ds-grey-95); font-weight: 700; }
body.ds-page .ds-panier-recap__mention { margin: 0; font-size: 12px; color: var(--ds-grey-60); }
body.ds-page .ds-panier-recap__champ { margin-top: 6px; }
body.ds-page .ds-panier-recap__champ label { font-size: 13px; font-weight: 500; color: var(--ds-grey-60); }
body.ds-page .ds-panier-recap__champ input[type="text"],
body.ds-page .ds-panier-recap__champ textarea {
    width: 100%;
    min-height: 44px;
    padding: 10px 12px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    font: 400 15px var(--ds-font);
    color: var(--ds-grey-95);
}
body.ds-page .ds-panier-recap__action { width: 100%; margin-top: 8px; }
body.ds-page .ds-panier-recap__devis {
    display: block;
    margin-top: 8px;
    text-align: center;
    font-size: 14px;
    color: var(--ds-grey-60);
}

@media (max-width: 1023.98px) {
    body.ds-page .ds-panier-grille { grid-template-columns: 1fr; }
    body.ds-page .ds-panier-recap { position: static; }
}

/* Sous 768 px : chaque ligne devient une carte, la quantité garde 44 px de haut
   et la suppression est détachée de la zone de quantité (Portail, écran Mobile). */
@media (max-width: 767.98px) {
    body.ds-page .ds-panier-inner { padding: 0 16px; }
    body.ds-page .ds-panier-lignes { border: 0; background: none; overflow: visible; }
    body.ds-page .ds-panier-lignes__entete { display: none; }
    body.ds-page .ds-panier-ligne {
        grid-template-columns: 56px minmax(0, 1fr);
        grid-template-areas:
            "visuel produit"
            "prix   prix"
            "total  total"
            "qte    action";
        row-gap: 10px;
        padding: 14px;
        margin-bottom: 12px;
        background: #fff;
        border: 1px solid var(--ds-grey-15);
        border-radius: var(--ds-radius-lg, 12px);
    }
    body.ds-page .ds-panier-ligne__visuel { grid-area: visuel; }
    body.ds-page .ds-panier-ligne__produit { grid-area: produit; }
    body.ds-page .ds-panier-ligne__prix { grid-area: prix; text-align: left; display: flex; justify-content: space-between; color: var(--ds-grey-60); }
    body.ds-page .ds-panier-ligne__qte { grid-area: qte; justify-content: flex-start; align-items: center; gap: 8px; }
    body.ds-page .ds-panier-ligne__action { grid-area: action; justify-content: flex-end; }
    /* Le total a sa propre ligne (libellé à gauche, montant à droite) : il partageait la zone du nom de
       l'article et le recouvrait. */
    body.ds-page .ds-panier-ligne__total {
        grid-area: total;
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        gap: 12px;
    }
    body.ds-page .ds-panier-ligne__total::before { content: attr(data-libelle); font-weight: 400; color: var(--ds-grey-60); }
    body.ds-page .ds-panier-ligne__libelle-mobile { display: inline; }
    body.ds-page .ds-panier-ligne .ds-qte { height: 44px; }
    body.ds-page .ds-panier-ligne .ds-qte__btn { width: 44px; }
    body.ds-page .ds-panier-ligne .ds-qte__champ { width: 48px; height: 42px; }
    /* La carte mobile nomme ses zones : la ligne repliable n'en a pas, on la
       place explicitement sur toute la largeur, sur une rangee implicite. */
    body.ds-page .ds-panier-ligne__notes { grid-column: 1 / -1; }
    body.ds-page .ds-panier-ligne__notes-resume { min-height: 44px; }
    body.ds-page .ds-panier-ligne__doc-suppr { width: 44px; height: 44px; }
    body.ds-page .ds-panier-ligne__doc-ajout { min-height: 44px; }
    body.ds-page .ds-panier-lignes__soustotal {
        border: 1px solid var(--ds-grey-15);
        border-radius: var(--ds-radius-lg, 12px);
    }
}

/* ══════════════════════════════════════════════════
   Lot D3 : tunnel de commande (trois étapes), connexion et codes.
   Transposition des écrans C5 et C6 du système DRM et des écrans
   « Livraison », « Confirmation », « Connexion », « Vérification » du Portail.
   Tout est scopé sous body.ds-page : une page non redessinée ne peut pas
   être atteinte par ces règles.
   ══════════════════════════════════════════════════ */

body.ds-page .ds-tunnel-page { background: var(--ds-grey-05); min-height: 60vh; }
body.ds-page .ds-tunnel-inner { max-width: 1200px; margin: 0 auto; padding: 24px 32px 56px; }

/* ── Indicateur d'étapes ── */
body.ds-page .ds-etapes-tunnel { margin: 8px 0 28px; }
body.ds-page .ds-etapes-tunnel__liste {
    display: flex;
    align-items: center;
    gap: 20px;
    list-style: none;
    margin: 0;
    padding: 0;
}
body.ds-page .ds-etapes-tunnel__item {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-etapes-tunnel__item + .ds-etapes-tunnel__item::before {
    content: "";
    width: 40px;
    height: 1px;
    background: var(--ds-grey-25);
    margin-right: 10px;
}
body.ds-page .ds-etapes-tunnel__puce {
    width: 26px;
    height: 26px;
    flex: none;
    border-radius: 999px;
    border: 1px solid var(--ds-grey-25);
    font-size: 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-variant-numeric: tabular-nums;
}
body.ds-page .ds-etapes-tunnel__item--actif { color: var(--ds-grey-95); font-weight: 600; }
body.ds-page .ds-etapes-tunnel__item--actif .ds-etapes-tunnel__puce {
    background: var(--ds-accent);
    border-color: var(--ds-accent);
    color: var(--ds-on-accent);
}
body.ds-page .ds-etapes-tunnel__item--faite { color: var(--ds-grey-95); }
body.ds-page .ds-etapes-tunnel__item--faite .ds-etapes-tunnel__puce {
    border-color: var(--ds-accent);
    color: var(--ds-accent-texte, var(--ds-accent));
}
body.ds-page .ds-etapes-tunnel__mobile { display: none; }

/* ── Grille du tunnel : formulaire à gauche, récapitulatif à droite ── */
body.ds-page .ds-tunnel-grille {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 380px;
    gap: 40px;
    align-items: start;
}
body.ds-page .ds-tunnel-colonne {
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 28px;
}
body.ds-page .ds-tunnel-h1 { margin: 0 0 24px; font-size: 32px; line-height: 1.15; font-weight: 600; letter-spacing: -0.021em; text-wrap: balance; }
body.ds-page .ds-tunnel-h2 {
    margin: 28px 0 14px;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ds-grey-95);
}
body.ds-page .ds-tunnel-h2:first-of-type { margin-top: 0; }
body.ds-page .ds-tunnel-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
    margin-top: 28px;
    padding-top: 20px;
    border-top: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-tunnel-retour { font-size: 15px; color: var(--ds-grey-60); }
body.ds-page .ds-tunnel-retour:hover { color: var(--ds-grey-95); }

/* ── Récapitulatif persistant ── */
body.ds-page .ds-tunnel-recap {
    position: sticky;
    top: 24px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
}
body.ds-page .ds-tunnel-recap__bascule { display: none; }
body.ds-page .ds-tunnel-recap__contenu { padding: 24px; }
body.ds-page .ds-tunnel-recap__entete {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 18px;
}
body.ds-page .ds-tunnel-recap__titre { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: -0.01em; }
body.ds-page .ds-tunnel-recap__modifier { font-size: 14px; font-weight: 500; }
body.ds-page .ds-tunnel-recap__lignes {
    list-style: none;
    margin: 0;
    padding: 0 0 18px;
    border-bottom: 1px solid var(--ds-grey-15);
    display: flex;
    flex-direction: column;
    gap: 14px;
    max-height: 320px;
    overflow-y: auto;
}
body.ds-page .ds-tunnel-recap__ligne { display: flex; gap: 12px; align-items: flex-start; }
body.ds-page .ds-tunnel-recap__visuel {
    width: 44px;
    height: 44px;
    flex: none;
    border-radius: var(--ds-radius-control, 8px);
    background: var(--ds-grey-05);
    border: 1px solid var(--ds-grey-15);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
body.ds-page .ds-tunnel-recap__visuel img { width: 100%; height: 100%; object-fit: contain; }
body.ds-page .ds-tunnel-recap__visuel-vide { color: var(--ds-grey-40); font-size: 14px; }
body.ds-page .ds-tunnel-recap__texte { flex: 1; min-width: 0; }
body.ds-page .ds-tunnel-recap__nom { display: block; font-size: 14px; font-weight: 500; line-height: 1.35; }
body.ds-page .ds-tunnel-recap__detail {
    display: block;
    font-size: 13px;
    color: var(--ds-grey-60);
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}
body.ds-page .ds-tunnel-recap__totaux { display: flex; flex-direction: column; gap: 10px; padding-top: 18px; font-size: 15px; }
body.ds-page .ds-tunnel-recap__total-ligne { display: flex; justify-content: space-between; gap: 16px; }
body.ds-page .ds-tunnel-recap__total-ligne > span { color: var(--ds-grey-60); }
body.ds-page .ds-tunnel-recap__total-ligne > strong { font-weight: 500; font-variant-numeric: tabular-nums; color: var(--ds-grey-95); }
body.ds-page .ds-tunnel-recap__total-ligne--final {
    margin-top: 6px;
    padding-top: 12px;
    border-top: 1px solid var(--ds-grey-15);
    font-size: 17px;
}
body.ds-page .ds-tunnel-recap__total-ligne--final > span { color: var(--ds-grey-95); font-weight: 600; }
body.ds-page .ds-tunnel-recap__total-ligne--final > strong { font-weight: 600; }

/* ── Cartes radio (mode de commande, moyen de paiement) ── */
body.ds-page .ds-cartes-radio { display: flex; flex-direction: column; gap: 14px; max-width: 680px; }
body.ds-page .ds-carte-radio {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    border: 1px solid var(--ds-grey-25);
    background: #fff;
    border-radius: var(--ds-radius-lg, 12px);
    padding: 20px;
    margin: 0;
    cursor: pointer;
}
body.ds-page .ds-carte-radio:hover { border-color: var(--ds-grey-60); }
body.ds-page .ds-carte-radio--choisie {
    border-width: 2px;
    border-color: var(--ds-accent);
    background: var(--ds-accent-light);
    padding: 19px;
}
body.ds-page .ds-carte-radio input[type="radio"] {
    width: 20px;
    height: 20px;
    margin: 3px 0 0;
    accent-color: var(--ds-accent);
    flex: none;
}
body.ds-page .ds-carte-radio:focus-within {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
}
body.ds-page .ds-carte-radio__titre { display: block; font-size: 17px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-carte-radio__texte { display: block; font-size: 15px; line-height: 1.55; color: var(--ds-grey-60); margin-top: 4px; }

/* ── Champs de formulaire du tunnel et de la connexion ── */
body.ds-page .ds-form-grille { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
body.ds-page .ds-form-grille .ds-champ--large { grid-column: 1 / -1; }
body.ds-page .ds-champ { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
body.ds-page .ds-champ > label,
body.ds-page .ds-champ label.control-label,
body.ds-page .ds-champ-label { font-size: 14px; font-weight: 500; color: var(--ds-grey-95); }
body.ds-page .ds-champ input[type="text"],
body.ds-page .ds-champ input[type="email"],
body.ds-page .ds-champ input[type="tel"],
body.ds-page .ds-champ input[type="password"],
body.ds-page .ds-champ input[type="number"],
body.ds-page .ds-champ input[type="search"],
body.ds-page .ds-champ select,
body.ds-page .ds-champ textarea {
    width: 100%;
    min-height: 48px;
    padding: 12px;
    font: inherit;
    font-size: 16px;
    color: var(--ds-grey-95);
    background: #fff;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    box-sizing: border-box;
}
body.ds-page .ds-champ textarea { min-height: 96px; resize: vertical; }
body.ds-page .ds-champ input:focus-visible,
body.ds-page .ds-champ select:focus-visible,
body.ds-page .ds-champ textarea:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
    border-color: var(--ds-accent);
}
body.ds-page .ds-champ--erreur input,
body.ds-page .ds-champ--erreur select,
body.ds-page .ds-champ--erreur textarea,
body.ds-page .ds-champ input.is-invalid,
body.ds-page .ds-champ select.is-invalid { border-color: var(--ds-err-fg); }
body.ds-page .ds-champ-erreur { font-size: 14px; color: var(--ds-err-fg); }
body.ds-page .ds-champ-erreur ul { list-style: none; margin: 0; padding: 0; }
body.ds-page .ds-champ-aide { font-size: 13px; color: var(--ds-grey-60); }

/* Formulaires Symfony rendus par form_row : le balisage Bootstrap 4 reste,
   on l'habille sans le réécrire (les noms, ids et jetons ne bougent pas). */
body.ds-page .ds-form-symfony .form-group { display: flex; flex-direction: column; gap: 6px; margin-bottom: 18px; }
body.ds-page .ds-form-symfony label { font-size: 14px; font-weight: 500; color: var(--ds-grey-95); margin: 0; }
body.ds-page .ds-form-symfony .form-control,
body.ds-page .ds-form-symfony select,
body.ds-page .ds-form-symfony textarea {
    width: 100%;
    min-height: 48px;
    padding: 12px;
    font: inherit;
    font-size: 16px;
    color: var(--ds-grey-95);
    background: #fff;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    box-shadow: none;
    box-sizing: border-box;
}
body.ds-page .ds-form-symfony .form-control:focus-visible,
body.ds-page .ds-form-symfony select:focus-visible,
body.ds-page .ds-form-symfony textarea:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
    border-color: var(--ds-accent);
}
body.ds-page .ds-form-symfony .form-control.is-invalid,
body.ds-page .ds-form-symfony .is-invalid .form-control { border-color: var(--ds-err-fg); }
/* Message d'erreur de champ : Symfony le rend en <ul class="..."> juste après
   le widget. Sous le champ, rouge sobre, jamais une seule alerte en haut. */
body.ds-page .ds-form-symfony .form-group ul,
body.ds-page .ds-form-symfony .invalid-feedback,
body.ds-page .ds-form-symfony .form-error-message {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 14px;
    color: var(--ds-err-fg);
    display: block;
}
body.ds-page .ds-form-symfony input[type="checkbox"],
body.ds-page .ds-form-symfony input[type="radio"] { width: 20px; height: 20px; accent-color: var(--ds-accent); }
body.ds-page .ds-form-symfony .form-check,
body.ds-page .ds-form-symfony .checkbox { display: flex; align-items: flex-start; gap: 10px; }
body.ds-page .ds-form-symfony .form-check label,
body.ds-page .ds-form-symfony .checkbox label { font-weight: 400; font-size: 15px; line-height: 1.5; }

/* ── Case à cocher autonome (facturation identique, CGV) ── */
body.ds-page .ds-case {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 15px;
    line-height: 1.5;
    margin: 18px 0 0;
    cursor: pointer;
}
body.ds-page .ds-case input[type="checkbox"] { width: 20px; height: 20px; margin: 1px 0 0; flex: none; accent-color: var(--ds-accent); }

/* ── Confirmation de commande ── */
body.ds-page .ds-confirmation { max-width: 780px; margin: 0 auto; }
body.ds-page .ds-confirmation__entete { display: flex; gap: 16px; align-items: flex-start; margin-bottom: 28px; }
body.ds-page .ds-confirmation__coche {
    width: 44px;
    height: 44px;
    flex: none;
    border-radius: 999px;
    background: var(--ds-ok-bg);
    color: var(--ds-ok-fg);
    border: 1px solid var(--ds-ok-bd);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
}
body.ds-page .ds-confirmation__sous-titre { font-size: 15px; color: var(--ds-grey-60); margin: 6px 0 0; }
body.ds-page .ds-confirmation__cartes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-bottom: 28px; }
body.ds-page .ds-confirmation__carte {
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 20px;
    background: #fff;
    font-size: 15px;
    line-height: 1.55;
}
body.ds-page .ds-confirmation__carte h2 {
    margin: 0 0 10px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
}
body.ds-page .ds-confirmation__etapes { margin: 0; padding-left: 20px; font-size: 15px; line-height: 1.7; color: var(--ds-grey-95); }
body.ds-page .ds-confirmation__actions { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 28px; }

/* ── Connexion, code courriel, code TOTP ── */
body.ds-page .ds-auth-page {
    background: var(--ds-grey-05);
    min-height: 70vh;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: var(--ds-rythme-chapitre) 16px var(--ds-rythme-chapitre);
}
body.ds-page .ds-auth-carte {
    width: 100%;
    max-width: 440px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 40px;
}
body.ds-page .ds-auth-marque {
    display: block;
    text-align: center;
    margin-bottom: 24px;
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.015em;
    color: var(--ds-accent-texte, var(--ds-accent));
}
body.ds-page .ds-auth-marque img { max-width: 200px; max-height: 56px; width: auto; height: auto; }
body.ds-page .ds-auth-titre { margin: 0 0 8px; font-size: 27px; font-weight: 600; letter-spacing: -0.02em; text-align: center; }
body.ds-page .ds-auth-titre--gauche { text-align: left; }
body.ds-page .ds-auth-intro { margin: 0 0 24px; font-size: 15px; line-height: 1.55; color: var(--ds-grey-60); }
body.ds-page .ds-auth-intro--centre { text-align: center; }
body.ds-page .ds-auth-champs { display: flex; flex-direction: column; gap: 18px; }
body.ds-page .ds-auth-lien { font-size: 14px; font-weight: 500; }
body.ds-page .ds-auth-lien--droite { align-self: flex-end; }
body.ds-page .ds-auth-lien--centre { display: block; text-align: center; margin-top: 16px; }
body.ds-page .ds-auth-separateur { display: flex; align-items: center; gap: 16px; margin: 28px 0; }
body.ds-page .ds-auth-separateur::before,
body.ds-page .ds-auth-separateur::after { content: ""; flex: 1; height: 1px; background: var(--ds-grey-15); }
body.ds-page .ds-auth-separateur > span { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-auth-sso { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
body.ds-page .ds-auth-sso .ds-btn { gap: 8px; }
/* Champ mot de passe avec bouton d'affichage : le bouton reste dans le flux,
   le champ garde sa place, aucune superposition qui masquerait le texte saisi. */
body.ds-page .ds-champ-mdp { display: flex; align-items: stretch; gap: 8px; }
body.ds-page .ds-champ-mdp input { flex: 1 1 auto; min-width: 0; }
body.ds-page .ds-champ-mdp__voir {
    flex: none;
    width: 48px;
    min-height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #fff;
    color: var(--ds-grey-60);
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    cursor: pointer;
}
body.ds-page .ds-champ-mdp__voir:hover { color: var(--ds-grey-95); background: var(--ds-grey-05); }
body.ds-page .ds-champ-mdp__voir:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
}
/* Code à six cases : un seul champ réel (name, autocomplete, validation
   inchangés), six cases visuelles pilotées par ds-code.js. */
body.ds-page .ds-code-cases { display: flex; gap: 10px; margin-bottom: 8px; }
/* Spécificité : les cases vivent DANS un .ds-champ, dont la règle générique
   (body.ds-page .ds-champ input[type="text"]) impose width:100%. Mesuré en
   navigateur : chaque case faisait 358 px et la page débordait de 540 px.
   D'où le sélecteur complet ici, et le !important d'aucune sorte. */
body.ds-page .ds-champ input.ds-code-case,
body.ds-page .ds-code-case {
    width: 48px;
    height: 56px;
    flex: none;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    text-align: center;
    font: 600 22px/1 inherit;
    font-variant-numeric: tabular-nums;
    color: var(--ds-grey-95);
    background: #fff;
    box-sizing: border-box;
}
body.ds-page .ds-champ input.ds-code-case:focus-visible,
body.ds-page .ds-code-case:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
    outline-offset: var(--ds-focus-ring-offset, 2px);
    border-color: var(--ds-accent);
}
body.ds-page .ds-champ input.ds-code-champ-reel,
body.ds-page .ds-code-champ-reel { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
body.ds-page .ds-auth-badge {
    display: inline-block;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--ds-info-bg);
    color: var(--ds-info-fg);
    border: 1px solid var(--ds-info-bd);
    margin-bottom: 16px;
}
body.ds-page .ds-auth-carte .ds-btn { width: 100%; }
body.ds-page .ds-auth-sso .ds-btn { width: 100%; }

@media (max-width: 991.98px) {
    body.ds-page .ds-tunnel-inner { padding: 16px 16px 40px; }
    body.ds-page .ds-tunnel-grille { grid-template-columns: minmax(0, 1fr); gap: 20px; }
    body.ds-page .ds-tunnel-colonne { padding: 20px 16px; border-radius: var(--ds-radius-lg, 12px); }
    /* Le récapitulatif passe AU-DESSUS du formulaire, replié : c'est la
       disposition de l'écran C5 à 390. */
    body.ds-page .ds-tunnel-recap { position: static; order: -1; }
    body.ds-page .ds-tunnel-recap__bascule {
        display: flex;
        width: 100%;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        min-height: 52px;
        padding: 14px 16px;
        background: var(--ds-grey-05);
        border: 0;
        text-align: left;
        font: 600 15px/1.4 inherit;
        color: var(--ds-grey-95);
        cursor: pointer;
    }
    body.ds-page .ds-tunnel-recap__bascule:focus-visible {
        outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color, var(--ds-accent));
        outline-offset: calc(var(--ds-focus-ring-offset, 2px) * -1);
    }
    body.ds-page .ds-tunnel-recap__chevron {
        width: 8px;
        height: 8px;
        flex: none;
        border-right: 2px solid var(--ds-grey-60);
        border-bottom: 2px solid var(--ds-grey-60);
        transform: rotate(45deg);
        transition: transform 0.15s ease;
    }
    body.ds-page .ds-tunnel-recap--ouvert .ds-tunnel-recap__chevron { transform: rotate(-135deg); }
    body.ds-page .ds-tunnel-recap__contenu { display: none; border-top: 1px solid var(--ds-grey-15); padding: 18px 16px; }
    body.ds-page .ds-tunnel-recap--ouvert .ds-tunnel-recap__contenu { display: block; }
    body.ds-page .ds-tunnel-recap__lignes { max-height: none; }
    body.ds-page .ds-confirmation__cartes { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 767.98px) {
    body.ds-page .ds-etapes-tunnel__liste { display: none; }
    body.ds-page .ds-etapes-tunnel__mobile { display: block; margin: 0; }
    /* F15 mobile : une seule barre de 2px, pleine largeur, remplie a la
       proportion de l'etape courante (1/3, 2/3, 3/3). */
    body.ds-page .ds-etapes-tunnel__barres { display: block; }
    body.ds-page .ds-etapes-tunnel__barre {
        display: block;
        width: 100%;
        height: 2px;
        border-radius: 999px;
        background: linear-gradient(to right, var(--ds-accent) 0 var(--p, 0%), var(--ds-grey-15) var(--p, 0%) 100%);
        transition: --p var(--ds-dur-media) var(--ds-ease-inout);
    }
    body.ds-page .ds-etapes-tunnel--remplie .ds-etapes-tunnel__barre--sur-3-1 { --p: 33%; }
    body.ds-page .ds-etapes-tunnel--remplie .ds-etapes-tunnel__barre--sur-3-2 { --p: 66%; }
    body.ds-page .ds-etapes-tunnel--remplie .ds-etapes-tunnel__barre--sur-3-3 { --p: 100%; }
    body.ds-page .ds-etapes-tunnel--remplie .ds-etapes-tunnel__barre--sur-2-1 { --p: 50%; }
    body.ds-page .ds-etapes-tunnel--remplie .ds-etapes-tunnel__barre--sur-2-2 { --p: 100%; }
    body.ds-page .ds-etapes-tunnel__compteur { font-size: 14px; }
    body.ds-page .ds-etapes-tunnel__compteur {
        display: block;
        margin-top: 8px;
        font-size: 14px;
        color: var(--ds-grey-60);
        font-variant-numeric: tabular-nums;
    }
    body.ds-page .ds-tunnel-h1 { font-size: 24px; }
    body.ds-page .ds-form-grille { grid-template-columns: minmax(0, 1fr); }
    body.ds-page .ds-tunnel-actions { flex-direction: column; align-items: stretch; }
    body.ds-page .ds-tunnel-actions .ds-btn { width: 100%; }
    body.ds-page .ds-tunnel-retour { text-align: center; }
    body.ds-page .ds-auth-page { padding: 24px 16px 48px; }
    body.ds-page .ds-auth-carte { padding: 24px 16px; border: 0; }
    body.ds-page .ds-auth-sso { grid-template-columns: minmax(0, 1fr); }
    body.ds-page .ds-code-cases { gap: 6px; justify-content: space-between; }
    /* Spécificité : les cases vivent DANS un .ds-champ, dont la règle générique
   (body.ds-page .ds-champ input[type="text"]) impose width:100%. Mesuré en
   navigateur : chaque case faisait 358 px et la page débordait de 540 px.
   D'où le sélecteur complet ici, et le !important d'aucune sorte. */
body.ds-page .ds-champ input.ds-code-case,
body.ds-page .ds-code-case { width: 46px; }
    body.ds-page .ds-confirmation__actions { flex-direction: column; }
    body.ds-page .ds-confirmation__actions .ds-btn { width: 100%; }
}
body.ds-page .ds-tunnel-grille--large { grid-template-columns: minmax(0, 1fr); }

/* Le thème débranché portait `.hidden { display:none }` (style_sun.css, l. 127),
   seule règle qui masquait le bloc « mot de passe oublié » de la page de
   connexion. Sans elle, les deux formulaires s'affichaient l'un sous l'autre.
   Même piège qu'aux lots précédents : après un débranchement de thème, tout
   masquage d'un bloc piloté par JS doit être reporté ici. */
body.ds-page .hidden { display: none; }
body.ds-page .login-sso-notice { margin: 12px 0 0; font-size: 14px; color: var(--ds-grey-60); }

/* ══════════════════════════════════════════════════
   Refonte design (lot D4, 2026-09-17) : espace client.
   Écrit d'après l'écran C7 du système DRM (navigation latérale du compte,
   cartes de lecture avec « Modifier », tableau à badges, version 390 en
   cartes) et les écrans « Accueil connecté », « Mes achats », « Détail
   commande », « Mes demandes », « Favoris », « Produits habituels » et
   « Mon compte » du Portail Coiffinéa.

   Toutes les règles sont scopées sous body.ds-page : une page de l'espace
   client non redessinée ne porte pas la classe, donc rien ne peut l'atteindre.
   ══════════════════════════════════════════════════ */

body.ds-page .ds-compte-page { background: var(--ds-grey-05); padding: 0 0 48px; }
body.ds-page .ds-compte-inner { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
body.ds-page .ds-compte-h1 { margin: 0 0 6px; font-size: 28px; font-weight: 600; letter-spacing: -0.02em; }
body.ds-page .ds-compte-intro { margin: 0 0 20px; font-size: 15px; color: var(--ds-grey-60); }

body.ds-page .ds-compte-grille {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 32px;
    align-items: start;
    padding-top: 8px;
}
/* min-width:0 obligatoire sur les deux cellules : un item de grille vaut
   min-width:auto par défaut, un tableau plus large que sa colonne poussait donc
   .ds-tableau à 933px dans une colonne de 358px. Le débordement ne se voyait
   pas (la garde overflow:clip de #page-content-wrapper, héritée du thème, le
   masquait) et les colonnes de droite étaient perdues sans barre de
   défilement. */
body.ds-page .ds-compte-grille > * { min-width: 0; }
body.ds-page .ds-compte-contenu { min-width: 0; }

/* Navigation latérale du compte (C7). En dessous de 900px elle devient une
   barre d'onglets défilante horizontalement : aucune JS, aucun piège de focus,
   et l'entrée active reste visible grâce à scroll-snap. */
body.ds-page .ds-compte-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    position: sticky;
    top: 16px;
}
body.ds-page .ds-compte-nav__groupe {
    padding: 8px 12px 4px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ds-grey-40);
}
/* Retour de Martin (lot D7) : l'entrée active n'a plus ni filet latéral ni
   pastille de fond. Elle se lit à sa graisse et à un point d'accent discret,
   comme « Mon compte » du Portail Coiffinéa. La gouttière du point est
   réservée sur toutes les entrées : l'entrée active ne décale pas la liste. */
body.ds-page .ds-compte-nav__item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 8px;
    font-size: 15px;
    color: var(--ds-grey-95);
    text-decoration: none;
}
body.ds-page .ds-compte-nav__item::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: transparent;
}
body.ds-page a.ds-compte-nav__item { color: var(--ds-grey-95); }
body.ds-page a.ds-compte-nav__item:hover { background: var(--ds-grey-05); color: var(--ds-grey-95); text-decoration: none; }
body.ds-page .ds-compte-nav__item[aria-current="page"] {
    background: transparent;
    color: var(--ds-grey-95);
    font-weight: 600;
    box-shadow: none;
}
body.ds-page .ds-compte-nav__item[aria-current="page"]::before { background: var(--ds-accent); }
body.ds-page a.ds-compte-nav__item[aria-current="page"]:hover { background: var(--ds-grey-05); }
body.ds-page .ds-compte-nav__item:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 2px;
}
/* F7-7 (2026-09-18), retour Martin : la deconnexion se distingue par la couleur
   destructive du systeme (texte seul, jamais de fond rouge plein), comme les deux
   autres sorties du front (menu compte et tiroir mobile). */
body.ds-page .ds-compte-nav__sortie { margin-top: 8px; }
body.ds-page a.ds-compte-nav__sortie,
body.ds-page a.ds-compte-nav__sortie:hover { color: var(--ds-err-fg); }
body.ds-page a.ds-compte-nav__sortie:hover { background: var(--ds-err-bg); }

/* Cartes de lecture avec action « Modifier » (C7 Mes informations). */
body.ds-page .ds-compte-cartes { display: flex; flex-direction: column; gap: 20px; }
body.ds-page .ds-compte-carte {
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 24px;
}
body.ds-page .ds-compte-carte__entete {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 20px;
    flex-wrap: wrap;
}
body.ds-page .ds-compte-carte__entete h2,
body.ds-page .ds-compte-carte__titre { margin: 0; font-size: 20px; font-weight: 600; }
body.ds-page .ds-compte-carte__sous-titre { margin: 4px 0 0; font-size: 14px; color: var(--ds-grey-60); }

body.ds-page .ds-compte-defs {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px;
    margin: 0;
}
body.ds-page .ds-compte-defs > div { min-width: 0; }
body.ds-page .ds-compte-defs dt,
body.ds-page .ds-compte-defs__cle {
    display: block;
    font-size: 13px;
    font-weight: 400;
    color: var(--ds-grey-60);
    margin-bottom: 4px;
}
body.ds-page .ds-compte-defs dd,
body.ds-page .ds-compte-defs__valeur {
    display: block;
    margin: 0;
    font-size: 16px;
    color: var(--ds-grey-95);
    overflow-wrap: anywhere;
}
body.ds-page .ds-compte-defs--num dd { font-variant-numeric: tabular-nums; }

/* Retour de Martin (lot D7) : les cartes d'adresse suivent le patron « Mon
   compte » du Portail (libellé gris au-dessus, valeur en dessous), sur deux
   colonnes en desktop et une seule sous 767px. Titre de carte à 17px, action
   « Modifier » en bouton secondaire en haut à droite. Une valeur absente garde
   sa ligne et affiche un tiret discret. */
body.ds-page .ds-compte-defs--paire { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 24px; }
body.ds-page .ds-compte-defs--paire dd { font-size: 15px; }
body.ds-page .ds-compte-defs__vide { color: var(--ds-grey-40); }
body.ds-page .ds-compte-cartes--groupe { margin-bottom: 24px; }
body.ds-page .ds-compte-carte--adresse { padding: 20px 22px; }
body.ds-page .ds-compte-carte--adresse .ds-compte-carte__entete { align-items: center; margin-bottom: 16px; }
body.ds-page .ds-compte-carte--adresse .ds-compte-carte__titre { font-size: 17px; font-weight: 600; }
@media (max-width: 767.98px) {
    body.ds-page .ds-compte-defs--paire { grid-template-columns: minmax(0, 1fr); gap: 14px; }
}

/* Message de succès inline (C7) : jamais un toast qui disparaît, l'action de
   suite reste atteignable au clavier. */
body.ds-page .ds-compte-msg {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    border-radius: var(--ds-radius-lg, 12px);
    padding: 14px 16px;
    margin-bottom: 20px;
    font-size: 15px;
}
body.ds-page .ds-compte-msg--ok { background: var(--ds-ok-bg); color: var(--ds-ok-fg); border: 1px solid var(--ds-ok-bd); }
body.ds-page .ds-compte-msg--err { background: var(--ds-err-bg); color: var(--ds-err-fg); border: 1px solid var(--ds-err-bd); }
body.ds-page .ds-compte-msg--info { background: var(--ds-info-bg); color: var(--ds-info-fg); border: 1px solid var(--ds-info-bd); }
body.ds-page .ds-compte-msg a { color: inherit; font-weight: 600; text-decoration: underline; }

/* Tableau de liste (C7 Mes commandes). */
body.ds-page .ds-tableau {
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
}
body.ds-page .ds-tableau > .table-responsive { border-radius: inherit; }
body.ds-page .ds-tableau table { width: 100%; margin: 0; border-collapse: collapse; background: #fff; }
body.ds-page .ds-tableau thead tr { background: var(--ds-grey-05); }
body.ds-page .ds-tableau thead th {
    text-align: left;
    /* Marges interieures alignees sur celles des listes DataTables (12 px) :
       a 16 px, les huit colonnes de « Mes demandes » demandaient 859 px la ou
       le conteneur en offre 858, et la derniere colonne etait rognee. */
    padding: 0 12px;
    height: 44px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
    border: 0;
    border-bottom: 1px solid var(--ds-grey-15);
    vertical-align: middle;
    /* Lot F6, retour 1 : un intitule insecable fixe la largeur minimale de sa
       colonne. Sur « Mes demandes » (huit colonnes, tableau sans DataTables),
       la somme de ces minimums faisait 859 px dans un conteneur de 730, et
       .ds-tableau (overflow: hidden) rognait la colonne d'actions sans meme
       sortir de barre de defilement. L'intitule passe donc a la ligne. */
    white-space: normal;
    line-height: 1.25;
}
body.ds-page .ds-tableau tbody td {
    padding: 10px 12px;
    font-size: 15px;
    color: var(--ds-grey-95);
    border: 0;
    border-bottom: 1px solid var(--ds-grey-15);
    vertical-align: middle;
}
body.ds-page .ds-tableau tbody tr:last-child td { border-bottom: 0; }
body.ds-page .ds-tableau tbody tr:hover { background: var(--ds-grey-05); }
body.ds-page .ds-tableau .ds-tableau__num { font-weight: 500; font-variant-numeric: tabular-nums; white-space: nowrap; }
body.ds-page .ds-tableau .ds-tableau__montant { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
body.ds-page .ds-tableau .ds-tableau__date { color: var(--ds-grey-60); white-space: nowrap; }
body.ds-page .ds-tableau .ds-tableau__actions { text-align: right; white-space: nowrap; }
body.ds-page .ds-tableau-actions { display: inline-flex; align-items: center; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }
body.ds-page .ds-tableau-actions > a,
body.ds-page .ds-tableau-actions > button {
    font-size: 14px;
    font-weight: 500;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
    padding: 0 4px;
    background: none;
    border: 0;
    color: var(--ds-accent-texte, var(--ds-accent));
    cursor: pointer;
}
body.ds-page .ds-tableau-actions > a:focus-visible,
body.ds-page .ds-tableau-actions > button:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 2px;
}
body.ds-page .ds-tableau-actions__sep { color: var(--ds-grey-25); }

/* Barre de filtres au-dessus d'une liste (C7). */
body.ds-page .ds-compte-filtres {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 16px;
    align-items: flex-end;
    margin-bottom: 20px;
    padding: 16px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
}
body.ds-page .ds-compte-filtres .form-group { margin-bottom: 0; }
body.ds-page .ds-compte-filtres label { font-size: 13px; color: var(--ds-grey-60); margin-bottom: 4px; display: block; }
body.ds-page .ds-compte-filtres input[type="text"],
body.ds-page .ds-compte-filtres input[type="search"],
body.ds-page .ds-compte-filtres input[type="date"],
body.ds-page .ds-compte-filtres select {
    height: 40px;
    padding: 0 12px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    font-size: 15px;
    color: var(--ds-grey-95);
    max-width: 100%;
}
body.ds-page .ds-compte-filtres input:focus-visible,
body.ds-page .ds-compte-filtres select:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 1px;
}
body.ds-page .ds-compte-filtres .btn,
body.ds-page .ds-compte-filtres input[type="submit"],
body.ds-page .ds-compte-filtres button[type="submit"] {
    height: 40px;
    padding: 0 16px;
    border-radius: var(--ds-radius-control, 8px);
    border: 1px solid transparent;
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    font-size: 15px;
    font-weight: 600;
    box-shadow: none;
    text-transform: none;
    letter-spacing: normal;
}
body.ds-page .ds-compte-filtres .btn-secondary,
body.ds-page .ds-compte-filtres input[type="reset"] {
    background: #fff;
    color: var(--ds-grey-95);
    border-color: var(--ds-grey-25);
}

/* Cartes d'adresse / de collaborateur, grille auto. */
body.ds-page .ds-compte-grille-cartes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
}
body.ds-page .ds-compte-mini-carte {
    display: flex;
    flex-direction: column;
    gap: 10px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 16px 18px;
    font-size: 15px;
    line-height: 1.55;
}
body.ds-page .ds-compte-mini-carte__titre { font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-compte-mini-carte__corps { color: var(--ds-grey-60); }
body.ds-page .ds-compte-mini-carte__corps table { width: auto; margin: 0; font-size: 15px; }
body.ds-page .ds-compte-mini-carte__corps td { border: 0; padding: 1px 8px 1px 0; }
body.ds-page .ds-compte-mini-carte__actions { display: flex; gap: 14px; margin-top: auto; padding-top: 4px; }

/* Retour de Martin (lot D7) : « Mes collaborateurs » en cartes plutôt qu'en
   tableau de quatorze colonnes. Les deux actions portent leur libellé, la
   suppression reste plus petite et éloignée de l'action principale. */
body.ds-page .ds-collab-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 16px;
}
body.ds-page .ds-collab-carte {
    display: flex;
    flex-direction: column;
    gap: 12px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 20px 22px;
    min-width: 0;
}
body.ds-page .ds-collab-carte__entete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
body.ds-page .ds-collab-carte__nom { margin: 0; font-size: 17px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-collab-carte__email { margin: -6px 0 0; font-size: 15px; overflow-wrap: anywhere; }
body.ds-page .ds-collab-carte__email a { color: var(--ds-grey-60); }
body.ds-page .ds-collab-carte__bloc { display: flex; flex-direction: column; gap: 4px; }
body.ds-page .ds-collab-carte__cle { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-collab-carte__liste { margin: 0; padding: 0; list-style: none; font-size: 15px; line-height: 1.6; }
body.ds-page .ds-collab-carte__droit { margin: 0; font-size: 15px; line-height: 1.6; }
body.ds-page .ds-collab-carte__actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: auto;
    padding-top: 8px;
    border-top: 1px solid var(--ds-grey-10, var(--ds-grey-15));
}

/* En-tête de section avec action à droite. */
body.ds-page .ds-compte-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: var(--ds-rythme-bloc);
}
body.ds-page .ds-compte-section-head h2 { margin: 0; font-size: 20px; font-weight: 600; }

/* Accueil connecté : panier en cours et dernières commandes (Portail). */
body.ds-page .ds-accueil-blocs {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 20px;
    max-width: 1200px;
    margin: 0 auto;
    padding: 24px;
}
body.ds-page .ds-accueil-bloc {
    display: flex;
    flex-direction: column;
    gap: 12px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 18px 20px;
}
body.ds-page .ds-accueil-bloc--vide { border-style: dashed; justify-content: center; }
body.ds-page .ds-accueil-bloc__entete {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
}
body.ds-page .ds-accueil-bloc__entete h2 { margin: 0; font-size: 16px; font-weight: 600; }
body.ds-page .ds-accueil-bloc__meta { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-accueil-panier-lignes { display: flex; flex-direction: column; gap: 8px; margin: 0; padding: 0; list-style: none; }
body.ds-page .ds-accueil-panier-ligne {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    min-width: 0;
}
body.ds-page .ds-accueil-panier-ligne__nom { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.ds-page .ds-accueil-panier-ligne__qte { color: var(--ds-grey-60); white-space: nowrap; }
body.ds-page .ds-accueil-bloc__pied {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    border-top: 1px solid var(--ds-grey-15);
    padding-top: 12px;
    margin-top: auto;
}
body.ds-page .ds-accueil-commande {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-top: 1px solid var(--ds-grey-15);
    font-size: 14px;
    min-width: 0;
}
body.ds-page .ds-accueil-commande__titre { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
body.ds-page .ds-accueil-commande__num { font-weight: 600; font-variant-numeric: tabular-nums; }
body.ds-page .ds-accueil-commande__meta { color: var(--ds-grey-60); font-size: 13px; margin-top: 2px; }
body.ds-page .ds-accueil-commande__action { flex-shrink: 0; }
body.ds-page .ds-accueil-habituels { max-width: 1200px; margin: 0 auto; padding: 0 24px 24px; }
body.ds-page .ds-accueil-actus { display: flex; flex-direction: column; }
body.ds-page .ds-accueil-actu { padding: 12px 0; border-top: 1px solid var(--ds-grey-15); }
body.ds-page .ds-accueil-actu:first-child { border-top: 0; }
body.ds-page .ds-accueil-actu__date { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-accueil-actu__titre { display: block; margin-top: 2px; font-weight: 600; }

/* DataTables : les listes de l'espace client (commandes, factures, bons de
   livraison, reliquats, devis) portent leur tri, leur recherche, leur
   pagination et leur export par DataTables, dont la feuille bootstrap4 fait
   partie du thème débranché. Elle est rechargée par la page (gabarit
   user/ds-compte.html.twig, drapeau bDsCompteDataTables) parce que ces
   commandes en dépendent ; ces règles la ramènent au système visuel.

   Les noms de classe sont ceux de DataTables 2.x (dt-container, dt-search,
   dt-length, dt-info, dt-paging, dt-buttons), relevés dans le DOM rendu et non
   supposés : la 1.x employait dataTables_wrapper, dataTables_filter, etc. Les
   deux familles sont couvertes, la version peut bouger. */
body.ds-page .ds-tableau .dt-container,
body.ds-page .ds-tableau .dataTables_wrapper { padding: 0; }
/* .ds-tableau porte overflow:hidden pour ses coins arrondis : sans ce
   overflow-x:auto explicite sur l'enveloppe, les colonnes de droite (statut,
   actions) étaient CLIPPÉES sans barre de défilement sous 900px (mesuré :
   contenu de 933px dans un cadre de 358px, aucun débordement de page, donc
   invisible à l'oeil comme au contrôle de débordement). */
body.ds-page .ds-tableau > .table-responsive { overflow-x: auto; overflow-y: hidden; }
body.ds-page .ds-tableau .dt-layout-row { margin: 0; padding: 10px 14px; align-items: center; }
body.ds-page .ds-tableau .dt-layout-row:first-child { border-bottom: 1px solid var(--ds-grey-15); }
body.ds-page .ds-tableau .dt-search,
body.ds-page .ds-tableau .dt-length,
body.ds-page .ds-tableau .dataTables_filter,
body.ds-page .ds-tableau .dataTables_length { font-size: 14px; color: var(--ds-grey-60); }
body.ds-page .ds-tableau .dt-search input,
body.ds-page .ds-tableau .dt-length select,
body.ds-page .ds-tableau .dataTables_filter input,
body.ds-page .ds-tableau .dataTables_length select {
    height: 36px;
    padding: 0 10px;
    margin-left: 8px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    font-size: 14px;
    color: var(--ds-grey-95);
}
body.ds-page .ds-tableau .dt-search input:focus-visible,
body.ds-page .ds-tableau .dt-length select:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 1px;
}
/* Les boutons d'export sortent en .btn.btn-secondary de Bootstrap (gris plein),
   ils ne portent PAS la classe .dt-button : cibler le conteneur. */
body.ds-page .ds-tableau .dt-buttons { gap: 6px; flex-wrap: wrap; }
body.ds-page .ds-tableau .dt-buttons .btn,
body.ds-page .ds-tableau .dt-buttons .btn-secondary,
body.ds-page .ds-tableau .dt-button {
    height: 36px;
    padding: 0 12px;
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    color: var(--ds-grey-95);
    font-size: 14px;
    font-weight: 500;
    box-shadow: none;
    text-transform: none;
}
body.ds-page .ds-tableau .dt-buttons .btn:hover,
body.ds-page .ds-tableau .dt-buttons .btn:focus { background: var(--ds-grey-05); color: var(--ds-grey-95); }
body.ds-page .ds-tableau .dt-buttons .btn-group { gap: 6px; }
body.ds-page .ds-tableau .dt-info,
body.ds-page .ds-tableau .dataTables_info,
body.ds-page .ds-tableau .dt-paging,
body.ds-page .ds-tableau .dataTables_paginate { font-size: 14px; color: var(--ds-grey-60); }
body.ds-page .ds-tableau .pagination { margin: 0; flex-wrap: wrap; }
body.ds-page .ds-tableau .page-link {
    border-color: var(--ds-grey-15);
    color: var(--ds-grey-95);
    font-size: 14px;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
}
body.ds-page .ds-tableau .page-item.active .page-link {
    background: var(--ds-accent);
    border-color: var(--ds-accent);
    color: var(--ds-on-accent);
}
/* En-tête figé de DataTables (dt-scroll-head) : il se rend dans un tableau
   séparé, les règles de .ds-tableau thead doivent l'atteindre aussi. */
body.ds-page .ds-tableau .dt-scroll-head table { margin: 0; }
body.ds-page .ds-tableau .dt-scroll-body { border-bottom: 1px solid var(--ds-grey-15); }
/* Compaction : avec le padding par défaut, dix colonnes dépassaient la colonne
   de contenu (mesuré : tableau de 1169 px dans 860 px) et le statut comme les
   actions tombaient hors du cadre. */
body.ds-page .ds-tableau .dt-container table th,
body.ds-page .ds-tableau .dt-container table td { padding-left: 10px; padding-right: 10px; font-size: 14px; }
body.ds-page .ds-tableau .dt-container table th { font-size: 12px; }
body.ds-page .ds-tableau table.dataTable.table-striped > tbody > tr.odd > * { box-shadow: none; }
body.ds-page .ds-tableau table.dataTable > tbody > tr.selected > * { box-shadow: none; }
/* Les actions des listes sont des liens-icônes Font Awesome (accroches JS
   inchangées : .js-btn-detail-commande, .js-btn-regenere-commande, etc.).
   Chacun reçoit une cible de 32x32 au minimum, critère WCAG 2.2 2.5.8. */
body.ds-page .ds-tableau .btn-tableau { display: inline-flex; align-items: center; gap: 4px; }
/* Lot F6, retour 2 : cette largeur etait fixee a 32 px pour TOUS les liens de
   la colonne, y compris ceux qui portent un libelle. « Continuer le panier »,
   « Passer commande » et « Supprimer » debordaient donc de leur boite de 32 px
   et se peignaient les uns par-dessus les autres. La largeur devient un
   minimum : un lien-icone garde 32 px, un lien libelle prend la sienne. */
body.ds-page .ds-tableau .btn-tableau > a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 32px;
    padding: 0 4px;
    border-radius: var(--ds-radius-control);
    color: var(--ds-accent-texte, var(--ds-accent));
    text-decoration: none;
}
body.ds-page .ds-tableau .btn-tableau > a:hover { background: var(--ds-accent-light); color: var(--ds-on-accent-light); }
/* Action principale et action destructrice gardent leur couleur une fois
   passees en lien-icone. Elles etaient decrites plus bas sur .ds-tableau__action,
   d'une specificite inferieure a « .ds-tableau .btn-tableau > a » : la
   suppression ressortait en vert accent au lieu du rouge d'erreur. */
body.ds-page .ds-tableau .btn-tableau > a.ds-tableau__action--principale {
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
}
body.ds-page .ds-tableau .btn-tableau > a.ds-tableau__action--principale:hover {
    background: var(--ds-primary-bg);
    color: var(--ds-on-primary);
    filter: brightness(0.92);
}
body.ds-page .ds-tableau .btn-tableau > a.ds-tableau__action--destructive { color: var(--ds-err-fg); }
body.ds-page .ds-tableau .btn-tableau > a.ds-tableau__action--destructive:hover {
    background: var(--ds-err-bg);
    color: var(--ds-err-fg);
}
/* Lot D1 (2026-10-07), état 5 de DESIGN-PAIEMENT-EN-COURS.md : la ligne d'un panier verrouillé par une carte (ou
   gelé) n'a qu'une action, un bouton secondaire libellé (« Voir ou annuler », « Voir »), pas un lien-icône. */
body.ds-page .ds-tableau .btn-tableau > a.dr-ligne-carte {
    height: auto;
    min-height: 44px;
    padding: 0 16px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control);
    background: #ffffff;
    color: var(--ds-grey-95);
    font-weight: 600;
    white-space: nowrap;
    text-transform: none;
    letter-spacing: normal;
}
body.ds-page .ds-tableau .btn-tableau > a.dr-ligne-carte:hover { background: var(--ds-grey-05); color: var(--ds-grey-95); }
@media (max-width: 767.98px) {
    body.ds-page .ds-tableau .btn-tableau > a.dr-ligne-carte { width: 100%; min-height: 48px; justify-content: center; }
}
/* Lot D1 : actions du détail de panier historique (page d'import), boutons du système alignés à droite. */
body.ds-page .dr-panier-detail-historique { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-top: 12px; }
body.ds-page .dr-panier-detail-historique > form { margin: 0; display: flex; }
body.ds-page .dr-panier-detail-note { margin: 12px 0 0; }
@media (max-width: 767.98px) {
    body.ds-page .dr-panier-detail-historique { flex-direction: column; align-items: stretch; }
    body.ds-page .dr-panier-detail-historique .ds-btn { justify-content: center; min-height: 48px; }
}

@media (max-width: 1100px) {
    body.ds-page .ds-compte-grille { grid-template-columns: 220px minmax(0, 1fr); gap: 24px; }
    body.ds-page .ds-compte-defs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
    body.ds-page .ds-accueil-blocs { grid-template-columns: 1fr; padding: 16px; }
    /* Lot F6, retour 5 : la grille de cartes passe a 16 px de marge des 900 px,
       le bloc de titre doit la suivre au meme palier, sinon les deux bords se
       decalent de 8 px entre 768 et 900 px. */
    body.ds-page .ds-accueil-entete__inner { padding: 0 16px; }
    body.ds-page .ds-compte-grille { grid-template-columns: 1fr; gap: 16px; }
    /* F7-8 (2026-09-18), retour 8 de Martin : sous 900px, la barre d'onglets du
       compte faisait doublon avec la section « Mon compte » du menu hamburger (memes
       liens). Elle est retiree, le menu suffit. Le balisage desktop reste intact
       (la colonne laterale ne change pas au-dessus de 900px) : les rubriques du
       compte restent toutes atteignables par le hamburger (voir ds-header.html.twig,
       entrees ajoutees pour ne laisser aucun lien orphelin). */
    body.ds-page .ds-compte-nav { display: none; }
}

@media (max-width: 767px) {
    body.ds-page .ds-compte-inner { padding: 0 16px; }
    body.ds-page .ds-compte-h1 { font-size: 24px; }
    body.ds-page .ds-compte-defs { grid-template-columns: 1fr; gap: 14px; }
    body.ds-page .ds-compte-carte { padding: 18px; }
    body.ds-page .ds-accueil-habituels { padding: 0 16px 16px; }

    /* Liste en cartes (C7 390) : chaque cellule reprend son en-tête par
       data-libelle, posé côté gabarit. Ne s'applique qu'aux tableaux marqués
       .ds-tableau--cartes : les tableaux ajax construits par DataTables gardent
       leur mode responsive natif. */
    body.ds-page .ds-tableau--cartes { border: 0; background: none; }
    body.ds-page .ds-tableau--cartes table,
    body.ds-page .ds-tableau--cartes thead,
    body.ds-page .ds-tableau--cartes tbody,
    body.ds-page .ds-tableau--cartes tr,
    body.ds-page .ds-tableau--cartes td { display: block; width: 100%; }
    body.ds-page .ds-tableau--cartes thead { display: none; }
    body.ds-page .ds-tableau--cartes tbody tr {
        background: #fff;
        border: 1px solid var(--ds-grey-15);
        border-radius: var(--ds-radius-lg, 12px);
        padding: 14px;
        margin-bottom: 12px;
    }
    body.ds-page .ds-tableau--cartes tbody td {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 12px;
        padding: 4px 0;
        border: 0;
        text-align: left;
    }
    body.ds-page .ds-tableau--cartes tbody td::before {
        content: attr(data-libelle);
        font-size: 13px;
        color: var(--ds-grey-60);
        flex-shrink: 0;
    }
    body.ds-page .ds-tableau--cartes tbody td:empty { display: none; }
    body.ds-page .ds-tableau--cartes .ds-tableau__actions {
        padding-top: 10px;
        margin-top: 6px;
        border-top: 1px solid var(--ds-grey-15);
        text-align: left;
    }
    body.ds-page .ds-tableau--cartes .ds-tableau__actions::before { content: none; }
    body.ds-page .ds-tableau--cartes .ds-tableau-actions { justify-content: flex-start; gap: 16px; }
}

/* Grille de cartes en pleine largeur (produits habituels de l'accueil) : la
   grille du catalogue est calée sur une colonne de contenu étroite (2 puis 3
   colonnes), elle laisserait ici d'énormes cartes sur 1440. */
body.ds-page .ds-product-grid--auto { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }
@media (min-width: 768px) { body.ds-page .ds-product-grid--auto { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); } }
@media (min-width: 1440px) { body.ds-page .ds-product-grid--auto { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); } }

/* Univers de l'accueil (lot D4) : cartes de catégorie, image au-dessus et nom
   dessous, sur une grille qui ne dépend d'aucun thème. */
body.ds-page .ds-univers-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
}
/* Retour de Martin (lot D7) : la carte d'univers mesurait 440px de haut pour
   une illustration de 145px, avec un grand vide au-dessus et en dessous, et le
   survol posait une bordure epaisse et soulignait le titre. Illustration en
   4:3, centree sur un fond gris, titre dessous, survol en ombre et en levee
   d'un pixel, bordure inchangee. */
body.ds-page .ds-univers-carte {
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
    color: var(--ds-grey-95);
    text-decoration: none;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}
body.ds-page a.ds-univers-carte { color: var(--ds-grey-95); }
body.ds-page .ds-univers-carte:hover {
    border-color: var(--ds-grey-15);
    text-decoration: none;
    box-shadow: var(--ds-shadow-2);
    transform: translateY(-1px);
}
body.ds-page .ds-univers-carte__media {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: var(--ds-grey-05);
    overflow: hidden;
}
/* L'illustration remplit le cadre : les visuels de categorie de cette instance
   sont des SVG a fond blanc et a large marge interne. En « contain », leur fond
   blanc se decoupait en rectangle au milieu du gris. En « cover », le cadre est
   plein, sans bande vide ni raccord de couleur. */
body.ds-page .ds-univers-carte__media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}
body.ds-page .ds-univers-carte__nom {
    display: block;
    padding: 14px;
    font-size: 17px;
    font-weight: 600;
    line-height: 1.3;
    text-decoration: none;
}
body.ds-page .ds-univers-grille a.ds-univers-carte:hover,
body.ds-page .ds-univers-grille a.ds-univers-carte:hover .ds-univers-carte__nom { text-decoration: none; }
body.ds-page .ds-univers-carte:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 2px;
}

/* ==========================================================================
   Lot D5 (2026-09-17) : inscription
   Reprise du patron de la carte de connexion (lot D3) en deux largeurs :
   --moyen pour l'inscription grand public, --large pour l'inscription
   professionnelle, qui compte quatre sections et treize champs.
   ========================================================================== */
body.ds-page .ds-auth-carte--moyen { max-width: 640px; }
body.ds-page .ds-auth-carte--large { max-width: 880px; }

/* La carte de connexion étire ses boutons sur toute la largeur
   (body.ds-page .ds-auth-carte .ds-btn { width: 100% }). Sur une carte
   d'inscription, les deux actions vivent côte à côte : on rend la largeur au
   contenu, avec la même spécificité plus une classe. */
body.ds-page .ds-auth-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    margin-top: 28px;
}
body.ds-page .ds-auth-carte .ds-auth-actions .ds-btn,
body.ds-page .ds-auth-carte .ds-auth-actions input[type="submit"],
body.ds-page .ds-auth-carte .ds-auth-actions button[type="submit"] { width: auto; }

body.ds-page .ds-auth-section {
    margin: 28px 0 14px;
    padding-top: 20px;
    border-top: 1px solid var(--ds-grey-15);
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ds-grey-95);
}
body.ds-page .ds-auth-section:first-of-type { margin-top: 8px; padding-top: 0; border-top: 0; }

body.ds-page .ds-auth-consentements { margin-top: 24px; display: flex; flex-direction: column; gap: 12px; }
body.ds-page .ds-auth-recaptcha { display: flex; justify-content: center; margin-top: 20px; }
body.ds-page .ds-auth-pied { margin: 24px 0 0; text-align: center; font-size: 14px; color: var(--ds-grey-60); }

/* Exigences du mot de passe : le `display:none` par défaut n'existait que dans
   les style_*.css du thème historique, débranché sur les pages redessinées.
   Sans ce report, le bloc s'affichait en permanence, toutes les lignes en
   rouge, avant même la première frappe. `initPasswordChecker()` le montre au
   focus du champ et bascule les classes valid/invalid ligne par ligne. */
body.ds-page #pswd_info { display: none; }
body.ds-page .ds-mdp-regles {
    margin-top: 4px;
    padding: 14px 16px;
    background: var(--ds-grey-05);
    border-radius: var(--ds-radius-md, 10px);
    font-size: 14px;
}
body.ds-page .ds-mdp-regles h4 { margin: 0 0 8px; font-size: 14px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-mdp-regles ul { margin: 0; padding-left: 18px; line-height: 1.7; }
body.ds-page .ds-mdp-regles .invalid { color: var(--ds-err-fg); }
body.ds-page .ds-mdp-regles .valid { color: var(--ds-ok-fg); }

@media (max-width: 767.98px) {
    body.ds-page .ds-auth-actions { flex-direction: column; align-items: stretch; }
    body.ds-page .ds-auth-carte .ds-auth-actions .ds-btn,
    body.ds-page .ds-auth-carte .ds-auth-actions input[type="submit"],
    body.ds-page .ds-auth-carte .ds-auth-actions button[type="submit"] { width: 100%; }
}

/* ==========================================================================
   Lot D5 (2026-09-17) : fin du tunnel visiteur (paiement, confirmation)
   ========================================================================== */
body.ds-page .ds-paiement-note { margin: 12px 0 0; font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-paiement-adresse { margin-top: 24px; }
body.ds-page .ds-paiement-adresse address { margin: 0; font-style: normal; font-size: 15px; line-height: 1.6; color: var(--ds-grey-95); }
body.ds-page #payment-element { margin-bottom: 20px; }

body.ds-page .ds-confirmation__titre { margin: 0; font-size: 27px; font-weight: 600; letter-spacing: -0.02em; }
body.ds-page .ds-confirmation__numero { margin: 0 0 20px; font-size: 15px; color: var(--ds-grey-60); }
body.ds-page .ds-confirmation__numero strong { font-variant-numeric: tabular-nums; color: var(--ds-grey-95); }
body.ds-page .ds-confirmation__carte address { margin: 0; font-style: normal; font-size: 15px; line-height: 1.6; color: var(--ds-grey-95); }
body.ds-page .ds-confirmation__lignes { margin: 0; padding: 0; list-style: none; font-size: 15px; }
body.ds-page .ds-confirmation__lignes li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--ds-grey-15);
    line-height: 1.4;
}
body.ds-page .ds-confirmation__lignes li:last-child { border-bottom: 0; }
body.ds-page .ds-confirmation__qte { flex: none; color: var(--ds-grey-60); font-variant-numeric: tabular-nums; }
body.ds-page .ds-confirmation__total {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin: 12px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--ds-grey-25);
    font-size: 15px;
}
body.ds-page .ds-confirmation__total strong { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   Lot D5 (2026-09-17) : gabarit éditorial
   Partagé par les actualités, les pages légales, les pages personnalisées et
   le contact. Une seule colonne, texte borné à 70 caractères (contrat SEO
   §3.5), aucune colonne latérale.
   ========================================================================== */
body.ds-page .ds-edito-page { background: #fff; }
body.ds-page .ds-edito-inner { max-width: 1200px; margin: 0 auto; padding: 24px 24px 64px; }
body.ds-page .ds-edito-h1 { margin: 8px 0 12px; }
body.ds-page .ds-edito-article { max-width: 70ch; }
body.ds-page .ds-edito-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin: 0 0 24px;
    font-size: 14px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-edito-visuel {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    border-radius: var(--ds-radius-lg, 12px);
    background: var(--ds-grey-05);
    margin-bottom: 28px;
}
/* Corps saisi au back-office : on borne la largeur et on normalise le rythme,
   sans imposer de couleur aux éléments qui en portent une. */
body.ds-page .ds-edito-texte { max-width: 70ch; font-size: 16px; line-height: 1.7; color: var(--ds-grey-95); }
body.ds-page .ds-edito-texte > *:first-child { margin-top: 0; }
body.ds-page .ds-edito-texte p { margin: 0 0 16px; }
body.ds-page .ds-edito-texte h2 { margin: 36px 0 12px; font-size: 22px; font-weight: 600; letter-spacing: -0.015em; scroll-margin-top: 96px; }
body.ds-page .ds-edito-texte h3 { margin: 28px 0 10px; font-size: 18px; font-weight: 600; }
body.ds-page .ds-edito-texte ul,
body.ds-page .ds-edito-texte ol { margin: 0 0 16px; padding-left: 22px; }
body.ds-page .ds-edito-texte li { margin-bottom: 6px; }
body.ds-page .ds-edito-texte img { max-width: 100%; height: auto; }
body.ds-page .ds-edito-texte table { width: 100%; border-collapse: collapse; margin: 0 0 20px; font-size: 15px; }
body.ds-page .ds-edito-texte th,
body.ds-page .ds-edito-texte td { border: 1px solid var(--ds-grey-15); padding: 8px 10px; text-align: left; }
body.ds-page .ds-edito-piece { margin: 28px 0 0; font-size: 15px; }
body.ds-page .ds-edito-piece i { margin-right: 8px; }
body.ds-page .ds-edito-retour { margin: 40px 0 0; font-size: 15px; }

/* Sommaire discret : rendu seulement quand le contenu porte des H2. */
body.ds-page .ds-edito-sommaire {
    max-width: 70ch;
    margin: 0 0 32px;
    padding: 16px 18px;
    background: var(--ds-grey-05);
    border-radius: var(--ds-radius-md, 10px);
}
body.ds-page .ds-edito-sommaire__titre { margin: 0 0 8px; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ds-grey-60); }
body.ds-page .ds-edito-sommaire ol { margin: 0; padding-left: 20px; font-size: 15px; line-height: 1.7; }

/* Cartes d'actualité */
body.ds-page .ds-actus-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 24px;
    margin-top: 24px;
}
body.ds-page .ds-actu-carte {
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
}
/* Retour de Martin (lot D7) : illustration en 16/9 en haut de carte, titre a
   17px, chapeau sur deux lignes. Sans illustration, le cadre garde sa hauteur et
   porte le nom du site en filigrane, jamais une carte a moitie vide. */
body.ds-page .ds-actu-carte__media {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: var(--ds-grey-05);
    overflow: hidden;
    padding: 0 16px;
}
body.ds-page .ds-actu-carte__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
body.ds-page .ds-actu-carte__filigrane {
    font-size: 16px;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--ds-grey-25);
    text-align: center;
    overflow-wrap: anywhere;
}
body.ds-page .ds-actu-carte__corps { display: flex; flex-direction: column; gap: 10px; padding: 18px; }
body.ds-page .ds-actu-carte__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0; font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-actu-carte__titre { margin: 0; font-size: 17px; font-weight: 600; line-height: 1.35; letter-spacing: -0.01em; }
body.ds-page .ds-actu-carte__titre a { color: var(--ds-grey-95); }
body.ds-page .ds-actu-carte__titre a:hover { color: var(--ds-accent-texte, var(--ds-accent)); }
body.ds-page .ds-actu-carte__chapeau {
    margin: 0;
    font-size: 15px;
    line-height: 1.6;
    color: var(--ds-grey-60);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
/* Trois cartes cote a cote sur l'accueil connecte, une colonne sous 768px. */
body.ds-page .ds-actus-grille--trois { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: 0; }
@media (max-width: 1023.98px) {
    body.ds-page .ds-actus-grille--trois { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767.98px) {
    body.ds-page .ds-actus-grille--trois { grid-template-columns: minmax(0, 1fr); }
}
/* « Lire la suite » reste un lien reconnaissable (couleur d'accent) mais
   discret : 14px, graisse 500, jamais un bouton, jamais souligne. */
body.ds-page .ds-actu-carte__lien { margin-top: auto; padding-top: 4px; font-size: 14px; font-weight: 500; }
body.ds-page .ds-actu-carte a.ds-actu-carte__lien:hover { text-decoration: none; }

@media (max-width: 767.98px) {
    body.ds-page .ds-edito-inner { padding: 16px 16px 48px; }
    body.ds-page .ds-actus-grille { grid-template-columns: minmax(0, 1fr); gap: 16px; }
}

/* Les messages « vous n'avez pas les droits » et les encarts d'information des
   listes gardent leurs classes Bootstrap d'origine (.alert .alert-danger,
   .alert-info) en plus de la classe du systeme visuel : plusieurs tests de
   non-regression les lisent comme marqueur du message propre rendu a la place
   d'une erreur (ex. FactureControllerMesFacturesTest, dans les deux sens :
   present sans le droit, absent avec le droit). La regle du systeme visuel
   l'emporte sur celle de Bootstrap (body.ds-page .x est plus specifique que
   .alert-danger), il reste a neutraliser ce que Bootstrap ajoute seul. */
body.ds-page .ds-compte-msg.alert { position: static; margin-bottom: 20px; }

/* ==========================================================================
   Lot D5 (2026-09-17) : page de contact
   ========================================================================== */
body.ds-page .ds-contact-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 48px;
    align-items: start;
    margin-top: 24px;
}
body.ds-page .ds-contact-form { max-width: 70ch; }
body.ds-page .ds-contact-sous-titre { margin: 0 0 20px; font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
body.ds-page .ds-contact-infos {
    background: var(--ds-grey-05);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 24px;
    font-size: 15px;
    line-height: 1.6;
    color: var(--ds-grey-95);
}
body.ds-page .ds-contact-bloc { margin-bottom: 20px; }
body.ds-page .ds-contact-bloc:last-child { margin-bottom: 0; }
body.ds-page .ds-contact-bloc h3 { margin: 0 0 6px; font-size: 14px; font-weight: 600; color: var(--ds-grey-60); }
body.ds-page .ds-contact-bloc p { margin: 0 0 4px; }
body.ds-page .ds-contact-nom { font-weight: 600; }
body.ds-page .ds-form-symfony textarea { min-height: 160px; }

@media (max-width: 991.98px) {
    body.ds-page .ds-contact-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ds-rythme-bloc); }
    body.ds-page .ds-contact-infos { order: 2; }
}
body.ds-page .ds-contact-sans-formulaire { margin: 0; font-size: 15px; line-height: 1.6; color: var(--ds-grey-60); max-width: 60ch; }
body.ds-page .ds-edito-surtitre { margin: 8px 0 0; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ds-grey-60); }
body.ds-page .ds-edito-texte h3 { scroll-margin-top: 96px; }

/* ==========================================================================
   Lot D5 (2026-09-17) : page de résultats de recherche
   Le champ pré-rempli du contrôleur, jamais rendu jusqu'ici, revient sous le H1.
   ========================================================================== */
body.ds-page .ds-recherche-champ { margin: 0 0 24px; }
body.ds-page .ds-recherche-champ form { display: flex; gap: 10px; max-width: 560px; align-items: stretch; }
body.ds-page .ds-recherche-champ .form-group { flex: 1 1 auto; min-width: 0; margin: 0; }
body.ds-page .ds-recherche-champ .ds-btn { flex: none; }
@media (max-width: 575.98px) {
    body.ds-page .ds-recherche-champ form { flex-direction: column; }
    body.ds-page .ds-recherche-champ .ds-btn { width: 100%; }
}

/* ==========================================================================
   Lot D5 (2026-09-17) : pages d'erreur (404, erreur générique)
   Gabarits autonomes : aucune sous-requête, aucun texte technique.
   ========================================================================== */
body.ds-page .ds-erreur-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 48px 16px;
    background: var(--ds-grey-05);
}
body.ds-page .ds-erreur-carte {
    width: 100%;
    max-width: 520px;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 40px;
    text-align: center;
}
body.ds-page .ds-erreur-code { margin: 0 0 12px; font-size: 13px; font-weight: 600; letter-spacing: 0.08em; color: var(--ds-grey-60); font-variant-numeric: tabular-nums; }
body.ds-page .ds-erreur-titre { margin: 0 0 12px; font-size: 27px; font-weight: 600; letter-spacing: -0.02em; color: var(--ds-grey-95); }
body.ds-page .ds-erreur-texte { margin: 0 0 28px; font-size: 15px; line-height: 1.6; color: var(--ds-grey-60); }
body.ds-page .ds-erreur-actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin: 0; }
@media (max-width: 575.98px) {
    body.ds-page .ds-erreur-carte { padding: 28px 20px; }
    body.ds-page .ds-erreur-actions { flex-direction: column; }
    body.ds-page .ds-erreur-actions .ds-btn { width: 100%; }
}

/* ==========================================================================
   Lot D5 (2026-09-17) : cases a cocher des formulaires Symfony
   Bootstrap 4 est charge hors du bloc de theme debranche : sa regle
   `.form-check-input { position: absolute; margin-left: -1.25rem }` sortait la
   case du flux, et `.custom-control-input { opacity: 0 }` la rendait invisible
   sans le pseudo-element de `.custom-control` qui la redessinait dans l'ancien
   theme. Constate en navigateur sur l'inscription et sur l'etape 2 du tunnel
   visiteur. On remet la case dans le flux et on lui redonne une taille.
   ========================================================================== */
body.ds-page .ds-form-symfony .form-check,
body.ds-page .ds-champ .form-check,
body.ds-page .ds-form-symfony .custom-control,
body.ds-page .ds-champ .custom-control {
    position: relative;
    padding-left: 0;
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 10px;
    min-height: 24px;
}
/* Le lien « lire » des CGU est un troisieme element de la ligne : il suit le
   libelle et passe a la ligne plutot que d'etre renvoye au bord droit. */
body.ds-page .ds-form-symfony .form-check > a,
body.ds-page .ds-champ .form-check > a,
body.ds-page .ds-form-symfony .custom-control > a,
body.ds-page .ds-champ .custom-control > a { align-self: center; font-size: 15px; }
body.ds-page .ds-form-symfony .form-check .form-check-input,
body.ds-page .ds-champ .form-check .form-check-input,
body.ds-page .ds-form-symfony .custom-control-input,
body.ds-page .ds-champ .custom-control-input {
    position: static;
    opacity: 1;
    z-index: auto;
    flex: none;
    width: 20px;
    height: 20px;
    margin: 2px 0 0;
    accent-color: var(--ds-accent);
}
body.ds-page .ds-form-symfony .form-check-label,
body.ds-page .ds-champ .form-check-label,
body.ds-page .ds-form-symfony .custom-control-label,
body.ds-page .ds-champ .custom-control-label {
    font-weight: 400;
    font-size: 15px;
    line-height: 1.5;
    /* Cible pointeur d'au moins 24 px de haut (WCAG 2.2, 2.5.8) : le libelle
       est lie par `for`, c'est lui la vraie cible. Il reste sur la ligne de la
       case et enroule son texte a l'interieur : `display:inline-flex` le
       renvoyait entierement a la ligne suivante des que le texte etait long
       (constate a 390 px sur l'inscription grand public). */
    flex: 1 1 200px;
    min-width: 0;
    display: block;
    min-height: 24px;
    padding-top: 1px;
    margin: 0;
    cursor: pointer;
}
body.ds-page .ds-form-symfony .custom-control-label::before,
body.ds-page .ds-champ .custom-control-label::before,
body.ds-page .ds-form-symfony .custom-control-label::after,
body.ds-page .ds-champ .custom-control-label::after { content: none; }

/* ==========================================================================
   Lot D7 (2026-09-17), retour de Martin : respiration en tete de page
   --------------------------------------------------------------------------
   Le fil d'Ariane collait au bas du header et le H1 collait au fil d'Ariane sur
   les gabarits dont le conteneur n'avait pas de retrait haut (fiche, panier,
   compte). Une seule regle pour tous les conteneurs de page redessinee :
   24px avant le fil d'Ariane en desktop, 16px sous 768px, 8px entre le fil
   d'Ariane et le H1, 24px apres le H1.
   ========================================================================== */
body.ds-page .ds-category-inner,
body.ds-page .ds-fiche-inner,
body.ds-page .ds-panier-inner,
body.ds-page .ds-tunnel-inner,
body.ds-page .ds-compte-inner,
body.ds-page .ds-edito-inner { padding-top: 24px; }

body.ds-page .ds-ariane { margin: 0 0 8px; }

body.ds-page .ds-category-h1,
body.ds-page .ds-panier-h1,
body.ds-page .ds-tunnel-h1,
body.ds-page .ds-compte-h1,
body.ds-page .ds-edito-h1 { margin-top: 0; margin-bottom: 24px; }

/* La grille du compte portait un retrait haut de 8px qui s'ajoutait a la marge
   du H1 : le H1 doit rester a 24px de ce qui le suit, pas 32. */
body.ds-page .ds-compte-grille,
body.ds-page .ds-compte-contenu > .ds-compte-cartes:first-child { padding-top: 0; }

@media (max-width: 767.98px) {
    body.ds-page .ds-category-inner,
    body.ds-page .ds-fiche-inner,
    body.ds-page .ds-panier-inner,
    body.ds-page .ds-tunnel-inner,
    body.ds-page .ds-compte-inner,
    body.ds-page .ds-edito-inner { padding-top: 16px; }
}

/* ==========================================================================
   Lot D7 (2026-09-17), retour de Martin : une seule regle de survol
   --------------------------------------------------------------------------
   Toutes les cartes cliquables repondent de la meme facon : ombre discrete et
   levee d'un pixel en 150ms. Jamais de bordure epaisse, jamais de titre
   souligne. Les boutons s'assombrissent de 6% au survol et de 10% a l'appui,
   et gardent leur anneau de focus.
   ========================================================================== */
body.ds-page .ds-carte,
body.ds-page .ds-actu-carte {
    transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}
body.ds-page .ds-carte:hover,
body.ds-page .ds-actu-carte:hover {
    border-color: var(--ds-grey-15);
    box-shadow: var(--ds-shadow-2);
    transform: translateY(-1px);
}
body.ds-page .ds-carte a.ds-carte__nom:hover,
body.ds-page .ds-carte .ds-carte__media-lien:hover,
body.ds-page .ds-actu-carte .ds-actu-carte__titre a:hover,
body.ds-page .ds-actu-carte a.ds-actu-carte__media:hover { text-decoration: none; }

/* Boutons : assombrissement, jamais d'eclaircissement (le principal partait en
   brightness(1.12), ce qui delavait l'accent au lieu de l'appuyer). */
.ds-btn--primary:hover { filter: brightness(0.94); color: var(--ds-on-primary); text-decoration: none; }
.ds-btn--primary:focus-visible { filter: none; color: var(--ds-on-primary); text-decoration: none; }
.ds-btn--primary:active { filter: brightness(0.90); }
.ds-btn--secondary:active { background: var(--ds-grey-15); }
.ds-btn--discret:active { filter: brightness(0.94); }
.ds-btn--destructif:active { filter: brightness(0.94); }

@media (prefers-reduced-motion: reduce) {
    body.ds-page .ds-carte,
    body.ds-page .ds-actu-carte,
    body.ds-page .ds-univers-carte { transition: none; }
    body.ds-page .ds-carte:hover,
    body.ds-page .ds-actu-carte:hover,
    body.ds-page .ds-univers-carte:hover { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Lot D6 (2026-09-17) : dettes restantes de l'espace client
   ══════════════════════════════════════════════════════════════════════════ */

/* D4-2 : détail d'une commande, écran « Détail commande » du Portail. Rendu
   dans la fenêtre ouverte depuis « Mes commandes » : les règles sont donc
   portées par body.ds-page (la fenêtre est ajoutée au body de la page) et non
   par un conteneur de page. */
body.ds-page .ds-cde-detail { font-size: 15px; color: var(--ds-grey-95); }
body.ds-page .ds-cde-detail__entete {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px 24px;
    padding-bottom: 16px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-cde-detail__num { margin: 0; font-size: 20px; font-weight: 600; }
body.ds-page .ds-cde-detail__meta { margin: 4px 0 0; font-size: 14px; color: var(--ds-grey-60); }
body.ds-page .ds-cde-detail__resume { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
body.ds-page .ds-cde-detail__montant { font-size: 18px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }

body.ds-page .ds-cde-detail__grille {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 24px;
    align-items: start;
}
body.ds-page .ds-cde-detail__lignes {
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
    background: #fff;
}
body.ds-page .ds-cde-detail__lignes-entete,
body.ds-page .ds-cde-detail__ligne {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr) 110px 70px 110px;
    gap: 12px;
    align-items: center;
    padding: 10px 16px;
}
body.ds-page .ds-cde-detail__lignes-entete {
    background: var(--ds-grey-05);
    border-bottom: 1px solid var(--ds-grey-15);
    font-size: 12px;
    font-weight: 600;
    color: var(--ds-grey-60);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
body.ds-page .ds-cde-detail__ligne { border-bottom: 1px solid var(--ds-grey-10, var(--ds-grey-15)); font-size: 14px; }
body.ds-page .ds-cde-detail__ligne:last-child { border-bottom: 0; }
body.ds-page .ds-cde-detail__col-prix,
body.ds-page .ds-cde-detail__col-total { text-align: right; font-variant-numeric: tabular-nums; }
body.ds-page .ds-cde-detail__col-qte { text-align: center; font-variant-numeric: tabular-nums; }
body.ds-page .ds-cde-detail__total { font-weight: 600; }
body.ds-page .ds-cde-detail__prix { color: var(--ds-grey-60); }
body.ds-page .ds-cde-detail__visuel {
    width: 44px;
    height: 44px;
    border-radius: var(--ds-radius-sm, 6px);
    background: var(--ds-grey-05);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
body.ds-page .ds-cde-detail__visuel img { width: 44px; height: 44px; object-fit: contain; }
body.ds-page .ds-cde-detail__visuel-vide { color: var(--ds-grey-40); font-size: 16px; }
body.ds-page .ds-cde-detail__produit { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.ds-page .ds-cde-detail__produit .ds-badge { align-self: flex-start; margin-top: 2px; }
body.ds-page .ds-cde-detail__nom { font-weight: 600; color: var(--ds-grey-95); overflow-wrap: anywhere; }
body.ds-page .ds-cde-detail a.ds-cde-detail__nom { color: var(--ds-grey-95); text-decoration: none; }
body.ds-page .ds-cde-detail a.ds-cde-detail__nom:hover { text-decoration: underline; }
body.ds-page .ds-cde-detail__ref { font-size: 12px; color: var(--ds-grey-60); }
body.ds-page .ds-cde-detail__reliquat {
    grid-column: 2 / -1;
    font-size: 12px;
    font-weight: 500;
    color: var(--ds-warn-fg, var(--ds-grey-60));
}
body.ds-page .ds-cde-detail__libelle-mobile { display: none; }

body.ds-page .ds-cde-detail__cote { display: flex; flex-direction: column; gap: 14px; }
body.ds-page .ds-cde-detail__bloc {
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    padding: 16px 18px;
    font-size: 14px;
}
body.ds-page .ds-cde-detail__bloc-titre { margin: 0 0 10px; font-size: 13px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-cde-detail__adresse { margin: 0; color: var(--ds-grey-60); line-height: 1.6; }
body.ds-page .ds-cde-detail__qr { color: var(--ds-grey-60); line-height: 1.6; }
body.ds-page .ds-cde-detail__total-ligne {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 0;
    color: var(--ds-grey-60);
}
body.ds-page .ds-cde-detail__total-ligne strong { color: var(--ds-grey-95); font-variant-numeric: tabular-nums; }
body.ds-page .ds-cde-detail__total-ligne--final {
    border-top: 1px solid var(--ds-grey-15);
    margin-top: 6px;
    padding-top: 10px;
    font-size: 16px;
    font-weight: 600;
    color: var(--ds-grey-95);
}
body.ds-page .ds-cde-detail__docs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
body.ds-page .ds-cde-detail__docs a { color: var(--ds-accent-texte, var(--ds-accent)); text-decoration: none; }
body.ds-page .ds-cde-detail__docs a:hover { text-decoration: underline; }
/* ==========================================================================
   Lot F6 (2026-09-18), retour 3 : detail d'un panier
   Le gabarit _partials/ds-panier-detail.html.twig partage les classes du detail
   de commande (lot D6). Ne s'ajoutent ici que la colonne de suppression de
   ligne, la remise affichee sous le prix unitaire et le pied d'actions.
   ========================================================================== */
body.ds-page .ds-cde-detail--panier .ds-cde-detail__lignes-entete,
body.ds-page .ds-cde-detail--panier .ds-cde-detail__ligne {
    grid-template-columns: 44px minmax(0, 1fr) 110px 132px 110px 32px;
}
body.ds-page .ds-cde-detail__remise { display: block; font-size: 12px; color: var(--ds-grey-60); }
body.ds-page .ds-cde-detail__ligne-action { display: flex; justify-content: flex-end; }
body.ds-page .ds-cde-detail__suppr {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: var(--ds-radius-control);
    color: var(--ds-grey-60);
    font-size: 18px;
    line-height: 1;
    text-decoration: none;
}
body.ds-page .ds-cde-detail__suppr:hover { background: var(--ds-err-bg); color: var(--ds-err-fg); text-decoration: none; }
body.ds-page .ds-cde-detail__suppr:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 2px;
}
/* Le selecteur de quantite du detail tient dans une colonne de 132 px. */
body.ds-page .ds-cde-detail--panier .ds-cde-detail__qte .ds-qte { display: inline-flex; }
body.ds-page .ds-cde-detail__actions--pied { justify-content: flex-end; margin-top: 16px; }
body.ds-page .ds-cde-detail__actions--pied .ds-btn { width: auto; }
/* Le refus d'un devis est une action destructrice : elle reste un bouton
   secondaire, mais en rouge d'erreur. */
body.ds-page .ds-btn--destructif { color: var(--ds-err-fg); border-color: var(--ds-err-bd, var(--ds-err-fg)); }
body.ds-page .ds-btn--destructif:hover,
body.ds-page .ds-btn--destructif:focus-visible { background: var(--ds-err-bg); color: var(--ds-err-fg); }

@media (max-width: 767.98px) {
    body.ds-page .ds-cde-detail--panier .ds-cde-detail__lignes-entete,
    body.ds-page .ds-cde-detail--panier .ds-cde-detail__ligne { grid-template-columns: 44px minmax(0, 1fr); }
    body.ds-page .ds-cde-detail__ligne-action { grid-column: 2 / -1; justify-content: flex-start; }
    body.ds-page .ds-cde-detail__actions--pied { justify-content: stretch; }
    body.ds-page .ds-cde-detail__actions--pied .ds-btn { width: 100%; }
}

body.ds-page .ds-cde-detail__actions { display: flex; flex-wrap: wrap; gap: 10px; }
body.ds-page .ds-cde-detail__actions .ds-btn { width: 100%; justify-content: center; }
body.ds-page .ds-cde-detail__actions--haut { justify-content: flex-end; margin-bottom: 16px; }
body.ds-page .ds-cde-detail__actions--haut .ds-btn { width: auto; }

@media (max-width: 991.98px) {
    body.ds-page .ds-cde-detail__grille { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 767.98px) {
    /* Mobile : chaque ligne devient une carte, avec le libellé de colonne en
       regard de la valeur (l'en-tête de grille disparaît). */
    body.ds-page .ds-cde-detail__lignes { border: 0; background: none; border-radius: 0; }
    body.ds-page .ds-cde-detail__lignes-entete { display: none; }
    body.ds-page .ds-cde-detail__ligne {
        grid-template-columns: 44px minmax(0, 1fr);
        background: #fff;
        border: 1px solid var(--ds-grey-15);
        border-radius: var(--ds-radius-lg, 12px);
        padding: 14px;
        margin-bottom: 12px;
    }
    body.ds-page .ds-cde-detail__prix,
    body.ds-page .ds-cde-detail__qte,
    body.ds-page .ds-cde-detail__total {
        grid-column: 2 / -1;
        display: flex;
        justify-content: space-between;
        gap: 12px;
        text-align: left;
    }
    body.ds-page .ds-cde-detail__libelle-mobile { display: inline; font-size: 13px; color: var(--ds-grey-60); }
}

/* D4-3 / D4-4 : barre de filtres de « Mes documents » (le formulaire Symfony
   est rendu champ pour champ dans .ds-compte-filtres). */
body.ds-page .ds-compte-filtres .ds-champ { min-width: 180px; flex: 1 1 180px; }
body.ds-page .ds-compte-filtres .ds-champ--large { flex-basis: 100%; }
body.ds-page .ds-compte-filtres__types { display: flex; flex-wrap: wrap; gap: 8px 20px; }
body.ds-page .ds-compte-filtres__types .form-check,
body.ds-page .ds-compte-filtres__types .custom-control { margin: 0; }
body.ds-page .ds-compte-filtres__actions { display: flex; gap: 10px; align-items: flex-end; }
body.ds-page .ds-tableau-actions__indispo { font-size: 13px; color: var(--ds-grey-60); }

/* D4-4 : « Supprimer mon compte ». La carte porte un filet d'alerte discret,
   pas un fond rouge : l'écran informe, il ne crie pas. Le bouton destructif
   reste le seul bouton coloré, en dessous du texte légal, jamais en tête. */
body.ds-page .ds-compte-carte--danger { border-color: var(--ds-err-bd); }
body.ds-page .ds-compte-carte__texte { margin: 0 0 20px; font-size: 15px; line-height: 1.6; color: var(--ds-grey-60); }
body.ds-page .ds-compte-carte__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 0; }
body.ds-page .ds-champ--code { max-width: 220px; margin-bottom: 20px; }

/* D4-5 et D7-5 : formulaires du compte. Le thème de formulaire Symfony
   (bootstrap_4) rend chaque champ dans un .form-group : c'est donc lui qui est
   la cellule de la grille deux colonnes, pas un conteneur ajouté à la main. */
body.ds-page .ds-form-grille > .form-group { margin-bottom: 0; }
body.ds-page .ds-compte-carte--etroite { max-width: 560px; }
body.ds-page .ds-form-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-top: 24px;
}
body.ds-page .ds-form-actions .form-group { margin: 0; }
body.ds-page .ds-form-actions .ds-btn { margin: 0; }
body.ds-page .ds-compte-section-head { margin-bottom: var(--ds-rythme-bloc); }
body.ds-page .ds-compte-section-head .ds-compte-carte__titre { font-size: 20px; font-weight: 600; }

/* Périmètres d'un collaborateur : l'ancien tableau à trois colonnes devient une
   liste de règles, une par module. Sous 768 px, tout passe en colonne. */
body.ds-page .ds-droits-liste { display: flex; flex-direction: column; }
body.ds-page .ds-droits-ligne {
    display: grid;
    grid-template-columns: 180px minmax(0, 1fr) minmax(0, 1fr);
    gap: 12px 20px;
    align-items: start;
    padding: 14px 0;
    border-top: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-droits-ligne:first-child { border-top: 0; padding-top: 0; }
body.ds-page .ds-droits-ligne__nom { font-size: 15px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-droits-ligne__aide { font-size: 13px; color: var(--ds-grey-60); line-height: 1.5; }
body.ds-page .ds-droits-ligne__champ .form-group { margin: 0; }
body.ds-page .ds-droits-ligne__champ--large { grid-column: 2 / -1; }
body.ds-page .ds-droits-case { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 500; color: var(--ds-grey-95); margin: 0; cursor: pointer; }
body.ds-page .ds-arbre-clients { list-style: none; padding-left: 0; margin: 0; }
body.ds-page .ds-arbre-clients ul { list-style: none; padding-left: 22px; margin: 6px 0 0; }
body.ds-page .ds-arbre-clients li { margin-bottom: 6px; }
body.ds-page .ds-apps-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; }
body.ds-page .ds-apps-groupe__entete { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
body.ds-page .ds-apps-groupe__entete .application-externe-img { width: 32px; height: 32px; border-radius: var(--ds-radius-sm, 6px); object-fit: contain; }
body.ds-page .ds-apps-groupe__nom { font-weight: 600; }
body.ds-page .ds-apps-groupe__desc { color: var(--ds-grey-60); }

@media (max-width: 767.98px) {
    body.ds-page .ds-droits-ligne { grid-template-columns: minmax(0, 1fr); }
    body.ds-page .ds-droits-ligne__champ--large { grid-column: auto; }
    body.ds-page .ds-form-actions { flex-direction: column; align-items: stretch; }
    body.ds-page .ds-form-actions .ds-btn { width: 100%; justify-content: center; }
}

/* D7-6 : « Mes rattachements ». Le choix du client par défaut est un bouton
   radio construit côté service : coché, son libellé devient la pastille d'état
   de la ligne ; décoché, il reste un choix discret et cliquable. La cible
   tactile couvre toute la pastille (au moins 24 px de haut, WCAG 2.5.8). */
body.ds-page .ds-tableau--rattachements td:first-child { white-space: nowrap; }
/* Ligne a 44 px : le gabarit Bootstrap du bouton radio reserve 1,5 rem a
   gauche du libelle et impose une hauteur minimale ; les deux sont neutralises
   ici, la pastille porte elle-meme sa gouttiere et son reperage. */
body.ds-page .ds-tableau--rattachements tbody td { padding-top: 8px; padding-bottom: 8px; }
/* Ligne du systeme a 44 px. C'est un plancher, pas un plafond : quand une
   raison sociale passe a la ligne (le mode defilant de DataTables resserre les
   colonnes), la ligne grandit au lieu de couper le texte. */
body.ds-page .ds-tableau--rattachements tbody tr { height: 44px; }
/* Le conteneur Bootstrap du bouton radio porte .d-inline-block, donc un
   display en !important : on ne le combat pas, on annule la hauteur de la
   ligne de texte qui l'accueille. La pastille, elle, tient sa propre hauteur. */
body.ds-page .ds-tableau--rattachements tbody td:first-child { line-height: 0; }
body.ds-page .ds-tableau--rattachements .custom-control {
    padding-left: 0;
    min-height: 0;
    margin: 0;
    line-height: 1;
    vertical-align: middle;
}
body.ds-page .ds-tableau--rattachements .custom-control-label::before,
body.ds-page .ds-tableau--rattachements .custom-control-label::after {
    left: 7px;
    top: 50%;
    transform: translateY(-50%);
    width: 12px;
    height: 12px;
}
body.ds-page .ds-tableau--rattachements .custom-control-label {
    display: inline-flex;
    align-items: center;
    min-height: 26px;
    padding: 2px 10px 2px 26px;
    border-radius: var(--ds-radius-pill, 999px);
    border: 1px solid var(--ds-grey-25);
    font-size: 13px;
    color: var(--ds-grey-60);
    cursor: pointer;
}
body.ds-page .ds-tableau--rattachements .userinfos-client-defaut:checked ~ .custom-control-label {
    background: var(--ds-accent-light);
    border-color: var(--ds-accent);
    color: var(--ds-accent-texte, var(--ds-accent));
    font-weight: 600;
}
body.ds-page .ds-tableau--rattachements .userinfos-client-defaut:focus-visible ~ .custom-control-label {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 2px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   Écrans de demandes (lot D8, 2026-09-17, dette D6-5)

   « Nouvelle demande » et « Détail d'une demande » passaient encore par le cadre
   historique et, pour le fil de discussion, par des styles écrits en ligne dans
   le gabarit. Tout est ici, scopé à body.ds-page comme le reste du système.
   ───────────────────────────────────────────────────────────────────────────── */

/* Choix du type de demande : les boutons radio du FormType restent ceux de
   Symfony, seule leur mise en ligne change. */
body.ds-page .ds-demande-choix__options {
    display: flex;
    flex-wrap: wrap;
    gap: 24px;
    margin-top: 8px;
}
/* Mesure au navigateur : la règle générale du système pose déjà .form-check en
   ligne (repère puis libellé), mais avec flex-wrap: wrap. Imbriquée dans un
   second conteneur flexible, la case se retrouvait AU-DESSUS de son libellé,
   parce que la largeur de l'option se calait sur le seul libellé. Le seul
   correctif nécessaire est donc d'interdire le retour à la ligne à l'intérieur
   d'une option ; tout le reste (taille du repère, gouttière) reste celui du
   système. Cible d'au moins 24 px de haut (WCAG 2.2, critère 2.5.8). */
body.ds-page .ds-demande-choix__options .form-check,
body.ds-page .ds-demande-choix__options .custom-control {
    flex-wrap: nowrap;
    align-items: center;
    margin: 0;
    min-height: 24px;
}
body.ds-page .ds-demande-choix__options .form-check-label {
    margin: 0;
    font-size: 15px;
    font-weight: 400;
    color: var(--ds-grey-95);
    cursor: pointer;
}

/* Pièce jointe : le champ natif est retiré de l'affichage mais reste dans le
   flux du formulaire et accessible au clavier par son libellé (for/id), jamais
   masqué par display:none qui le sortirait de l'ordre de tabulation. */
body.ds-page .ds-demande-pj {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}
body.ds-page .ds-demande-pj__bouton { margin: 0; cursor: pointer; }
body.ds-page .ds-demande-pj__nom { font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-demande-pj input[type="file"]:focus-visible + .ds-demande-pj__nom,
body.ds-page .ds-demande-pj input[type="file"]:focus-visible ~ .ds-demande-pj__bouton,
body.ds-page .ds-demande-pj input[type="file"]:focus-visible {
    outline: var(--ds-focus-ring-width, 2px) solid var(--ds-focus-ring-color);
    outline-offset: 2px;
}

/* En-tête de la demande : sujet, actions à droite, badges et repères en dessous. */
body.ds-page .ds-demande-entete__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
body.ds-page .ds-demande-entete__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-demande-entete__date { margin-left: auto; font-variant-numeric: tabular-nums; }

/* Deux colonnes : le fil des échanges, puis l'historique. */
body.ds-page .ds-demande-grille {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
    margin-top: 20px;
}

/* Fil des échanges. Les bulles sont neutres : le message de l'utilisateur est
   sur fond d'accent clair avec un texte de contraste, celui du back-office sur
   gris clair. Aucune couleur n'est écrite en dur. */
body.ds-page .ds-demande-fil {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
body.ds-page .ds-demande-msg {
    max-width: 80%;
    padding: 12px 16px;
    border: 1px solid var(--ds-grey-15, #e6e6e8);
    border-radius: var(--ds-radius-md, 10px);
}
body.ds-page .ds-demande-msg--moi {
    align-self: flex-end;
    background: var(--ds-accent-light);
    border-color: var(--ds-accent-light);
}
body.ds-page .ds-demande-msg--eux {
    align-self: flex-start;
    background: var(--ds-grey-05);
}
body.ds-page .ds-demande-msg__auteur {
    margin: 0 0 6px;
    font-size: 12px;
    color: var(--ds-grey-60);
}
/* Le texte du message est saisi par un humain dans une zone de texte : les
   retours à la ligne comptent, et un mot très long ne doit pas élargir la page. */
body.ds-page .ds-demande-msg__texte {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: 15px;
    line-height: 1.55;
    color: var(--ds-grey-95);
}
body.ds-page .ds-demande-msg__pj {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 8px;
    font-size: 13px;
}

body.ds-page .ds-demande-reponse { margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--ds-grey-15, #e6e6e8); }
body.ds-page .ds-demande-reponse .ds-champ { margin-bottom: 14px; }
body.ds-page .ds-demande-reponse textarea { resize: vertical; }

/* Historique : une liste ordonnée, pas une frise décorative. */
body.ds-page .ds-demande-histo {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 16px;
}
body.ds-page .ds-demande-histo__item {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-left: 18px;
    font-size: 13px;
    color: var(--ds-grey-95);
}
body.ds-page .ds-demande-histo__item::before {
    content: "";
    position: absolute;
    left: 0;
    top: 6px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ds-accent);
}
body.ds-page .ds-demande-histo__date,
body.ds-page .ds-demande-histo__auteur { color: var(--ds-grey-60); }
body.ds-page .ds-demande-histo__date { font-variant-numeric: tabular-nums; }

body.ds-page .ds-demande-partages__titre { margin: 18px 0 8px; font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-demande-partages { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; font-size: 14px; }

/* Modale de partage : le bandeau en dégradé du thème historique est remplacé par
   un en-tête sobre. Le comportement reste celui de Bootstrap, non touché. */
body.ds-page .ds-modal .modal-content { border: 0; border-radius: var(--ds-radius-lg, 12px); box-shadow: var(--ds-shadow-2); }
body.ds-page .ds-modal .modal-header { align-items: center; border-bottom: 1px solid var(--ds-grey-15, #e6e6e8); }
body.ds-page .ds-modal .modal-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--ds-grey-95); }
body.ds-page .ds-modal .modal-footer { border-top: 1px solid var(--ds-grey-15, #e6e6e8); gap: 8px; }
body.ds-page .ds-modal .modal-footer > .ds-btn { margin: 0; }

@media (max-width: 900px) {
    body.ds-page .ds-demande-grille { grid-template-columns: minmax(0, 1fr); }
    body.ds-page .ds-demande-msg { max-width: 100%; }
    body.ds-page .ds-demande-entete__date { margin-left: 0; }
    body.ds-page .ds-demande-entete__actions { width: 100%; }
    body.ds-page .ds-demande-entete__actions .ds-btn { flex: 1 1 auto; justify-content: center; }
}

/* ==========================================================================
   Lot F3 (2026-09-17) : deuxieme serie de retours de Martin
   --------------------------------------------------------------------------
   Retour 2  : l'icone des etats vides n'etait pas centree.
   Retours 3 a 7 : « problemes d'espaces » et « faut revoir comment
                l'organiser » sur toutes les listes DataTables du compte.
   Retours 8 et 9 : catalogue en mode liste.
   Retour 10 : selecteur natif a la place de bootstrap-select.
   Retour 11 : respiration sous le header, y compris apres defilement.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Retour 2 : icone d'etat vide centree, 40 px, gris --ds-grey-40.
   La regle de base posait width:40px avec un cadre ; la surcharge ds-page la
   passait en display:block, ce qui laissait un bloc de 40 px cale a GAUCHE
   (un bloc ne se centre pas avec text-align du parent, seul son contenu le
   fait). D'ou l'icone decalee vue par Martin. On centre le bloc lui-meme.
   -------------------------------------------------------------------------- */
.ds-empty-state__icon,
body.ds-page .ds-empty-state__icon {
    display: block;
    width: 40px;
    height: 40px;
    margin: 0 auto 16px;
    border: 0;
    line-height: 40px;
    font-size: 40px;
    text-align: center;
    color: var(--ds-grey-40);
}

/* --------------------------------------------------------------------------
   Retours 3 a 7 : rendu du systeme impose a DataTables
   --------------------------------------------------------------------------
   La disposition (barre d'outils sur une ligne, pied a deux zones) vient de
   l'option dom posee par ds-tableaux.js ; ces regles l'habillent. Les noms de
   classe sont ceux de DataTables 2.x releves dans le DOM rendu.
   -------------------------------------------------------------------------- */

/* Barre d'outils : recherche a gauche, nombre par page puis export a droite. */
body.ds-page .ds-tableau .ds-dt-barre {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 12px 14px;
    border-bottom: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-tableau .ds-dt-barre__g { flex: 1 1 200px; min-width: 0; }
body.ds-page .ds-tableau .ds-dt-barre__d {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* Champ de recherche du systeme, loupe fine en prefixe, aucun libelle
   « Filtrer : » (la langue de DataTables est videe cote JS). */
body.ds-page .ds-tableau .dt-search { position: relative; display: block; margin: 0; }
body.ds-page .ds-tableau .dt-search::before {
    content: "\f002";
    font-family: "Font Awesome 6 Free", "Font Awesome 5 Free", FontAwesome;
    font-weight: 400;
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--ds-grey-40);
    font-size: 13px;
    pointer-events: none;
}
body.ds-page .ds-tableau .dt-search input,
body.ds-page .ds-tableau .dt-search input[type="search"] {
    width: 100%;
    max-width: 320px;
    height: 40px;
    margin: 0;
    padding: 0 12px 0 34px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    font-size: 14px;
}
body.ds-page .ds-tableau .dt-search label { margin: 0; display: block; }

/* Selecteur du nombre par page : plus de libelle « Nbr par page », le mot
   « Afficher » precede la liste (cle de traduction compte.tableauafficher). */
body.ds-page .ds-tableau .dt-length {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: 13px;
    color: var(--ds-grey-60);
}
body.ds-page .ds-tableau .dt-length label { margin: 0; display: flex; align-items: center; gap: 8px; }
body.ds-page .ds-tableau .dt-length select {
    height: 40px;
    margin: 0;
    padding: 0 28px 0 10px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23767676' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 10px center/10px 7px;
    -webkit-appearance: none;
    appearance: none;
    font-size: 14px;
    color: var(--ds-grey-95);
}

/* Menu « Exporter » discret : un seul bouton, Excel, CSV et PDF dedans. */
body.ds-page .ds-tableau .dt-buttons { margin: 0; display: flex; }
body.ds-page .ds-tableau .dt-buttons .btn,
body.ds-page .ds-tableau .dt-buttons .dt-button {
    height: 40px;
    padding: 0 14px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    color: var(--ds-grey-60);
    font-size: 14px;
    font-weight: 500;
}
body.ds-page .dt-button-collection {
    padding: 6px;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-md, 8px);
    background: #fff;
    box-shadow: var(--ds-shadow-2);
    min-width: 180px;
    z-index: 1200;
}
body.ds-page .dt-button-collection .btn,
body.ds-page .dt-button-collection .dt-button {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    height: 40px;
    padding: 0 10px;
    border: 0;
    border-radius: var(--ds-radius-control);
    background: transparent;
    color: var(--ds-grey-95);
    font-size: 14px;
    text-align: left;
}
body.ds-page .dt-button-collection .btn:hover,
body.ds-page .dt-button-collection .dt-button:hover { background: var(--ds-grey-05); }

/* Tableau : largeur bornee, en-tete en capitales espacees.

   Lot F6 (2026-09-18), retour 1 de Martin : en `table-layout: fixed`, le
   navigateur ignore le contenu et distribue la place restante A PARTS EGALES
   entre les colonnes sans largeur declaree. Sur « Mes commandes », huit colonnes
   de donnees dans 858 px laissaient 97 px par colonne, alors qu'une date en
   demande 107 et un montant 98 : TOUTES les cellules sortaient coupees, a
   toutes les largeurs de fenetre, pas seulement en dessous de 1024.

   On revient donc a la repartition par le contenu (`auto`), qui donne aux
   colonnes courtes et insecables (date, montant, reference, quantite) la
   largeur exacte dont elles ont besoin et laisse le reste aux colonnes de
   texte libre, qui passent a la ligne au lieu d'etre tronquees. */
body.ds-page .ds-tableau table.dataTable,
body.ds-page .ds-tableau > .table-responsive > table {
    table-layout: auto;
    width: 100%;
    margin: 0;
    border-collapse: collapse;
}
body.ds-page .ds-tableau table.dataTable > thead > tr > th {
    padding: 12px 10px;
    border-bottom: 1px solid var(--ds-grey-15);
    background: var(--ds-grey-05);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
    /* L'intitule de colonne passe a la ligne plutot que de se faire couper :
       « STATUT COMMANDE » sortait en « STATUT COM... ». */
    white-space: normal;
    line-height: 1.25;
}
body.ds-page .ds-tableau table.dataTable > tbody > tr > td {
    /* 10 px de marge laterale, la meme valeur que la regle de compaction posee
       plus bas sur .dt-container : a 12 px, la colonne des montants rendue
       insecable faisait deborder le tableau de 8 px a 1280 px. */
    padding: 8px 10px;
    height: 52px;
    border-bottom: 1px solid var(--ds-grey-10, var(--ds-grey-15));
    font-size: 14px;
    color: var(--ds-grey-95);
    vertical-align: middle;
    /* Plus d'ellipse par defaut : une donnee coupee est une donnee perdue. Le
       texte libre (raison sociale, libelle) passe a la ligne, les colonnes
       courtes restent sur une ligne par leurs classes ci-dessous. */
    white-space: normal;
    overflow-wrap: break-word;
}
/* Les valeurs vides affichent un tiret discret, jamais « Aucun ». Le tiret est
   decoratif : il n'entre ni dans le tri ni dans l'export. */
body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-dt-vide::after {
    content: "\2013";
    color: var(--ds-grey-40);
}
/* Reference, numero, date et montant : une seule ligne, jamais de cesure au
   milieu. Ce sont les donnees que Martin cite comme jamais tronquables. */
/* Specificite : la regle generique des cellules ci-dessus vaut (0,3,5) une fois
   ecrite « body.ds-page .ds-tableau table.dataTable > tbody > tr > td ». Ecrire
   ces exceptions en « .ds-tableau .ds-tableau__montant » (0,3,1) les rendait
   inertes dans les listes DataTables : « 8,60 € HT » repassait a la ligne sur le
   suffixe HT. Elles sont donc ecrites au meme niveau. */
body.ds-page .ds-tableau .ds-tableau__ref,
body.ds-page .ds-tableau .ds-tableau__num,
body.ds-page .ds-tableau .ds-tableau__date,
body.ds-page .ds-tableau .ds-tableau__montant,
body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-tableau__ref,
body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-tableau__num,
body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-tableau__date { white-space: nowrap; word-break: keep-all; hyphens: none; }
/* Le montant, lui, garde le droit de replier son suffixe « HT » sous le nombre :
   le rendre entierement insecable coutait 44 px de large et faisait deborder la
   liste a 768 px. Le nombre et son symbole, eux, ne se separent jamais : ils sont
   lies par une espace insecable dans les gabarits. */
/* Le texte libre prend la place qui reste et passe a la ligne. Sans cette
   largeur minimale, une colonne de raison sociale se reduit a un mot par
   ligne quand le tableau est serre. */
body.ds-page .ds-tableau .ds-tableau__client { min-width: 9em; }
/* Entre 768 et 1100 px, la colonne de contenu ne fait plus que ~720 px pour
   sept a huit colonnes : la somme des largeurs minimales depassait de 47 px et
   sortait une barre de defilement horizontale. On reprend cette place sur les
   marges interieures des cellules et sur la largeur minimale du texte libre,
   sans rien masquer ni tronquer. */
@media (max-width: 1100px) {
    body.ds-page .ds-tableau table.dataTable > thead > tr > th,
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td,
    body.ds-page .ds-tableau .dt-container table th,
    body.ds-page .ds-tableau .dt-container table td { padding-left: 4px; padding-right: 4px; }
    body.ds-page .ds-tableau thead th,
    body.ds-page .ds-tableau tbody td { padding-left: 6px; padding-right: 6px; }
    /* La colonne de texte libre rend sa largeur minimale a la colonne de statut,
       dont le badge doit tenir sur une seule ligne (« En cours de traitement »
       demande 172 px a lui seul). Elle passe seulement a la ligne plus tot. */
    body.ds-page .ds-tableau .ds-tableau__client { min-width: 5em; }
}
/* Les colonnes courtes ne reclament plus une part fixe du tableau.
   « width: 1% » est la forme usuelle en repartition automatique : le
   navigateur reduit la colonne a la largeur de son contenu et rend le reste
   aux colonnes de texte. */
body.ds-page .ds-tableau th.ds-col-ref,
body.ds-page .ds-tableau th.ds-col-statut,
body.ds-page .ds-tableau th.ds-col-actions { width: 1%; }
/* Montants en chiffres tabulaires, alignes a droite. */
body.ds-page .ds-tableau .ds-tableau__montant,
body.ds-page .ds-tableau th.ds-col-montant {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}
body.ds-page .ds-tableau .ds-tableau__montant small { color: var(--ds-grey-60); font-size: 12px; }
body.ds-page .ds-tableau .ds-tableau__date { font-variant-numeric: tabular-nums; }
/* Le badge de statut tient sur une seule ligne (retour 1 du lot F6 : « En cours
   de traitement » sortait sur deux lignes et epaississait la ligne). En
   repartition automatique, la colonne prend la largeur du badge au lieu de
   forcer le badge a se replier. */
body.ds-page .ds-tableau .ds-tableau__statut { overflow: visible; white-space: nowrap; }
body.ds-page .ds-tableau .ds-tableau__statut .ds-badge {
    white-space: nowrap;
    display: inline-block;
    max-width: 100%;
    line-height: 1.3;
    text-align: center;
}
/* Tri : fleche fine, visible seulement sur la colonne active. */
body.ds-page .ds-tableau table.dataTable > thead > tr > th.dt-orderable-asc,
body.ds-page .ds-tableau table.dataTable > thead > tr > th.dt-orderable-desc { cursor: pointer; }
body.ds-page .ds-tableau table.dataTable > thead > tr > th span.dt-column-order::before,
body.ds-page .ds-tableau table.dataTable > thead > tr > th span.dt-column-order::after { opacity: 0; }
body.ds-page .ds-tableau table.dataTable > thead > tr > th.dt-ordering-asc span.dt-column-order::before,
body.ds-page .ds-tableau table.dataTable > thead > tr > th.dt-ordering-desc span.dt-column-order::after {
    opacity: 1;
    color: var(--ds-accent-texte, var(--ds-accent));
    font-weight: 400;
}
body.ds-page .ds-tableau table.dataTable > thead > tr > th.dt-ordering-asc,
body.ds-page .ds-tableau table.dataTable > thead > tr > th.dt-ordering-desc { color: var(--ds-grey-95); }

/* Actions libellees (retour 7) : jamais une icone seule. */
/* Lot F6 (2026-09-18), retour 2 : avec flex-wrap: wrap et une colonne d'actions
   reduite a son contenu, la largeur minimale de la colonne devenait celle d'UNE
   action, et les cinq liens-icones s'empilaient verticalement (ligne de tableau
   de 220 px de haut, mesuree sur « Mes paniers »). Les actions restent sur une
   ligne a l'ecran ; sous 768 px, la regle du mode carte les remet en colonne
   pleine largeur. */
body.ds-page .ds-tableau .btn-tableau { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
/* Une ligne de « Mes paniers » peut porter cinq actions : a 6 px d'ecart, leur
   colonne reclamait 16 px de plus que la place disponible a 768 px. L'ecart se
   resserre sous 1100 px, la cible de chaque action reste entiere (32 px).
   Regle posee ICI et pas dans la requete media plus haut : a specificite egale,
   c'est la derniere regle du fichier qui gagne. */
@media (max-width: 1100px) {
    body.ds-page .ds-tableau .btn-tableau { gap: 2px; }
}
body.ds-page .ds-tableau .ds-tableau__actions { overflow: visible; white-space: normal; }
body.ds-page .ds-tableau .ds-tableau__action {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 32px;
    padding: 0 8px;
    border-radius: var(--ds-radius-control);
    color: var(--ds-accent-texte, var(--ds-accent));
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
}
body.ds-page .ds-tableau .ds-tableau__action:hover { background: var(--ds-accent-light); color: var(--ds-on-accent-light); }
body.ds-page .ds-tableau .ds-tableau__action--destructive { color: var(--ds-err-text, #b3261e); }
body.ds-page .ds-tableau .ds-tableau__action--destructive:hover { background: var(--ds-err-bg, #fdecea); color: var(--ds-err-text, #b3261e); }
body.ds-page .ds-tableau .ds-tableau__action i { font-size: 13px; }

/* Pied : « 1 a 10 sur 18 » a gauche en 13 px gris, pagination a droite. */
body.ds-page .ds-tableau .ds-dt-pied {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 12px 14px;
    border-top: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-tableau .ds-dt-pied .dt-info { font-size: 13px; color: var(--ds-grey-60); padding: 0; }
body.ds-page .ds-tableau .ds-dt-pied .dt-paging { padding: 0; }
body.ds-page .ds-tableau .ds-dt-pied .pagination { gap: 4px; margin: 0; }
body.ds-page .ds-tableau .ds-dt-pied .page-item { margin: 0; }
body.ds-page .ds-tableau .ds-dt-pied .page-link {
    min-width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff;
    color: var(--ds-grey-95);
    font-size: 14px;
}
body.ds-page .ds-tableau .ds-dt-pied .page-item.active .page-link {
    background: var(--ds-accent);
    border-color: var(--ds-accent);
    color: var(--ds-on-accent);
}
body.ds-page .ds-tableau .ds-dt-pied .page-item.disabled .page-link { color: var(--ds-grey-40); background: #fff; }

/* Actions de bas de liste (importer des pieces, vider les paniers). */
body.ds-page .ds-compte-actions-bas { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }

/* --------------------------------------------------------------------------
   Sous 768 px : chaque ligne devient une carte (retours 3 a 6)
   --------------------------------------------------------------------------
   Remplace le mode responsif natif de DataTables, qui masquait des colonnes et
   les rejouait dans une ligne fille aux libelles en gras. Les intitules sont
   poses en data-libelle par ds-tableaux.js, y compris sur les listes chargees
   en ajax, dont les lignes n'existent pas au rendu du gabarit.
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {

    body.ds-page .ds-tableau .ds-dt-barre,
    body.ds-page .ds-tableau .ds-dt-pied { flex-direction: column; align-items: stretch; }
    body.ds-page .ds-tableau .ds-dt-barre__g { flex: 0 0 auto; }
    body.ds-page .ds-tableau .ds-dt-barre__d { justify-content: space-between; }
    body.ds-page .ds-tableau .dt-search input { max-width: none; }

    body.ds-page .ds-tableau table.dataTable,
    body.ds-page .ds-tableau > .table-responsive > table { table-layout: auto; display: block; }
    body.ds-page .ds-tableau table.dataTable > thead { display: none; }
    body.ds-page .ds-tableau table.dataTable > tbody { display: block; }
    body.ds-page .ds-tableau table.dataTable > tbody > tr {
        display: block;
        margin: 12px;
        padding: 12px 14px;
        border: 1px solid var(--ds-grey-15);
        border-radius: var(--ds-radius-lg, 12px);
        background: #fff;
    }
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 12px;
        height: auto;
        min-height: 0;
        padding: 4px 0;
        border: 0;
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
        font-size: 15px;
    }
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td::before {
        content: attr(data-libelle);
        flex: 0 0 auto;
        color: var(--ds-grey-60);
        font-size: 12px;
        text-transform: uppercase;
        letter-spacing: 0.04em;
    }
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-tableau__actions {
        display: block;
        margin-top: 10px;
        padding-top: 10px;
        border-top: 1px solid var(--ds-grey-15);
    }
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-tableau__actions::before { content: none; }
    body.ds-page .ds-tableau .ds-tableau__actions .btn-tableau { flex-direction: column; align-items: stretch; gap: 8px; }
    body.ds-page .ds-tableau .ds-tableau__action {
        justify-content: center;
        min-height: 44px;
        border: 1px solid var(--ds-grey-15);
    }
    body.ds-page .ds-tableau .ds-tableau__action--principale {
        background: var(--ds-primary-bg);
        border-color: var(--ds-primary-bg);
        color: var(--ds-on-primary);
    }
    body.ds-page .ds-tableau .ds-tableau__montant { text-align: right; }

    /* Revue responsive du 31/10 : la zébrure native de DataTables (ombre interne sur les
       cellules des lignes impaires) grisait la moitié des cartes, la carte devient blanche. */
    body.ds-page .ds-tableau table.dataTable > tbody > tr > * { box-shadow: none !important; } /* !important : la zébrure Bootstrap/DataTables l'emporte sinon */
    /* Actions de ligne : des icônes nues empilées pleine largeur ne disent pas ce qu'elles
       font sur un écran tactile (pas de survol). L'intitulé déjà porté par l'infobulle
       (data-original-title) s'affiche à côté de l'icône. */
    /* Montant : valeur, symbole et mention HT/TTC sont plusieurs enfants ; en flex ils s'écartaient
       sur toute la ligne. Le montant redevient une ligne de texte alignée à droite. */
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-tableau__montant { display: block; text-align: right; }
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td.ds-tableau__montant::before { float: left; }
    /* Ligne « Aucune donnée » : pas d'intitulé de colonne devant, texte centré. */
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td.dt-empty { display: block; text-align: center; }
    body.ds-page .ds-tableau table.dataTable > tbody > tr > td.dt-empty::before { content: none; }
    /* Filtres bâtis en colonnes Bootstrap (devis, paniers) : trois champs de 73 px côte à côte
       tronquaient « Date de début » ; chaque champ prend la ligne. */
    body.ds-page .ds-compte-filtres > .row > [class*="col"] { flex: 0 0 100%; max-width: 100%; padding: 0; margin-bottom: 10px; }
    body.ds-page .ds-compte-filtres > .row > [class*="col"]:last-child { margin-bottom: 0; }
    body.ds-page .ds-tableau .ds-tableau__actions .btn-tableau > a,
    body.ds-page .ds-tableau .ds-tableau__actions .btn-tableau > form { width: 100%; }
    body.ds-page .ds-tableau .ds-tableau__actions .btn-tableau > a,
    body.ds-page .ds-tableau .ds-tableau__actions .btn-tableau > form > button {
        justify-content: flex-start;
        gap: 10px;
        min-height: 44px;
        padding: 0 12px;
        font-size: 14px;
    }
    body.ds-page .ds-tableau .ds-tableau__actions .btn-tableau > form > button {
        padding: 0 12px !important; /* bootstrap p-0 du gabarit */
        display: flex; align-items: center; width: 100%; border-radius: var(--ds-radius-control);
        color: var(--ds-accent-texte, var(--ds-accent)); text-decoration: none;
    }
    body.ds-page .ds-tableau .ds-tableau__actions .btn-tableau [data-original-title]::after {
        content: attr(data-original-title);
        font-family: var(--ds-font);
        font-size: 14px;
        font-weight: 600;
        line-height: 1.2;
        letter-spacing: 0;
        text-align: left;
    }
}

/* Retour 10 : selecteur natif du systeme, 44 px, chevron fin. Il remplace le
   bouton vert bootstrap-select, debranche sur les pages redessinees. */
body.ds-page .ds-compte-filtres select,
body.ds-page .ds-compte-filtres .ds-select {
    height: 44px;
    padding: 0 32px 0 12px;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-control, 8px);
    background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23767676' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 12px center/11px 8px;
    -webkit-appearance: none;
    appearance: none;
    font-size: 14px;
    color: var(--ds-grey-95);
    width: 100%;
}
body.ds-page .ds-compte-filtres input[type="text"],
body.ds-page .ds-compte-filtres input[type="search"],
body.ds-page .ds-compte-filtres input[type="date"] { height: 44px; }
/* La barre de filtres tient sur une ligne a 1440 : chaque champ prend sa part,
   les deux boutons restent au bout. */
body.ds-page .ds-compte-filtres { flex-wrap: wrap; }
body.ds-page .ds-compte-filtres .ds-champ { flex: 1 1 120px; min-width: 110px; }
body.ds-page .ds-compte-filtres__actions { display: flex; gap: 10px; align-items: flex-end; flex: 0 0 auto; }
/* Deux mesures, relevees au navigateur, qui desalignaient la liste « Langue »
   du reste de la barre :
   - le theme de formulaire Symfony pose .mb-3 sur le champ, et les utilitaires
     d'espacement de Bootstrap sont en !important : dans une barre alignee en
     bas, cette marge remontait le champ de 12 px. La barre porte deja son
     propre interligne, on la neutralise ici, au meme poids ;
   - la regle generale des formulaires du systeme impose min-height: 48px, qui
     l'emportait sur la hauteur de 44 px demandee. */
body.ds-page .ds-compte-filtres select.mb-3,
body.ds-page .ds-compte-filtres input.mb-3 { margin-bottom: 0 !important; }
body.ds-page .ds-compte-filtres select,
body.ds-page .ds-compte-filtres .ds-select,
body.ds-page .ds-compte-filtres input[type="text"],
body.ds-page .ds-compte-filtres input[type="search"],
body.ds-page .ds-compte-filtres input[type="date"] {
    box-sizing: border-box;
    min-height: 44px;
    height: 44px;
    font-size: 14px;
}
/* Reste d'un bootstrap-select monte avant le debranchement : jamais visible. */
body.ds-page .bootstrap-select { display: none !important; }

@media (max-width: 767.98px) {
    body.ds-page .ds-compte-filtres .ds-champ { flex: 1 1 100%; }
    body.ds-page .ds-compte-filtres__actions { width: 100%; }
    body.ds-page .ds-compte-filtres__actions .ds-btn,
    body.ds-page .ds-compte-filtres__actions .btn { flex: 1 1 auto; }
}

/* --------------------------------------------------------------------------
   Retours 8 et 9 : catalogue en mode liste
   -------------------------------------------------------------------------- */
body.ds-page .ds-product-grid--liste {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    background: #fff;
    overflow: hidden;
}
body.ds-page .ds-product-grid--liste .ds-carte {
    display: grid;
    grid-template-columns: 64px minmax(0, 1fr) auto;
    align-items: center;
    gap: 16px;
    border: 0;
    border-top: 1px solid var(--ds-grey-15);
    border-radius: 0;
    box-shadow: none;
    padding: 12px 16px;
}
body.ds-page .ds-product-grid--liste .ds-carte:first-child { border-top: 0; }
body.ds-page .ds-product-grid--liste .ds-carte:hover { transform: none; box-shadow: none; background: var(--ds-grey-05); }
body.ds-page .ds-product-grid--liste .ds-carte__media {
    width: 64px;
    height: 64px;
    aspect-ratio: 1 / 1;
    border-radius: var(--ds-radius-md, 8px);
    overflow: hidden;
    flex: 0 0 64px;
}
body.ds-page .ds-product-grid--liste .ds-carte__img { width: 64px; height: 64px; object-fit: contain; }
/* Le coeur de favori quitte le coin de la vignette pour la colonne d'actions :
   sur une ligne de 64 px il recouvrait l'image. */
body.ds-page .ds-product-grid--liste .ds-carte__favori {
    position: static;
    order: 3;
    grid-column: 3;
    width: 40px;
    height: 40px;
}
body.ds-page .ds-product-grid--liste .ds-carte__corps {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 8px 20px;
    grid-column: 2 / 4;
    padding: 0;
}
body.ds-page .ds-product-grid--liste .ds-carte__nom {
    grid-column: 1;
    grid-row: 1;
    font-size: 15px;
    font-weight: 600;
    -webkit-line-clamp: 2;
}
body.ds-page .ds-product-grid--liste .ds-carte__ref,
body.ds-page .ds-product-grid--liste .ds-carte__segment { grid-column: 1; grid-row: 2; font-size: 13px; }
body.ds-page .ds-product-grid--liste .ds-carte__prix-ligne {
    grid-column: 2;
    grid-row: 1 / 3;
    align-self: center;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
body.ds-page .ds-product-grid--liste .ds-carte__stock { grid-column: 3; grid-row: 1 / 3; align-self: center; justify-self: end; }
body.ds-page .ds-product-grid--liste .ds-carte__achat {
    grid-column: 1 / 4;
    grid-row: 3;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 4px;
}
body.ds-page .ds-product-grid--liste .ds-carte__achat .ds-carte__action { width: auto; min-width: 120px; }
body.ds-page .ds-product-grid--liste .ds-carte__decline,
body.ds-page .ds-product-grid--liste .ds-carte__action { grid-column: 1 / 4; justify-self: end; }

@media (min-width: 1100px) {
    body.ds-page .ds-product-grid--liste .ds-carte__corps {
        grid-template-columns: minmax(0, 1fr) auto auto auto;
    }
    body.ds-page .ds-product-grid--liste .ds-carte__achat {
        grid-column: 4;
        grid-row: 1 / 3;
        align-self: center;
        margin-top: 0;
    }
}

@media (max-width: 767.98px) {
    /* Le mode liste du catalogue redevient la grille de cartes du mode grille. */
    body.ds-page .ds-product-grid--liste {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
        border: 0;
        background: transparent;
        overflow: visible;
    }
    body.ds-page .ds-product-grid--liste .ds-carte {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: 0;
        border: 1px solid var(--ds-grey-15);
        border-radius: var(--ds-radius-lg, 12px);
        overflow: hidden;
    }
    body.ds-page .ds-product-grid--liste .ds-carte__media { width: auto; height: auto; flex: none; border-radius: 0; }
    body.ds-page .ds-product-grid--liste .ds-carte__img { width: 100%; height: auto; }
    body.ds-page .ds-product-grid--liste .ds-carte__favori { position: absolute; order: 0; }
    body.ds-page .ds-product-grid--liste .ds-carte__corps { display: flex; flex-direction: column; }
    body.ds-page .ds-product-grid--liste .ds-carte__achat { justify-content: stretch; margin-top: 8px; }
}

/* --------------------------------------------------------------------------
   Retour 11 : respiration sous le header, y compris apres defilement
   --------------------------------------------------------------------------
   Le header des pages redessinees est colle en haut : une ancre ou un retour
   de navigation pouvait amener le H1 juste dessous, donc recouvert. Le retrait
   de defilement le garantit (critere 2.4.11 de WCAG 2.2, « focus non masque »).
   -------------------------------------------------------------------------- */
body.ds-page .ds-compte-page { padding-top: 0; }
body.ds-page .ds-compte-inner { padding-top: 24px; }
body.ds-page .ds-ariane { margin: 0 0 8px; }
body.ds-page .ds-compte-h1 { margin-top: 0; margin-bottom: 24px; }


/* ══════════════════════════════════════════════════════════════════════════
   Passe signature (lot F4, 2026-09-17), SPEC-SIGNATURE.md partie 1
   ══════════════════════════════════════════════════════════════════════════
   Les etats, le non-nominal et l'accessibilite. Trois durees, deux courbes,
   aucune couleur en dur, aucun asset externe. Tout est scope a body.ds-page :
   une page non redessinee ne peut pas etre atteinte par ces regles.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── F7. Apparition du contenu principal, 180ms, opacite seule ───────────
   Pas de translation : elle deplacerait la cible du clic et couterait du
   decalage de mise en page. Le header, le fil d'Ariane et le pied de page ne
   sont pas animes, ils sont deja la quand le contenu arrive. */
@media (prefers-reduced-motion: no-preference) {
    body.ds-page main { animation: dsEntree var(--ds-dur-page) var(--ds-ease-out) backwards; }
    @keyframes dsEntree { from { opacity: 0; } to { opacity: 1; } }
}

/* ── F8. Header au defilement : une reduction de 12px, une ombre, 200ms ──
   .headerFixed est posee par scripts_global.js (sentinelle), rien a ecrire en
   JS. Le logo ne change pas de taille, seul le padding bouge. */
body.ds-page .ds-header-main { transition: padding var(--ds-dur-compo) var(--ds-ease-out); }
body.ds-page .ds-header.headerFixed .ds-header-main { --ds-header-pad-y: 10px; }
body.ds-page .ds-header { transition: box-shadow var(--ds-dur-compo) var(--ds-ease-out); }
/* #header porte « box-shadow: none » plus haut dans ce fichier (specificite
   d'identifiant) : l'ombre du header colle doit donc se poser sur le meme
   identifiant, sinon elle ne s'applique jamais. */
body.ds-page #header.ds-header.headerFixed { box-shadow: 0 1px 0 var(--ds-grey-15), var(--ds-shadow-1); }

/* ── F9. Cartes : une seule regle de survol, et l'appui qui manquait ─────
   1px de levee, jamais 2 ni 4. La bordure ne change ni d'epaisseur ni de
   couleur, le titre ne se souligne pas. Le retour a plat a l'appui est ce qui
   donne la sensation physique du clic. */
body.ds-page .ds-carte,
body.ds-page .ds-actu-carte,
body.ds-page .ds-univers-carte {
    transition: box-shadow var(--ds-dur-etat) var(--ds-ease-out),
                transform var(--ds-dur-etat) var(--ds-ease-out);
}
body.ds-page .ds-carte:active,
body.ds-page .ds-actu-carte:active,
body.ds-page .ds-univers-carte:active {
    transform: translateY(0);
    box-shadow: var(--ds-shadow-1);
}

/* ── F10. Bouton principal : six etats, largeur verrouillee au chargement ─ */
body.ds-page .ds-btn--primary:active { filter: brightness(0.90); transform: translateY(1px); }
body.ds-page .ds-btn--primary:focus-visible {
    filter: none;
    outline: 2px solid var(--ds-accent);
    outline-offset: 2px;
    box-shadow: 0 0 0 4px #fff inset;
}
body.ds-page .ds-btn.ds-btn--chargement {
    pointer-events: none;
    cursor: default;
}
body.ds-page .ds-btn.ds-btn--chargement > * { opacity: 0.6; }

/* ── F11. Ajout au panier : la confirmation se joue dans le bouton ───────
   La largeur et la hauteur sont verrouillees en ligne par ds-signature.js au
   moment du clic ; ici, seulement le fondu croise du libelle. */
body.ds-page .ds-btn__libelle,
body.ds-page .ds-btn__confirmation {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    transition: opacity var(--ds-dur-etat) var(--ds-ease-out);
}
body.ds-page .ds-btn__confirmation { display: none; }
body.ds-page .ds-btn--confirme .ds-btn__libelle { display: none; }
body.ds-page .ds-btn--confirme .ds-btn__confirmation { display: inline-flex; }
body.ds-page .ds-btn__coche { flex: none; width: 16px; height: 16px; }

/* ── F12. Favori : le coeur se remplit, 1,15 puis 1, en 200ms ────────────
   Le retrait ne rejoue pas l'animation : il vide le remplissage en 150ms.
   L'asymetrie est voulue, on marque l'engagement, pas l'abandon. */
body.ds-page .ds-carte__favori .ds-icone,
body.ds-page .ds-fiche__favori .ds-icone {
    transition: fill var(--ds-dur-etat) var(--ds-ease-out), transform 200ms var(--ds-ease-out);
}
@media (prefers-reduced-motion: no-preference) {
    body.ds-page .ds-carte__favori[aria-pressed="true"] .ds-icone,
    body.ds-page .ds-fiche__favori[aria-pressed="true"] .ds-icone { animation: dsCoeur 200ms var(--ds-ease-out); }
    @keyframes dsCoeur {
        0% { transform: scale(1); }
        45% { transform: scale(1.15); }
        100% { transform: scale(1); }
    }
}

/* ── F14. Galerie : fondu 150ms au changement, zoom 1,03 en 400ms ────────
   Le cadre est verrouille en 1:1, l'image ne se deplace pas : c'est le fondu
   qui evite le flash blanc entre deux images. La vignette active garde son
   lisere par une ombre interne, qui ne decale pas la vignette d'un pixel. */
body.ds-page .ds-fiche__visuel { overflow: hidden; }
body.ds-page .ds-fiche__image {
    transition: opacity var(--ds-dur-etat) var(--ds-ease-out),
                transform var(--ds-dur-media) var(--ds-ease-out);
}
body.ds-page .ds-fiche__image--transition { opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
    body.ds-page .ds-fiche__visuel:hover .ds-fiche__image { transform: scale(1.03); }
}
body.ds-page .ds-fiche__vignette--active {
    border: 1px solid var(--ds-grey-15);
    padding: 2px;
    box-shadow: inset 0 0 0 2px var(--ds-accent);
}

/* ── F15. Tunnel : la ligne d'etapes se remplit ──────────────────────────
   Le trait entre deux pastilles fait 2px et passe a l'accent par un
   remplissage de la gauche vers la droite en 400ms, au chargement de l'etape.
   --p est enregistree comme propriete de type pourcentage : sans cela, un
   degrade ne peut pas etre transitionne. */
@property --p {
    syntax: "<percentage>";
    inherits: false;
    initial-value: 0%;
}
body.ds-page .ds-etapes-tunnel__item + .ds-etapes-tunnel__item::before {
    --p: 0%;
    width: 40px;
    height: 2px;
    background: linear-gradient(to right, var(--ds-accent) 0 var(--p), var(--ds-grey-15) var(--p) 100%);
    transition: --p var(--ds-dur-media) var(--ds-ease-inout);
}
body.ds-page .ds-etapes-tunnel--remplie .ds-etapes-tunnel__item--actif::before,
body.ds-page .ds-etapes-tunnel--remplie .ds-etapes-tunnel__item--faite::before { --p: 100%; }
body.ds-page .ds-etapes-tunnel__puce { width: 28px; height: 28px; background: #fff; }
body.ds-page .ds-etapes-tunnel__item--faite .ds-etapes-tunnel__puce {
    background: var(--ds-accent);
    border-color: var(--ds-accent);
    color: var(--ds-on-accent);
    font-size: 0;
}
body.ds-page .ds-etapes-tunnel__item--faite .ds-etapes-tunnel__puce::before {
    content: "";
    width: 12px;
    height: 7px;
    border-left: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translateY(-1px) rotate(-45deg);
}
body.ds-page .ds-etapes-tunnel__item--actif .ds-etapes-tunnel__puce {
    background: #fff;
    border: 2px solid var(--ds-accent);
    color: var(--ds-accent-texte, var(--ds-accent));
}
body.ds-page .ds-etapes-tunnel__item:not(.ds-etapes-tunnel__item--actif):not(.ds-etapes-tunnel__item--faite) .ds-etapes-tunnel__puce {
    border-color: var(--ds-grey-25);
    color: var(--ds-grey-60);
}

/* ── F16. Squelette de carte, aux dimensions exactes de .ds-carte ────────
   Il n'apparait qu'au-dela de 300ms d'attente (ds-signature.js) : en dessous,
   il ferait clignoter la page pour rien. Sous reduction d'animation, le fond
   reste, il ne defile plus. */
body.ds-page .ds-skeleton-carte {
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--ds-grey-15);
    border-radius: var(--ds-radius-lg, 12px);
    overflow: hidden;
}
body.ds-page .ds-skeleton-carte__media { aspect-ratio: 1 / 1; background: var(--ds-grey-05); }
body.ds-page .ds-skeleton-carte__corps { display: flex; flex-direction: column; gap: 8px; padding: 12px; }
body.ds-page .ds-skeleton-carte .ds-skeleton-line--titre { height: 14px; width: 100%; }
body.ds-page .ds-skeleton-carte .ds-skeleton-line--titre-2 { height: 14px; width: 70%; }
body.ds-page .ds-skeleton-carte .ds-skeleton-line--ref { height: 12px; width: 40%; }
body.ds-page .ds-skeleton-carte .ds-skeleton-line--prix { height: 20px; width: 35%; }

/* ── F17. Etat vide : une phrase utile, une action, jamais un cul-de-sac ─ */
body.ds-page .ds-empty-state__icon {
    display: inline-flex;
    width: 20px;
    height: 20px;
    border: 0;
    margin-bottom: 16px;
    color: var(--ds-grey-40);
    font-size: 20px;
    line-height: 1;
}
body.ds-page .ds-empty-state__text { max-width: 46ch; margin-left: auto; margin-right: auto; text-wrap: pretty; }
body.ds-page .ds-empty-state__aide {
    margin: -8px auto 20px;
    max-width: 46ch;
    font-size: 14px;
    color: var(--ds-grey-60);
}

/* ── F18. Focus visible, lisible sur fond blanc comme sur l'accent ───────
   Une seule definition. Sur les surfaces qui portent deja l'accent en fond,
   un lisere blanc interne garde l'anneau lisible. */
body.ds-page :where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--ds-accent);
    outline-offset: 2px;
    border-radius: inherit;
}
/* Les composants qui posaient deja leur propre anneau (boutons, champs, liens
   du header, vignettes) pesent plus lourd que la regle chapeau ci-dessus :
   l'anneau unique doit donc etre repose a leur niveau, sinon il reste bleu
   marine sur un site dont l'accent est vert ou rouge. */
body.ds-page .ds-btn:focus-visible,
body.ds-page .ds-field input:focus-visible,
body.ds-page .ds-champ input:focus-visible,
body.ds-page .ds-header :focus-visible,
body.ds-page .ds-header-drawer :focus-visible,
body.ds-page .ds-fiche__vignette:focus-visible,
body.ds-page .ds-tableau a:focus-visible,
body.ds-page .ds-footer a:focus-visible {
    outline: 2px solid var(--ds-accent);
    outline-offset: 2px;
}
body.ds-page .ds-header-panier__count:focus-visible,
body.ds-page .ds-btn--primary:focus-visible,
body.ds-page .ds-etapes-tunnel__item--actif:focus-visible { box-shadow: 0 0 0 2px #fff; }

/* ── F19. Toute cible cliquable fait 44px ───────────────────────────────
   Loi de Fitts et WCAG 2.2 (2.5.8). Les liens de tableau, de pied de page et
   de fil d'Ariane en font partie ; 8px separent deux liens empiles. */
body.ds-page .ds-tableau__action,
body.ds-page .ds-tableau .btn-tableau > a,
body.ds-page .ds-footer__liens a,
body.ds-page .ds-footer__contact a,
body.ds-page .ds-fil-ariane a,
body.ds-page .ds-actu-carte__lien {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}
body.ds-page .ds-footer__liens li + li { margin-top: 0; }
body.ds-page .ds-footer__liens li { display: flex; }

/* ── F20. Pied de page : quatre colonnes, une ligne legale, rien de plus ─ */
body.ds-page .ds-footer { border-top: 1px solid var(--ds-grey-15); margin-top: var(--ds-rythme-chapitre); }
body.ds-page .ds-footer__titre {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ds-grey-60);
}
body.ds-page .ds-footer__liens a,
body.ds-page .ds-footer__contact a { font-size: 15px; color: var(--ds-grey-95); text-decoration: none; }
body.ds-page .ds-footer__liens a:hover,
body.ds-page .ds-footer__contact a:hover { color: var(--ds-accent-texte, var(--ds-accent)); text-decoration: none; }
body.ds-page .ds-footer__mention { font-size: 13px; color: var(--ds-grey-60); }

/* ── F21. Connexion : une colonne de 400px, rien autour ─────────────────
   C'est le seul ecran ou l'utilisateur n'a rien a decider : tout ce qui
   s'ajoute le ralentit. */
/* Lot R2-design (D1) : cette règle (même spécificité que --large/--moyen, placée plus bas) écrasait la largeur des
   carte d'inscription professionnelle (400px au lieu de 1040px). Elle ne vise plus que les cartes autres que --large :
   /login et /register-public (B2C) restent à 400px comme avant. */
body.ds-page .ds-auth-carte:not(.ds-auth-carte--large) { max-width: 400px; }
body.ds-page .ds-auth-marque img { max-height: 44px; width: auto; }
body.ds-page .ds-auth-marque { margin-bottom: 32px; }
body.ds-page .ds-auth-titre { font-size: 24px; line-height: 1.25; letter-spacing: -0.014em; }
body.ds-page .ds-code-cases .ds-code-case,
body.ds-page .ds-code-case {
    width: 48px;
    height: 56px;
    font-size: 24px;
    font-variant-numeric: tabular-nums;
}

/* ── F22. Respect global de la reduction d'animation ─────────────────────
   La regle precedente ne couvrait que les cartes, sur une feuille qui anime
   le tiroir, le zoom d'image, le coeur et la ligne d'etapes. Les changements
   de couleur restent instantanes mais visibles : aucun etat ne disparait. */
@media (prefers-reduced-motion: reduce) {
    body.ds-page *,
    body.ds-page *::before,
    body.ds-page *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    body.ds-page .ds-skeleton-line { animation: none !important; background: var(--ds-grey-05); }
}

/* ── F25. Mini-panier : tiroir sobre, 250ms, voile en fondu de 200ms ─────
   Le focus entre dans le tiroir, y reste, et revient au declencheur a la
   fermeture (ds-mini-panier.js). Un tiroir dont on ne sort pas au clavier est
   un piege, c'est le defaut le plus frequent des tiroirs ajoutes apres coup. */
body.ds-page .ds-drawer-panier__overlay {
    background: rgba(16, 16, 20, 0.24);
    transition: opacity var(--ds-dur-compo) var(--ds-ease-out);
}
body.ds-page .ds-drawer-panier__panneau {
    width: min(400px, 100vw);
    border-radius: 12px 0 0 12px;
    opacity: 0;
    transform: translateX(16px);
    transition: transform 250ms var(--ds-ease-out), opacity 250ms var(--ds-ease-out);
}
body.ds-page .ds-drawer-panier--ouvert .ds-drawer-panier__panneau { opacity: 1; transform: translateX(0); }
@media (max-width: 767.98px) {
    body.ds-page .ds-drawer-panier__panneau { width: calc(100vw - 32px); }
}

/* ── F13 (suite). Le multiple de vente se lit sous le selecteur ──────────
   La mention est permanente ; la seconde ligne, elle, n'apparait qu'apres un
   ajustement et reste jusqu'au prochain changement. Le champ clignote une
   fois : 300ms de fond d'alerte, puis retour en 150ms. Pas d'alerte, pas de
   modale, pas de bouton bloque (Nielsen 5). */
body.ds-page .ds-qte-bloc { display: flex; flex-direction: column; gap: 4px; flex: none; }
body.ds-page .ds-qte-mention,
body.ds-page .ds-qte-ajuste { margin: 0; font-size: 13px; line-height: 1.3; color: var(--ds-grey-60); }
body.ds-page .ds-qte-ajuste { color: var(--ds-warn-fg); }
body.ds-page .ds-qte-ajuste:empty { display: none; }
body.ds-page .ds-qte__champ { transition: background-color var(--ds-dur-etat) var(--ds-ease-out); }
body.ds-page .ds-qte__champ--ajuste { background: var(--ds-warn-bg); transition-duration: 300ms; }
body.ds-page .ds-fiche__achat .ds-qte-bloc { align-self: flex-start; }

/* ── F4 (suite). Un seul conteneur de 1200px sur le front ────────────────
   Les sections « Nos nouveautes » et « Promotions du moment » vivent dans un
   .container Bootstrap de 1140px, les autres dans .ds-page-section de 1200px :
   leurs titres ne tombaient pas sur la meme verticale, ce qui donnait deux
   gabarits colles. Meme largeur, meme gouttiere, donc meme ligne de lecture. */
/* !important assume : les gouttieres de ces conteneurs viennent de classes
   utilitaires Bootstrap (px-lg-*) qui sont elles-memes en !important. */
body.ds-page main > .container,
body.ds-page main > div > .container { max-width: 1200px; padding-left: 24px !important; padding-right: 24px !important; }
@media (max-width: 389.98px) {
    body.ds-page main > .container,
    body.ds-page main > div > .container { padding-left: 16px !important; padding-right: 16px !important; }
}

/* ── F19 (suite). Les cibles restantes sous 44px, mesurees a 390px ───────
   Fil d'Ariane, pagination, liens d'action de tableau et bouton d'export :
   ils etaient entre 20 et 40px de haut, donc une cible manquee sur deux au
   doigt dans une liste de dix lignes. */
body.ds-page .ds-ariane__item a,
body.ds-page .ds-ariane__item {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}
body.ds-page .pagination .page-item .page-link,
body.ds-page .ds-pagination__lien { min-height: 44px; height: 44px; min-width: 44px; }
body.ds-page .ds-dt-export,
body.ds-page .ds-tableau .btn-tableau > a,
body.ds-page .ds-tableau__action { min-height: 44px; }

@media (max-width: 767.98px) {
    /* F19 : au doigt, aucune exception. La taille « sm » (36px) reste la regle
       a la souris, elle passe a 44px des qu'on est sur un ecran tactile, et les
       liens d'action des cartes et des tableaux de compte suivent. */
    body.ds-page .ds-btn--sm { height: 44px; min-height: 44px; }
    body.ds-page .ds-compte-carte a:not(.ds-btn),
    body.ds-page .ds-tableau a:not(.ds-btn) {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }
}

/* ── R10 (suite). L'anneau de focus suit l'accent du tenant ──────────────
   --ds-focus-ring-color est declare sur :root, ou --ds-accent vaut encore son
   repli (#1c1c1e) : la couleur calculee par le serveur est posee sur <body>,
   plus bas dans la cascade. Le token est donc redefini au niveau du body, la
   ou l'accent du site existe reellement. Sans cela, l'anneau reste gris sombre
   sur la boutique dont l'accent est rouge. */
body.ds-page { --ds-focus-ring-color: var(--ds-accent); }

/* ══════════════════════════════════════════════════════════════════════════
   R2-design. Inscription professionnelle (/register) : carte de 1040px, quatre
   blocs (Société, Adresse, Contact, Accès) en deux colonnes (rail à gauche,
   champs à droite), icône d'information du SIREN, zone de retour du SIREN.
   Maquette et justifications : DESIGN-REGISTER-PRO.md (design-ux, 2026-10-04).
   ══════════════════════════════════════════════════════════════════════════ */
body.ds-page .ds-auth-carte--large { max-width: 1040px; padding: 48px; }
body.ds-page .ds-auth-page--inscription { padding-top: 64px; padding-bottom: 88px; }
body.ds-page .ds-auth-page--inscription .ds-auth-marque { margin-bottom: 24px; }
body.ds-page .ds-auth-page--inscription .ds-auth-titre { font-size: 28px; }
body.ds-page .ds-auth-page--inscription .ds-auth-intro { max-width: 560px; margin: 0 auto 40px; font-size: 16px; }

body.ds-page .ds-auth-bloc {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    column-gap: 48px;
    padding: 32px 0;
    border-top: 1px solid var(--ds-grey-15);
}
body.ds-page .ds-auth-bloc:first-of-type { border-top: 0; padding-top: 0; }
body.ds-page .ds-auth-bloc .ds-auth-section { margin: 0; padding: 0; border: 0; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
body.ds-page .ds-auth-section__aide { margin: 6px 0 0; font-size: 14px; line-height: 1.5; color: var(--ds-grey-60); }
body.ds-page .ds-auth-bloc .form-group { margin-bottom: 0; }
body.ds-page .ds-auth-bloc .ds-form-grille > div { min-width: 0; }
body.ds-page .ds-auth-bloc .ds-form-grille--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
body.ds-page .ds-auth-bloc textarea.form-control { min-height: 80px; }

/* Bordure de champ à 3:1 (jeton --ds-champ-bord) : limitée à ce formulaire. Spécificité volontairement inférieure
   à celle des états :focus-visible et .is-invalid (bordure accent ou rouge, déjà posées plus haut). */
body.ds-page .ds-auth-bloc .form-control,
body.ds-page .ds-auth-bloc select,
body.ds-page .ds-auth-bloc textarea { border-color: var(--ds-champ-bord); }
body.ds-page .ds-auth-bloc .form-control::placeholder,
body.ds-page .ds-auth-bloc textarea::placeholder { color: var(--ds-grey-60); opacity: 1; }
body.ds-page .ds-auth-bloc .form-control[aria-invalid="true"] { border-color: var(--ds-err-fg); box-shadow: inset 0 0 0 1px var(--ds-err-fg); }

body.ds-page .ds-champ__facultatif { font-weight: 400; color: var(--ds-grey-60); }
body.ds-page .ds-champ__prerempli { margin-left: 6px; font-size: 12px; font-weight: 500; color: #0f5a37; }
body.ds-page .ds-champ__prerempli[hidden], body.ds-page .ds-champ__requis[hidden], body.ds-page .ds-champ__facultatif[hidden] { display: none; }
body.ds-page .ds-champ__requis { font-size: 14px; font-weight: 600; color: var(--ds-err-fg); }

/* Étiquette du SIREN et bouton i. */
body.ds-page .ds-champ__tete { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; position: relative; width: fit-content; max-width: 100%; }
body.ds-page .ds-info {
    position: relative;
    flex: none;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 1px solid var(--ds-grey-60);
    border-radius: 50%;
    background: #fff;
    color: var(--ds-grey-60);
    font: italic 700 12px/1 Georgia, serif;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
body.ds-page .ds-info::after { content: ""; position: absolute; inset: -12px; } /* cible tactile 44 x 44 */
body.ds-page .ds-info:hover { background: var(--ds-grey-05); color: var(--ds-grey-95); border-color: var(--ds-grey-95); }
body.ds-page .ds-info[aria-expanded="true"] { background: var(--ds-accent); border-color: var(--ds-accent); color: var(--ds-on-accent, #fff); }
body.ds-page .ds-info:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 3px; }
body.ds-page .ds-info__panneau {
    position: absolute;
    z-index: 20;
    top: -12px;
    right: calc(100% + 12px);
    width: 320px;
    padding: 16px 16px 12px;
    background: #fff;
    border: 1px solid var(--ds-grey-25);
    border-radius: var(--ds-radius-lg, 12px);
    box-shadow: 0 1px 2px rgba(16, 16, 20, 0.06), 0 12px 32px rgba(16, 16, 20, 0.14);
}
body.ds-page .ds-info__panneau[hidden] { display: none; }
body.ds-page .ds-info__titre { margin: 0 0 6px; font-size: 15px; font-weight: 600; }
body.ds-page .ds-info__texte { margin: 0 0 8px; font-size: 14px; line-height: 1.55; color: var(--ds-grey-95); }
body.ds-page .ds-info__pied { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 4px; }
body.ds-page .ds-info__pied a { display: inline-flex; align-items: center; min-height: 44px; font-size: 14px; }
body.ds-page .ds-info__fermer {
    min-height: 44px;
    padding: 0 8px;
    border: 0;
    background: none;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--ds-accent-texte, var(--ds-accent));
    cursor: pointer;
    border-radius: 6px;
}

/* Zone de retour du SIREN (pleine largeur sous SIREN et raison sociale). */
body.ds-page .ds-siren-retour:empty { display: none; }
body.ds-page .ds-retour { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; border: 1px solid; border-radius: var(--ds-radius-control, 8px); font-size: 15px; line-height: 1.5; }
body.ds-page .ds-retour > svg { flex: none; width: 20px; height: 20px; margin-top: 1px; }
body.ds-page .ds-retour p { margin: 0; }
body.ds-page .ds-retour p + p { margin-top: 4px; }
body.ds-page .ds-retour strong { font-weight: 600; }
body.ds-page .ds-retour--neutre { background: var(--ds-grey-05); border-color: var(--ds-grey-15); color: var(--ds-grey-95); }
body.ds-page .ds-retour--ok { background: var(--ds-ok-bg); border-color: var(--ds-ok-bd); color: #0f5a37; }
body.ds-page .ds-retour--err { background: var(--ds-err-bg); border-color: var(--ds-err-bd); color: #8f1d17; }
body.ds-page .ds-retour--warn { background: #fdf3e1; border-color: #f0d9a8; color: #6b4000; }
body.ds-page .ds-retour a.ds-retour__tel { display: inline-block; font-weight: 700; color: inherit; text-decoration: underline; padding: 4px 0; white-space: nowrap; }
body.ds-page .ds-retour__actions { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; }
body.ds-page .ds-retour a.ds-retour__lien { display: inline-block; font-weight: 600; color: inherit; text-decoration: underline; padding: 4px 0; }
body.ds-page .ds-retour .ds-btn--secondary { border-color: currentColor; background: transparent; color: inherit; }
@keyframes ds-tourne { to { transform: rotate(360deg); } }
body.ds-page .ds-spin { animation: ds-tourne 0.9s linear infinite; }
@media (prefers-reduced-motion: reduce) { body.ds-page .ds-spin { animation: none !important; } }

/* Mot de passe : règles sur toute la largeur du bloc. */
body.ds-page .ds-auth-bloc .ds-mdp-regles { margin-top: 0; }

/* Consentements et actions, alignés sur la colonne des champs. */
body.ds-page .ds-auth-page--inscription .ds-auth-pied { display: grid; grid-template-columns: 260px minmax(0, 1fr); column-gap: 48px; padding-top: 32px; border-top: 1px solid var(--ds-grey-15); }
body.ds-page .ds-auth-page--inscription .ds-auth-pied > div { grid-column: 2; }
body.ds-page .ds-auth-page--inscription .ds-auth-pied .ds-auth-consentements { margin-top: 0; }
body.ds-page .ds-auth-page--inscription .ds-auth-pied input[type="checkbox"] { width: 24px; height: 24px; flex: none; margin: 0; }
body.ds-page .ds-auth-page--inscription .ds-auth-pied .ds-auth-actions { margin-top: 24px; }
body.ds-page .ds-auth-page--inscription .ds-auth-pied .ds-auth-actions .ds-btn--primary,
body.ds-page .ds-auth-page--inscription .ds-auth-pied .ds-auth-actions input[type="submit"] { min-width: 240px; }
body.ds-page .ds-auth-page--inscription .ds-auth-pied .ds-auth-actions .ds-btn { min-height: 44px; }

/* En dessous de 900px : le rail passe au-dessus des champs, le panneau d'information s'intègre sous le libellé. */
@media (max-width: 899.98px) {
    body.ds-page .ds-champ__tete { display: flex; width: 100%; }
    body.ds-page .ds-info__panneau { position: static; width: 100%; flex: 0 0 100%; margin-top: 6px; box-shadow: none; background: var(--ds-grey-05); }
    body.ds-page .ds-auth-bloc,
    body.ds-page .ds-auth-page--inscription .ds-auth-pied { grid-template-columns: minmax(0, 1fr); row-gap: 20px; }
    body.ds-page .ds-auth-page--inscription .ds-auth-pied > div { grid-column: 1; }
}
@media (max-width: 767.98px) {
    body.ds-page .ds-auth-page--inscription { padding: 24px 16px 48px; }
    body.ds-page .ds-auth-carte--large { padding: 24px 16px; }
    body.ds-page .ds-auth-page--inscription .ds-auth-titre { font-size: 24px; }
    body.ds-page .ds-auth-page--inscription .ds-auth-intro { margin-bottom: 28px; }
    body.ds-page .ds-auth-bloc .ds-form-grille--3 { grid-template-columns: minmax(0, 1fr); }
    body.ds-page .ds-auth-page--inscription .ds-auth-pied .ds-auth-actions .ds-btn,
    body.ds-page .ds-auth-page--inscription .ds-auth-pied .ds-auth-actions input[type="submit"] { width: 100%; min-width: 0; }
}

/* R2-design, retouches : l'erreur du SIREN s'affiche dans #siren-retour, pas deux fois ; consentements alignés à gauche. */
body.ds-page .ds-champ-siren .invalid-feedback { display: none !important; } /* .d-block de Bootstrap est en !important */
body.ds-page .ds-auth-page--inscription .ds-auth-pied,
body.ds-page .ds-auth-page--inscription .ds-auth-pied label { text-align: left; }
body.ds-page .ds-auth-page--inscription .ds-auth-pied .rgpd-mention-courte { text-align: left; font-size: 13px; color: var(--ds-grey-60); margin: 0; }

/* ── Lot AI4 : tunnel du visiteur sans compte ─────────────────────────────
   Carte radio choisie : fond teinté à 8 % de l'accent, jamais l'accent clair du thème (bleu saturé sur Paul Mitchell,
   texte gris illisible dessus). Tiroir du visiteur : le libellé du bouton « Finaliser ma commande » suit la couleur
   « sur primaire » (la feuille du thème historique le forçait à la couleur du texte), total aligné comme celui du
   compte connecté. */
body.ds-page .ds-carte-radio--choisie {
    background: #fff;
    background: color-mix(in srgb, var(--ds-accent) 8%, #fff);
}
body.ds-page .mini-panier-anon-btn-cde,
body.ds-page .mini-panier-anon-btn-cde:hover,
body.ds-page .mini-panier-anon-btn-cde:focus {
    color: var(--ds-on-primary) !important;
    text-decoration: none !important;
}
body.ds-page .mini-panier-anon-btn-cde { display: flex; align-items: center; justify-content: space-between; padding: 0 18px; }
body.ds-page .mini-panier-anon-btn-cde:hover { background: var(--ds-primary-bg); filter: brightness(1.12); }
body.ds-page .mini-panier-anon-footer { display: flex; flex-direction: column; gap: 10px; }
body.ds-page .mini-panier-total { display: flex; justify-content: space-between; font-size: 15px; color: var(--ds-grey-60); }
body.ds-page .mini-panier-total span:last-child { color: var(--ds-grey-95); font-weight: 600; }
body.ds-page .mini-panier-anon-body .ds-drawer-panier__liste { padding: 0; }
body.ds-page .mini-panier-anon-body .mini-panier-delete { background: none; border: 0; }
body.ds-page .mini-panier-anon-body .mini-panier-delete:hover { background: var(--ds-err-bg); color: var(--ds-err-fg); }
body.ds-page .mini-panier-anon-body .mini-panier-img-ph { color: var(--ds-grey-60); font-size: 18px; }
body.ds-page .mini-panier-anon-btn-continuer { margin: 0; }

/* JT-22 : inscription particulier (/register-public), même famille que la connexion : carte centrée un peu plus large
   que la connexion (deux champs côte à côte pour le prénom et le nom), champs empilés, CGU lisible, bouton pleine largeur. */
body.ds-page .ds-auth-carte.ds-auth-carte--public { max-width: 480px; }
body.ds-page .ds-auth-carte--public .ds-auth-titre { margin-bottom: 24px; }
body.ds-page .ds-auth-carte--public .ds-auth-champs { gap: 18px; }
body.ds-page .ds-auth-carte--public .ds-form-grille { gap: 18px; }
body.ds-page .ds-auth-carte--public .form-group { margin-bottom: 0; }
body.ds-page .ds-auth-carte--public .form-text { margin-top: 6px; font-size: 13px; color: var(--ds-grey-60); }
body.ds-page .ds-auth-carte--public .ds-auth-consentements { margin-top: 24px; gap: 14px; }
body.ds-page .ds-auth-carte--public .ds-auth-cgu { display: flex; flex-wrap: wrap; align-items: flex-start; column-gap: 12px; row-gap: 4px; padding-left: 0; margin: 0; }
body.ds-page .ds-auth-carte--public .ds-auth-cgu input[type="checkbox"] { flex: none; width: 24px; height: 24px; margin: 0; float: none; }
body.ds-page .ds-auth-carte--public .ds-auth-cgu label { flex: 1 1 0; min-width: 0; margin: 0; font-size: 15px; line-height: 1.5; padding-top: 1px; }
body.ds-page .ds-auth-carte--public .ds-auth-cgu a { flex-basis: 100%; margin-left: 36px; font-size: 14px; font-weight: 500; }
body.ds-page .ds-auth-carte--public .rgpd-mention-courte { margin: 0; font-size: 13px; line-height: 1.5; color: var(--ds-grey-60); }
body.ds-page .ds-auth-carte--public .ds-auth-actions { margin-top: 24px; }
body.ds-page .ds-auth-carte--public .ds-auth-actions .ds-btn,
body.ds-page .ds-auth-carte--public .ds-auth-actions input[type="submit"],
body.ds-page .ds-auth-carte--public .ds-auth-actions button[type="submit"] { width: 100%; }
@media (max-width: 480px) {
    body.ds-page .ds-auth-carte--public .ds-form-grille { grid-template-columns: minmax(0, 1fr); }
}

/* JT-23 : lien « Créer mon compte » dans l'en-tête des sites particulier (ordinateur). Sous 1024 px il passe dans le tiroir. */
body.ds-page .dr-entete__creer-compte {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 12px;
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    color: var(--ds-grey-95);
    text-decoration: none;
}
body.ds-page .dr-entete__creer-compte:hover { text-decoration: underline; }
@media (max-width: 1023.98px) { body.ds-page .dr-entete__creer-compte { display: none; } }

/* Revue responsive du 31/10 : pied de panier. Lien « Continuer mes achats » et date ne se collent
   plus sur une ligne étroite, chaque lien garde une cible de 44 px. */
@media (max-width: 480px) {
    body.ds-page .ds-panier-sous-lignes { flex-direction: column; align-items: flex-start; gap: 4px; }
    body.ds-page .ds-panier-sous-lignes .ds-panier-continuer,
    body.ds-page .ds-panier-sous-lignes .ds-panier-lien-secondaire { display: inline-flex; align-items: center; min-height: 44px; }
}
