/* ============================================================================
   SOCIALNEST — DESIGN SYSTEM v12
   ----------------------------------------------------------------------------
   Couche finale, chargée APRÈS main.css + shadcn-flavor.css + app-dark.css +
   cw-kit.css. Même stratégie que app-dark.css v10k : on ne réécrit pas les
   templates, on redéfinit les tokens qu'ils consomment déjà.

   Ce que cette couche apporte :
     1. UNE échelle sémantique (--ds-*) au lieu de trois systèmes parallèles
        (--sn-* clair, --app-* sombre, --cw-* wizard) qui divergeaient.
     2. Un CONTRAT MÉDIA : 4 ratios au lieu des 12 constatés dans le code,
        scrim tokenisé, montée en flou, pas de saut de page.
     3. Les blocs qui manquaient : contenu verrouillé, prix, boutique,
        feuille de paiement, squelettes, états vides.
     4. Les correctifs d'accessibilité mesurés (voir V12_UPGRADE.md §2).

   LEGACY : aucun sélecteur existant n'est supprimé. Les anciens noms de tokens
   (--app-*, --cw-*, --sn-* en contexte sombre, --pg-*) sont RÉ-ALIASÉS sur
   l'échelle v12 en §3. Un template non touché hérite du rafraîchissement ;
   un template déjà migré consomme --ds-* directement.

   Ordre de chargement (base.html) :
     main.css → shadcn-flavor.css → app-dark.css → cw-kit.css → sn-ds-v12.css
   ========================================================================== */

/* ─────────────────────────────────────────────── 1. ÉCHELLE CANONIQUE ── */
:root {
  /* — Surfaces : 4 niveaux, jamais plus. Chaque niveau = +1 profondeur. — */
  --ds-bg:        #0E0E10;   /* fond application (jamais #000 : smearing OLED) */
  --ds-1:         #16161A;   /* carte posée sur le fond                        */
  --ds-2:         #1F1F24;   /* élément imbriqué DANS une carte                */
  --ds-3:         #2B2B31;   /* survol, piste de contrôle, avatar vide         */

  /* — Texte : 3 niveaux. Alpha sur blanc, jamais de gris fixes. — */
  --ds-t1:        #FFFFFF;
  --ds-t2:        rgba(255,255,255,.68);
  --ds-t3:        rgba(255,255,255,.50);   /* v11 : .38 → 2,74:1 sur carte. Corrigé. */

  --ds-line:      rgba(255,255,255,.13);
  --ds-line-str:  rgba(255,255,255,.24);   /* bordure de champ, contour actif  */

  /* — Accents. La marque ne change pas : lime = action, violet = lien. — */
  --ds-accent:      #E3F331;   /* CTA primaire — 15,7:1 sur l'encre           */
  --ds-accent-ink:  #0E0E10;   /* texte sur lime                              */
  --ds-accent-soft: rgba(227,243,49,.14);
  --ds-link:        #8B6CF6;   /* liens, nav active, anneau de focus — 5,1:1  */
  --ds-goog:        #8AB4F8;   /* réservé au contexte OAuth Google            */

  --ds-ok:        #4ADE80;
  --ds-warn:      #FBBF24;
  --ds-danger:    #F87171;
  --ds-ok-soft:   rgba(74,222,128,.14);
  --ds-warn-soft: rgba(251,191,36,.14);
  --ds-danger-soft: rgba(248,113,113,.14);

  /* — Voile média : une seule définition pour toute l'application. — */
  --ds-scrim: linear-gradient(to top,
                rgba(0,0,0,.86) 0%, rgba(0,0,0,.55) 34%,
                rgba(0,0,0,.12) 62%, transparent 100%);
  --ds-scrim-soft: linear-gradient(to top, rgba(0,0,0,.68) 0%, transparent 62%);

  /* — Contrat média : 4 emplacements. Le ratio vient de l'EMPLACEMENT,
       jamais du fichier. C'est ce qui garantit CLS < 0,1. — */
  --ar-wide:     16/9;    /* vidéo horizontale, bannière            */
  --ar-square:   1/1;     /* produit boutique, pochette, avatar     */
  --ar-portrait: 3/4;     /* carte de contenu — le format de travail */
  --ar-story:    9/16;    /* vertical plein cadre : reel, short, TikTok */
  --ar-hero:     4/3;     /* couverture de profil (16/9 ≥ 640px)    */

  /* — Géométrie mobile. Rayons resserrés : 40px sur une carte pleine
       largeur à 390px rogne le contenu. — */
  --ds-r-xs:   8px;
  --ds-r-sm:   12px;
  --ds-r-md:   14px;   /* média          */
  --ds-r-lg:   18px;   /* carte, rangée  */
  --ds-r-xl:   22px;
  --ds-pill:   999px;

  /* — Rythme 4pt. — */
  --ds-1x: 4px;  --ds-2x: 8px;  --ds-3x: 12px; --ds-4x: 16px;
  --ds-5x: 20px; --ds-6x: 24px; --ds-8x: 32px; --ds-10x: 40px; --ds-14x: 56px;

  --ds-gutter: 16px;   /* gouttière mobile  */
  --ds-tap:    44px;   /* cible tactile minimale */
  --ds-col:    440px;  /* colonne « phone shell » du playbook */

  /* — Profondeur : ombre portée + halo, jamais l'un sans l'autre. — */
  --ds-e1: 0 1px 2px rgba(0,0,0,.34);
  --ds-e2: 0 4px 14px rgba(0,0,0,.40);
  --ds-e3: 0 12px 34px rgba(0,0,0,.48);

  /* — Mouvement. Un seul easing signature, hérité du wizard. — */
  --ds-ease: cubic-bezier(.16,1,.3,1);
  --ds-fast: .15s;
  --ds-mid:  .28s;
  --ds-slow: .45s;

  --ds-z-sticky: 40;
  --ds-z-dock:   50;
  --ds-z-sheet:  60;
  --ds-z-toast:  70;

  /* — Typographie. Anton reste le display de marque ; Inter le corps.
       Le corps monte à 16px : en dessous, iOS zoome les champs. — */
  --ds-f-display: 'Anton','Bebas Neue','Archivo Black',sans-serif;
  --ds-f-body:    'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;

  --ds-fs-hero:  30px;
  --ds-fs-h1:    25px;
  --ds-fs-h2:    20px;
  --ds-fs-h3:    17px;
  --ds-fs-body:  16px;
  --ds-fs-sm:    14px;
  --ds-fs-xs:    12.5px;
  --ds-fs-2xs:   11px;
}

/* ─────────────────────────────────────────────────── 2. THÈME CLAIR ── */
/* Utilisé par les pages publiques à fond clair et par [data-theme="paper"].
   Les mêmes composants, aucun changement de balisage.                    */
[data-theme="paper"] {
  --ds-bg:   #FBFBF9;
  --ds-1:    #FFFFFF;
  --ds-2:    #F3F3F0;
  --ds-3:    #E7E7E2;
  --ds-t1:   #131316;
  --ds-t2:   rgba(19,19,22,.68);
  --ds-t3:   rgba(19,19,22,.52);
  --ds-line: rgba(19,19,22,.12);
  --ds-line-str: rgba(19,19,22,.22);
  /* Le lime est invisible sur blanc (1,23:1). En thème clair l'action
     passe au violet, qui tient 6,7:1 avec du texte blanc.               */
  --ds-accent:      #5F35E6;
  --ds-accent-ink:  #FFFFFF;
  --ds-accent-soft: rgba(95,53,230,.10);
  --ds-link:        #4F2ED1;
  --ds-ok:          #15803D;
  --ds-warn:        #A16207;
  --ds-danger:      #C2314A;
  --ds-e1: 0 1px 2px rgba(19,19,22,.07);
  --ds-e2: 0 4px 14px rgba(19,19,22,.09);
  --ds-e3: 0 12px 34px rgba(19,19,22,.13);
}

/* ─────────────────────────────────────── 3. PONT LEGACY (le cœur) ── */
/* Chaque famille de tokens déjà consommée par les templates pointe
   désormais sur l'échelle v12. Zéro modification de balisage.          */
:root {
  /* app-dark.css v10k */
  --app-bg: var(--ds-bg);          --app-surface: var(--ds-1);
  --app-surface-2: var(--ds-2);    --app-surface-3: var(--ds-3);
  --app-text: var(--ds-t1);        --app-muted: var(--ds-t2);
  --app-faint: var(--ds-t3);       --app-border: var(--ds-line);
  --app-accent: var(--ds-accent);  --app-accent-ink: var(--ds-accent-ink);
  --app-accent-2: var(--ds-link);  --app-green: var(--ds-ok);
  --app-red: var(--ds-danger);     --app-amber: var(--ds-warn);
  --app-pill: var(--ds-pill);      --app-r-card: var(--ds-r-lg);
  --app-r-input: var(--ds-r-md);

  /* cw-kit.css — le wizard garde son bleu Google, tout le reste s'aligne */
  --cw-bg: var(--ds-bg);           --cw-surface: var(--ds-1);
  --cw-surface-2: var(--ds-2);     --cw-text: var(--ds-t1);
  --cw-muted: var(--ds-t2);        --cw-faint: var(--ds-t3);
  --cw-border: var(--ds-line);     --cw-green: var(--ds-ok);
  --cw-pill: var(--ds-pill);       --cw-r-card: var(--ds-r-lg);
  --cw-r-input: var(--ds-r-md);

  /* Géométrie et sémantique : neutres, sans effet sur le thème. */
  --sn-radius-md: var(--ds-r-md);     --sn-radius-lg: var(--ds-r-lg);
  --sn-radius-pill: var(--ds-pill);
}

/* main.css v5 — remap SOMBRE, volontairement scopé.
   Ces tokens pilotent aussi le site vitrine et les écrans d'authentification,
   qui vivent sur main.css en clair. Les redéfinir au niveau :root noircissait
   toute la partie publique. Ils ne s'appliquent donc qu'à l'intérieur de la
   coquille applicative — la seule surface réellement sombre. */
.app-shell, [data-surface="app"] {
  --sn-neutral-100: var(--ds-line);   --sn-neutral-200: var(--ds-line);
  --sn-neutral-300: var(--ds-t3);     --sn-neutral-400: var(--ds-t2);
  --sn-neutral-500: var(--ds-t2);     --sn-neutral-900: var(--ds-t1);
  --sn-purple-600: var(--ds-link);    --sn-purple-1000: var(--ds-t1);
  --sn-purple-50: var(--ds-2);        --sn-purple-100: var(--ds-3);
  --sn-cream: var(--ds-1);
  --sn-error: var(--ds-danger);       --sn-success: var(--ds-ok);
  --sn-warning: var(--ds-warn);
}

/* ─────────────────────────────────────────── 4. SOCLE & ACCESSIBILITÉ ── */
html { -webkit-text-size-adjust: 100%; }

/* Anneau de focus visible partout. v11 s'appuyait sur le défaut navigateur,
   invisible sur fond sombre.                                              */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--ds-link);
  outline-offset: 2px;
  border-radius: var(--ds-r-xs);
}

/* Cible tactile. Le dessin peut rester petit ; la zone, non. */
.ds-tap, .cw-chip, .gb-chip, .sidebar-nav a, .topbar-burger, .bottomnav a {
  position: relative;
}
.ds-tap::after, .cw-chip::after, .gb-chip::after {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%,-50%);
  width: 100%; height: 100%;
  min-width: var(--ds-tap); min-height: var(--ds-tap);
}

/* iOS zoome tout champ sous 16px, puis laisse la page décalée. Non négociable.
   !important assumé : le <style> d'un gabarit est injecté APRÈS les feuilles
   et gagne à spécificité égale. Six gabarits déclaraient 13, 14 ou 15 px. */
/* La liste reprend exactement les sélecteurs de app-dark.css §forms. Un simple
   `select` ne suffisait pas : app-dark cible `select.select` (spécificité 0,1,1)
   en !important, et gagnait donc sur `select` (0,0,1). Mesuré à 14px sur la
   liste des commandes. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select, textarea, .cw-input, .ds-input,
.field input, .field select, .field textarea,
input.input, select.select, textarea.textarea {
  font-size: max(16px, 1em) !important;
}

/* Tableaux — 13 gabarits en affichaient un sans conteneur défilant : sous
   400 px, la page entière débordait horizontalement et le reste du contenu
   partait avec. Le tableau devient sa propre zone de défilement. */
@media (max-width: 760px) {
  table {
    display: block;
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  table thead, table tbody, table tfoot { display: table; width: 100%; min-width: max-content; }
  table th, table td { white-space: nowrap; }
}

/* Hauteur de frappe des boutons.
   main.css donne à `.btn` un remplissage de 8px et un corps de 13px, soit
   34px de haut — mesuré au navigateur sur la page d'accueil, où ce sont les
   actions PRINCIPALES. `.btn.sm` tombe à 25px. En dessous de 44px, le taux
   d'erreur au pouce grimpe et l'action doit être visée.
   Uniquement sur petit écran ou pointeur imprécis : la densité du bureau,
   voulue, ne bouge pas. */
@media (max-width: 900px), (pointer: coarse) {
  .btn, .cw-btn-primary, .gbtn, button[type="submit"] { min-height: 44px; }
  .btn.sm, .btn-icon, .hp-mic, .hp-send, .hp-chip { min-height: 40px; }
  .btn-icon, .hp-mic, .hp-send { min-width: 40px; }

  /* Liens de navigation et de pied du site vitrine : de vraies cibles, pas
     des liens en ligne dans une phrase. Mesurés à 12px de haut. La marge
     interne verticale suffit — la mise en page ne bouge pas. */
  .mk-nav-links a, .mk-footer-links a, .mk-nav-brand {
    display: inline-flex; align-items: center; min-height: 40px;
  }

  /* Coquille applicative : mesurée à 34px pour la navigation latérale, 36 pour
     l'avatar, 21 pour la marque, 23 pour la fermeture de l'assistant. Ce sont
     les commandes présentes sur TOUTES les pages connectées — les corriger ici
     vaut pour l'application entière. */
  .sidebar-nav a, .bottomnav a { min-height: 44px; }
  .topbar-avatar { width: 40px; height: 40px; }
  .topbar-brand { display: inline-flex; align-items: center; min-height: 44px; }
  .as-x { min-width: 40px; min-height: 40px; display: grid; place-items: center; }

  /* Onglets de filtre (deals, offres) mesurés à 28px : c'est le contrôle par
     lequel passe toute la lecture du pipeline. */
  .offer-tab, .tabs a, .tab-link, .mk-toc-link { min-height: 40px; display: inline-flex; align-items: center; }
  .ed-url-badge { min-height: 44px; display: inline-flex; align-items: center; }
}

/* Barre d'action fixée en bas : sans réserve d'encoche, le bouton passe sous
   la barre d'accueil iPhone et devient intappable. */
.cw-bottom, .ds-dock, [data-fixed-bottom] {
  padding-bottom: max(var(--ds-5x), calc(var(--ds-3x) + env(safe-area-inset-bottom))) !important;
}

/* Barre de défilement masquée sur les rails — une seule déclaration. */
.ds-rail, .row-scroll, .gb-chips, .gb-rail, .cw-rail {
  -ms-overflow-style: none; scrollbar-width: none;
}
.ds-rail::-webkit-scrollbar, .row-scroll::-webkit-scrollbar,
.gb-chips::-webkit-scrollbar, .gb-rail::-webkit-scrollbar { display: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
}

/* ──────────────────────────────────────────── 5. CONTRAT MÉDIA ── */
/* Règle unique : le conteneur porte le ratio, l'image le remplit.
   Le navigateur réserve la place avant le chargement → pas de saut.   */
.ds-media {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--ds-r-md);
  background: var(--ds-2);
  aspect-ratio: var(--ar-portrait);
  isolation: isolate;
}
.ds-media > img, .ds-media > video, .ds-media > .ds-media__bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  background-size: cover; background-position: center;
  display: block;
}
.ds-media--wide     { aspect-ratio: var(--ar-wide); }
.ds-media--square   { aspect-ratio: var(--ar-square); }
.ds-media--portrait { aspect-ratio: var(--ar-portrait); }
.ds-media--story    { aspect-ratio: var(--ar-story); }
.ds-media--hero     { aspect-ratio: var(--ar-hero); border-radius: 0; }
@media (min-width: 640px) { .ds-media--hero { aspect-ratio: var(--ar-wide); } }

/* Voile. Ne s'applique QUE si du texte se superpose — sinon il salit l'image. */
.ds-media__scrim { position: absolute; inset: 0; background: var(--ds-scrim); pointer-events: none; z-index: 1; }
.ds-media__scrim--soft { background: var(--ds-scrim-soft); }

.ds-media__cap {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  padding: 10px 11px 11px;
  display: flex; flex-direction: column; gap: 4px;
}
.ds-media__title {
  font: 600 13px/1.3 var(--ds-f-body); color: #fff;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ds-media__meta { font-size: var(--ds-fs-2xs); color: rgba(255,255,255,.80); display: flex; align-items: center; gap: 5px; }

.ds-media__tl { position: absolute; top: 8px; left: 8px;  right: auto; bottom: auto; z-index: 3; }
.ds-media__tr { position: absolute; top: 8px; right: 8px; left: auto;  bottom: auto; z-index: 3; }
.ds-media__br { position: absolute; right: 8px; bottom: 8px; top: auto; left: auto; z-index: 3;
  font: 700 11px/1 var(--ds-f-body); color:#fff; background: rgba(0,0,0,.62);
  padding: 4px 7px; border-radius: 6px; backdrop-filter: blur(6px); }

/* Bouton lecture — 44px de zone, dessin 20px. */
.ds-play {
  position: absolute; inset: 0; margin: auto; z-index: 3;
  width: var(--ds-tap); height: var(--ds-tap); border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0,0,0,.52); backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,.26); color: #fff;
}

/* Montée en flou : la miniature 20px se dévoile, aucune reflow. */
.ds-media img[data-blur] { filter: blur(14px); transform: scale(1.06); transition: filter var(--ds-mid) ease, transform var(--ds-mid) ease; }
.ds-media img[data-blur].is-loaded { filter: none; transform: none; }

/* Média absent : le bloc GARDE sa place dans la grille. */
.ds-media--missing { display: grid; place-items: center; background: var(--ds-2); }
.ds-media--missing span { font-size: var(--ds-fs-xs); color: var(--ds-t3); text-align: center; padding: 12px; }

/* ── Normalisation des ratios existants ────────────────────────────────
   v11 déclarait 12 ratios distincts pour 4 usages réels (9/14, 9/16, 9/17,
   3/4, 2/2.5, 4/3, 16/9, 16/10, 1/1…). On les ramène aux 4 emplacements.
   Effet immédiat : les rails cessent de « sauter » d'une carte à l'autre. */
.pn-card, .gb-card-media, .card-media, .content-card__media { aspect-ratio: var(--ar-portrait) !important; }
.gb-hero { aspect-ratio: var(--ar-hero) !important; }
@media (min-width: 640px) { .gb-hero { aspect-ratio: var(--ar-wide) !important; } }

/* ────────────────────────────────────────────── 6. PRIMITIVES ── */
.ds-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--ds-tap); padding: 0 18px;
  border: 0; border-radius: var(--ds-pill);
  font: 700 var(--ds-fs-sm)/1 var(--ds-f-body); letter-spacing: .01em;
  color: var(--ds-t1); background: transparent; cursor: pointer;
  transition: filter var(--ds-fast), transform .1s, background var(--ds-fast);
  text-decoration: none; white-space: nowrap;
}
.ds-btn:active { transform: scale(.98); }
.ds-btn:disabled, .ds-btn[aria-disabled="true"] { opacity: .42; cursor: not-allowed; transform: none; }
.ds-btn--primary { background: var(--ds-accent); color: var(--ds-accent-ink); }
.ds-btn--primary:hover { filter: brightness(1.07); }
.ds-btn--surface { background: var(--ds-2); color: var(--ds-t1); border: 1px solid var(--ds-line); }
.ds-btn--surface:hover { background: var(--ds-3); }
.ds-btn--ghost   { color: var(--ds-t2); }
.ds-btn--ghost:hover { background: var(--ds-2); color: var(--ds-t1); }
.ds-btn--danger  { background: var(--ds-danger-soft); color: var(--ds-danger); border: 1px solid var(--ds-danger); }
.ds-btn--full    { width: 100%; }
.ds-btn--sm      { min-height: 36px; padding: 0 14px; font-size: var(--ds-fs-xs); }
.ds-btn > svg    { width: 18px; height: 18px; flex: none; }

.ds-iconbtn {
  display: inline-grid; place-items: center; flex: none;
  width: var(--ds-tap); height: var(--ds-tap); border-radius: 50%;
  background: var(--ds-2); border: 1px solid var(--ds-line); color: var(--ds-t1);
  cursor: pointer; transition: background var(--ds-fast);
}
.ds-iconbtn:hover { background: var(--ds-3); }
.ds-iconbtn--glass { background: rgba(0,0,0,.42); backdrop-filter: blur(10px); border-color: rgba(255,255,255,.20); color:#fff; }
.ds-iconbtn > svg:not([width]) { width: 20px; height: 20px; }

.ds-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: var(--ds-pill);
  background: var(--ds-2); border: 1px solid var(--ds-line);
  font: 600 var(--ds-fs-2xs)/1.35 var(--ds-f-body); color: var(--ds-t2);
  white-space: nowrap;
}
.ds-pill > svg { width: 13px; height: 13px; }
.ds-pill--accent { background: var(--ds-accent-soft); border-color: transparent; color: var(--ds-accent); }
.ds-pill--ok     { background: var(--ds-ok-soft);     border-color: transparent; color: var(--ds-ok); }
.ds-pill--warn   { background: var(--ds-warn-soft);   border-color: transparent; color: var(--ds-warn); }
.ds-pill--danger { background: var(--ds-danger-soft); border-color: transparent; color: var(--ds-danger); }
.ds-pill--glass  { background: rgba(0,0,0,.55); backdrop-filter: blur(8px); border-color: rgba(255,255,255,.18); color:#fff; }
.ds-pill--live   { background: var(--ds-danger); border-color: transparent; color: #fff; }
.ds-live-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; animation: ds-pulse 1.8s ease-in-out infinite; }
@keyframes ds-pulse { 0%,100% { opacity: 1; } 50% { opacity: .34; } }

/* Chip de filtre — état actif lisible à DEUX endroits (fond + contour). */
.ds-chip {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 36px; padding: 0 14px; border-radius: var(--ds-pill);
  background: var(--ds-1); border: 1px solid var(--ds-line);
  font: 600 var(--ds-fs-xs)/1 var(--ds-f-body); color: var(--ds-t2);
  cursor: pointer; white-space: nowrap; transition: all var(--ds-fast);
}
.ds-chip:hover { border-color: var(--ds-line-str); color: var(--ds-t1); }
.ds-chip[aria-pressed="true"], .ds-chip.active {
  background: var(--ds-accent); border-color: var(--ds-accent); color: var(--ds-accent-ink);
}
.ds-chip > svg { width: 15px; height: 15px; }

.ds-rail {
  display: flex; gap: var(--ds-3x); overflow-x: auto;
  padding-inline: var(--ds-gutter); padding-bottom: 4px;
  scroll-snap-type: x proximity; overscroll-behavior-x: contain;
}
.ds-rail > * { flex: 0 0 auto; scroll-snap-align: start; }

.ds-card {
  background: var(--ds-1); border: 1px solid var(--ds-line);
  border-radius: var(--ds-r-lg); overflow: hidden;
}
.ds-card__b { padding: var(--ds-4x); display: flex; flex-direction: column; gap: var(--ds-3x); }

/* Rangée de lien — le bloc le plus vu de toute l'application. */
.ds-row {
  display: flex; align-items: center; gap: 12px;
  min-height: 62px; padding: 11px 14px;
  background: var(--ds-1); border: 1px solid var(--ds-line);
  border-radius: var(--ds-r-lg); color: var(--ds-t1);
  text-decoration: none; transition: background var(--ds-fast), border-color var(--ds-fast);
}
.ds-row:hover { background: var(--ds-2); border-color: var(--ds-line-str); }
.ds-row__ico {
  width: 40px; height: 40px; border-radius: 11px; flex: none;
  display: grid; place-items: center; overflow: hidden;
  background: var(--ds-2); color: var(--ds-t2);
}
.ds-row__ico > svg { width: 19px; height: 19px; }
.ds-row__body { flex: 1; min-width: 0; }
.ds-row__t {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font: 600 var(--ds-fs-sm)/1.3 var(--ds-f-body);
}
.ds-row__s {
  display: block; margin-top: 2px;
  font-size: var(--ds-fs-xs); color: var(--ds-t3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ds-row__end { flex: none; color: var(--ds-t3); display: flex; align-items: center; gap: 8px; }
.ds-row__end > svg { width: 18px; height: 18px; }
/* Trois niveaux d'emphase, pas quatre. */
.ds-row--feat { border-color: var(--ds-accent); box-shadow: 0 0 0 1px var(--ds-accent) inset; }
.ds-row--off  { opacity: .45; pointer-events: none; }

.ds-stack { display: flex; flex-direction: column; gap: var(--ds-2x); }
.ds-grid2 { display: grid; grid-template-columns: repeat(2,1fr); gap: var(--ds-3x); }
.ds-pad   { padding-inline: var(--ds-gutter); }

/* ─────────────────────────────────────────── 7. MONÉTISATION ── */
/* Le prix est TOUJOURS visible avant le tap. */
.ds-price { font: 800 20px/1 var(--ds-f-body); color: var(--ds-t1); }
.ds-price small { font-size: 12px; font-weight: 600; color: var(--ds-t3); }
.ds-strike { font-size: var(--ds-fs-xs); color: var(--ds-t3); text-decoration: line-through; }
.ds-priceline { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }

/* Contenu verrouillé. Le flou est un EFFET, pas une protection : l'aperçu
   servi doit être une basse définition générée côté serveur.              */
.ds-locked { position: relative; overflow: hidden; aspect-ratio: var(--ar-wide); background: var(--ds-2); }
.ds-locked__blur { position: absolute; inset: 0; width:100%; height:100%; object-fit: cover; filter: blur(26px) saturate(.75); transform: scale(1.15); }
.ds-locked__veil { position: absolute; inset: 0; background: rgba(6,6,8,.60); }
.ds-locked__c {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 7px; padding: 18px; text-align: center;
}
.ds-lockring {
  width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255,255,255,.13); border: 1px solid rgba(255,255,255,.22); color: #fff;
}
.ds-lockring > svg { width: 21px; height: 21px; }
.ds-locked__t { font: 700 var(--ds-fs-h3)/1.25 var(--ds-f-body); color: #fff; }
.ds-locked__s { font-size: var(--ds-fs-xs); color: rgba(255,255,255,.72); }

/* Créneaux de rendez-vous — l'indisponible reste VISIBLE et barré. */
.ds-slots { display: flex; flex-wrap: wrap; gap: 8px; }
.ds-slot {
  min-height: 40px; padding: 0 14px; border-radius: var(--ds-pill);
  background: var(--ds-2); border: 1px solid var(--ds-line);
  font: 700 var(--ds-fs-xs)/1 var(--ds-f-body); color: var(--ds-t1); cursor: pointer;
}
.ds-slot[aria-pressed="true"] { background: var(--ds-accent); border-color: var(--ds-accent); color: var(--ds-accent-ink); }
.ds-slot:disabled { opacity: .38; text-decoration: line-through; cursor: not-allowed; }

/* Feuille de paiement — un seul composant pour tous les blocs marchands. */
.ds-sheet {
  position: fixed; inset: auto 0 0 0; z-index: var(--ds-z-sheet);
  max-width: var(--ds-col); margin-inline: auto;
  background: var(--ds-1); border: 1px solid var(--ds-line); border-bottom: 0;
  border-radius: var(--ds-r-xl) var(--ds-r-xl) 0 0;
  padding: 10px var(--ds-5x) calc(var(--ds-5x) + env(safe-area-inset-bottom));
  box-shadow: var(--ds-e3);
  animation: ds-rise var(--ds-slow) var(--ds-ease);
}
@keyframes ds-rise { from { transform: translateY(100%); } to { transform: none; } }
.ds-sheet__grab { width: 38px; height: 4px; border-radius: 3px; background: var(--ds-3); margin: 0 auto 14px; }
.ds-sheet__line { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; font-size: var(--ds-fs-sm); color: var(--ds-t2); }
.ds-sheet__line b { color: var(--ds-t1); font-weight: 700; }
.ds-sheet__tot { border-top: 1px solid var(--ds-line); margin-top: 4px; padding-top: 13px; }
.ds-legal { font-size: var(--ds-fs-2xs); line-height: 1.45; color: var(--ds-t3); margin-top: 12px; text-align: center; }

/* ────────────────────────────────────────────────── 8. ÉTATS ── */
.ds-sk {
  background: linear-gradient(100deg, var(--ds-2) 30%, var(--ds-3) 50%, var(--ds-2) 70%);
  background-size: 240% 100%;
  animation: ds-shim 1.5s linear infinite;
  border-radius: var(--ds-r-sm);
}
@keyframes ds-shim { from { background-position: 140% 0; } to { background-position: -40% 0; } }

.ds-empty {
  text-align: center; padding: var(--ds-8x) var(--ds-5x);
  border: 1px dashed var(--ds-line); border-radius: var(--ds-r-lg); background: var(--ds-1);
}
.ds-empty > svg { display: block; width: 26px; height: 26px; margin: 0 auto 10px; color: var(--ds-t3); }
.ds-empty b { display: block; font: 700 var(--ds-fs-h3)/1.3 var(--ds-f-body); margin-bottom: 6px; }
.ds-empty p { font-size: var(--ds-fs-xs); color: var(--ds-t2); max-width: 30ch; margin: 0 auto 14px; line-height: 1.5; }

.ds-toast {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-radius: var(--ds-r-md);
  background: var(--ds-3); border: 1px solid var(--ds-line);
  font-size: var(--ds-fs-sm); box-shadow: var(--ds-e2);
}
.ds-toast > svg { width: 18px; height: 18px; flex: none; }
.ds-toast button { margin-left: auto; background: none; border: 0; color: var(--ds-accent); font: 700 var(--ds-fs-xs) var(--ds-f-body); cursor: pointer; }

/* Bandeau non bloquant : les données périmées restent lisibles. */
.ds-banner {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 12px 14px; border-radius: var(--ds-r-md);
  background: var(--ds-warn-soft); border: 1px solid color-mix(in srgb, var(--ds-warn) 40%, transparent);
  font-size: var(--ds-fs-xs); line-height: 1.45; color: var(--ds-t2);
}
.ds-banner > svg { width: 17px; height: 17px; flex: none; color: var(--ds-warn); margin-top: 1px; }

/* ──────────────────────────────── 9. BARRE D'ACTION COLLÉE ── */
/* Le pouce ne bouge jamais : principe P3 du playbook, étendu à toute l'app. */
.ds-dock {
  position: sticky; bottom: 0; z-index: var(--ds-z-dock);
  margin-inline: calc(var(--ds-gutter) * -1);
  padding: 12px var(--ds-gutter) calc(12px + env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--ds-bg) 72%, transparent);
  backdrop-filter: blur(12px);
}
.ds-dock--bordered { background: color-mix(in srgb, var(--ds-bg) 92%, transparent); border-top: 1px solid var(--ds-line); }
.ds-dock__row { display: flex; gap: 10px; align-items: center; }

/* ───────────────────────────── 10. REPRISES DE COMPOSANTS v11 ── */
/* Les classes existantes héritent des correctifs sans changer le balisage. */
.gb-chip, .cw-chip { min-height: var(--ds-tap); }
.gb-card-caption, .pn-caption { text-shadow: 0 1px 3px rgba(0,0,0,.55); }
.stat-card, .quick-action, .progress-card, .action-card { border-radius: var(--ds-r-lg); }
.quick-action:hover { transform: none; border-color: var(--ds-line-str); background: var(--ds-2); }

/* La barre de progression du wizard : même easing partout. */
.cw-progress > span, .progress-bar-fill { transition: width var(--ds-slow) var(--ds-ease); }

/* Anton en capitales serrées casse la lisibilité sous 20px : on borne. */
.hub-greeting h1, .sec-title, .stat-card .val {
  font-family: var(--ds-f-display); letter-spacing: .01em;
}
.stat-card .val { font-size: clamp(1.75rem, 6vw, 2.5rem); line-height: 1; }

@media print {
  .ds-dock, .ds-sheet, .topbar, .sidebar, .bottomnav { display: none !important; }
}
