/* Page acheteur — l'affiche imprimée.
   Crème, indigo, vermillon, ocre. Archivo 900 en capitales, filets noirs, zéro
   arrondi, prix en autocollant pivoté. La photo occupe tout le haut, le bloc
   imprimé la suit. Lumineux, fort, lisible de loin.
   Les règles et leurs raisons : apps/buyer/DESIGN.md. */
@font-face{font-family:Arch;font-weight:100 900;font-display:swap;src:url(/assets/archivo.woff2) format('woff2')}
@font-face{font-family:Fig;font-weight:300 900;font-display:swap;src:url(/assets/figtree-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
/* Le wolof écrit « ŋ » (U+014B). Sans cette tranche, il retombe sur une police
   système et l'étiquette change de dessin au milieu du mot. */
@font-face{font-family:Fig;font-weight:300 900;font-display:swap;src:url(/assets/figtree-latin-ext.woff2) format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,
    U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,
    U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
:root{--creme:#f7f1e3;--papier:#fffdf6;--encre:#14110c;--indigo:#1b3a6b;--verm:#d93f2b;
      --ocre:#e9a426;--ocre-doux:#fbf3e3;--trait:#14110c;--gris:#6f6757;
      --cible:56px;--m:16px;--max:560px}
*{box-sizing:border-box}
html{font-size:106.25%}
html,body{margin:0;background:var(--creme);color:var(--encre);font-family:Fig,system-ui,sans-serif;
  font-size:1rem;line-height:1.35;-webkit-text-size-adjust:100%}
.prix,.prix-barre,.prix-unite,.stock,.quantite output,.recap-total,.detail-prix,.tarif,
.prix-p,.principal,.dispo,.economie,.compteur{font-variant-numeric:tabular-nums}
.page{position:relative;max-width:var(--max);margin:0 auto;background:var(--papier);
  padding-bottom:calc(7rem + env(safe-area-inset-bottom));border-left:3px solid var(--trait);border-right:3px solid var(--trait)}
.vendeur{display:grid;grid-template-columns:auto 1fr;align-items:center;column-gap:11px;
  padding:52px var(--m) 0;background:var(--indigo);color:#fff;position:sticky;top:0;z-index:10}
.vendeur>div{min-width:0}
.vendeur-logo{width:42px;height:42px;flex:none;display:grid;place-items:center;background:var(--ocre);
  color:var(--encre);font-family:Arch;font-weight:900;font-size:.95rem;border:2px solid var(--trait);object-fit:cover}
.vendeur-nom{font-family:Arch;font-weight:900;font-size:1rem;text-transform:uppercase;letter-spacing:-.01em;
  display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.vendeur-legal{font-size:.74rem;opacity:.82}
.verifie{font-family:Arch;font-size:.62rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase;
  background:var(--ocre);color:var(--encre);padding:3px 7px;border:2px solid var(--trait)}
.direct{grid-column:1/-1;display:flex;align-items:center;justify-content:center;gap:9px;
  margin:11px calc(-1*var(--m)) 0;padding:7px;background:var(--verm);color:#fff;font-family:Arch;
  font-size:.78rem;font-weight:900;letter-spacing:.2em;text-transform:uppercase;border-top:3px solid var(--trait)}
.vendeur:not(:has(.direct)){padding-bottom:12px}
.pastille{width:9px;height:9px;background:#fff;animation:c 1.4s steps(2) infinite}
@keyframes c{50%{opacity:.15}}
.galerie{position:relative;background:var(--creme);border-bottom:3px solid var(--trait)}
.pellicule{display:grid;grid-auto-flow:column;grid-auto-columns:100%;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}
.pellicule::-webkit-scrollbar{display:none}
.photo{position:relative;width:100%;aspect-ratio:1;overflow:hidden;scroll-snap-align:center}
.photo img{width:100%;height:100%;object-fit:cover;display:block}
.photo-vide{height:130px;display:grid;place-items:center;font-weight:800}
.compteur{position:absolute;top:10px;right:10px;background:var(--encre);color:#fff;font-family:Arch;
  font-size:.72rem;font-weight:900;letter-spacing:.08em;padding:5px 10px;border:2px solid #fff}
.epuise-voile{position:absolute;inset:0;background:rgba(20,17,12,.58);display:grid;place-items:center}
.epuise-texte{background:var(--verm);color:#fff;font-family:Arch;font-weight:900;font-size:1.5rem;
  letter-spacing:.1em;text-transform:uppercase;padding:10px 24px;border:3px solid var(--trait);transform:rotate(-7deg)}
.corps{padding:var(--m)}
#zone-produit .galerie + .corps{padding-top:0;display:flex;flex-direction:column}
#zone-produit .galerie + .corps .prix-ligne{order:-1;width:max-content;max-width:100%;
  margin:-2.9em 0 .8em auto;display:flex;flex-direction:column;align-items:center;
  background:var(--ocre);color:var(--encre);border:3px solid var(--trait);padding:.5em .8em .6em;
  transform:rotate(-4deg);box-shadow:6px 6px 0 var(--trait);position:relative;z-index:3}
.prix{font-family:Arch;font-size:clamp(2.3rem,11vw,2.9rem);font-weight:900;letter-spacing:-.05em;line-height:.9}
.prix-unite{font-family:Arch;font-size:.74rem;font-weight:900;letter-spacing:.16em;text-transform:uppercase}
.prix-barre{font-size:.82rem;font-weight:700;text-decoration:line-through;opacity:.7}
.economie{font-family:Arch;font-size:.7rem;font-weight:900;background:var(--verm);color:#fff;padding:2px 8px;margin-top:3px}
.nom-produit{font-family:Arch;font-size:1.55rem;font-weight:900;text-transform:uppercase;
  letter-spacing:-.025em;line-height:1.02;margin:0 0 5px;text-wrap:balance}
.nom-wolof{font-size:.86rem;margin:0 0 12px;opacity:.72}
.stock{font-family:Arch;font-size:.82rem;font-weight:900;letter-spacing:.06em;text-transform:uppercase;
  margin:10px 0 0;display:inline-block;padding:6px 11px;border:2px solid var(--trait)}
.stock-ok{background:var(--creme)} .stock-bas{background:var(--verm);color:#fff}
.bloc{margin-top:22px}
.bloc-titre,.etape{font-family:Arch;font-size:.74rem;font-weight:900;letter-spacing:.16em;text-transform:uppercase;margin:0 0 10px}
.etape{margin-top:10px;padding-top:18px;border-top:3px solid var(--trait);font-size:.86rem}
.choix{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:10px}
.choix button,.zones button{min-height:var(--cible);padding:11px 13px;border:3px solid var(--trait);
  border-radius:0;background:var(--papier);color:var(--encre);font-family:Fig,sans-serif;font-size:1rem;font-weight:800;cursor:pointer}
.choix button{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}
.choix button[aria-pressed="true"],.zones button[aria-pressed="true"]{background:var(--ocre);box-shadow:4px 4px 0 var(--trait)}
.choix button:disabled{opacity:.4;text-decoration:line-through;cursor:not-allowed}
.dispo{font-family:Arch;font-size:.7rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}
.desc-variante{margin:12px 0 0;padding:11px 13px;background:var(--creme);border:2px solid var(--trait);font-size:.88rem;line-height:1.45}
.desc-variante[hidden]{display:none}
.quantite{display:flex;align-items:center;gap:12px}
.quantite button{width:var(--cible);height:var(--cible);flex:none;border:3px solid var(--trait);border-radius:0;
  background:var(--papier);font-family:Arch;font-size:1.6rem;font-weight:900;cursor:pointer}
.quantite button:active:not(:disabled){background:var(--ocre)}
.quantite button:disabled{opacity:.3}
.quantite output{font-family:Arch;font-size:2rem;font-weight:900;min-width:2.4ch;text-align:center}
.barre-action{position:fixed;bottom:0;left:0;right:0;z-index:20;background:var(--indigo);
  border-top:3px solid var(--trait);padding:11px var(--m) calc(11px + env(safe-area-inset-bottom))}
.barre-action-inner{max-width:var(--max);margin:0 auto}
.principal{width:100%;min-height:var(--cible);border:3px solid var(--trait);border-radius:0;background:var(--ocre);
  color:var(--encre);font-family:Arch;font-size:1.08rem;font-weight:900;letter-spacing:.04em;text-transform:uppercase;
  cursor:pointer;padding:12px 16px;display:flex;align-items:center;justify-content:center;box-shadow:5px 5px 0 var(--trait)}
.principal:active:not(:disabled){transform:translate(3px,3px);box-shadow:2px 2px 0 var(--trait)}
.principal:disabled{background:var(--creme);color:var(--gris);box-shadow:none;cursor:not-allowed}
.secondaire{width:100%;min-height:50px;border:3px solid var(--trait);border-radius:0;background:var(--papier);
  color:var(--encre);font-family:Arch;font-size:.92rem;font-weight:900;text-transform:uppercase;cursor:pointer;padding:12px}
label{display:block;font-family:Arch;font-size:.72rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase;margin:18px 0 6px}
label .aide{display:block;font-family:Fig,sans-serif;font-weight:400;font-size:.8rem;letter-spacing:0;text-transform:none;opacity:.7;margin-top:3px}
input,textarea{width:100%;min-height:var(--cible);padding:12px 13px;border:3px solid var(--trait);border-radius:0;
  background:var(--papier);color:var(--encre);font-family:Fig,sans-serif;font-size:1.05rem;font-weight:600}
input:focus,textarea:focus{outline:none;background:#fff9e6;box-shadow:4px 4px 0 var(--indigo)}
input:focus-visible,textarea:focus-visible,button:focus-visible,a:focus-visible{outline:3px solid var(--verm);outline-offset:2px}
textarea{min-height:86px;resize:vertical}
.erreur{background:var(--verm);color:#fff;border:3px solid var(--trait);padding:13px;font-weight:800;margin:14px 0}
.zones{display:grid;gap:10px}
.zones button{display:flex;align-items:center;justify-content:space-between;gap:12px;text-align:left}
.tarif{font-family:Arch;font-weight:900}
.delai{display:block;font-family:Fig,sans-serif;font-size:.74rem;font-weight:500;opacity:.72}
.detail-prix{background:var(--creme);border:3px solid var(--trait);padding:14px;display:grid;gap:9px;margin-top:18px}
.detail-prix div{display:flex;justify-content:space-between;gap:12px;font-size:.92rem;font-weight:700}
.detail-prix .total{border-top:2px solid var(--trait);padding-top:10px;font-family:Arch;font-weight:900;text-transform:uppercase}
.detail-prix .total b{font-size:1.5rem}
.recap{background:var(--creme);border:3px solid var(--trait);padding:14px;display:grid;gap:10px}
.recap-ligne{display:flex;justify-content:space-between;gap:12px;font-weight:700}
/* Le montant ne se coupe pas. Sans cela, un nom de produit un peu long pousse
   le prix et « 2 500 » part d'un côté, « F » de l'autre : le franc a l'air
   d'une légende au lieu d'appartenir au nombre. Le nom, lui, peut se replier —
   c'est lui qui a de la place à céder. La console a tranché pareil. */
.recap-ligne>strong,.recap-ligne .recap-total{white-space:nowrap}
.recap-ligne>span:first-child{min-width:0}
.recap-total{font-family:Arch;font-size:1.5rem;font-weight:900}
.frise{list-style:none;margin:22px 0 0;padding:0}
.frise li{display:flex;gap:13px;padding:0 0 18px;position:relative}
.frise li:not(:last-child)::before{content:'';position:absolute;left:14px;top:32px;bottom:0;width:3px;background:var(--trait)}
.puce{width:32px;height:32px;flex:none;display:grid;place-items:center;font-family:Arch;font-weight:900;
  background:var(--papier);border:3px solid var(--trait)}
.frise li[data-fait="oui"] .puce{background:var(--indigo);color:#fff}
.frise-texte{font-weight:800;padding-top:4px}
.presentes{margin-top:26px}
.presentes h2{font-family:Arch;font-size:1rem;font-weight:900;letter-spacing:.04em;text-transform:uppercase;margin:0 0 3px}
.presentes .sous{font-size:.82rem;opacity:.72;margin:0 0 12px}
.rangee{display:grid;grid-auto-flow:column;grid-auto-columns:136px;gap:10px;overflow-x:auto;
  scroll-snap-type:x proximity;padding-bottom:8px;margin:0 calc(-1*var(--m));padding-left:var(--m);padding-right:var(--m)}
.carte-p{scroll-snap-align:start;text-align:left;cursor:pointer;background:var(--papier);border:3px solid var(--trait);
  border-radius:0;padding:0;overflow:hidden;display:flex;flex-direction:column;font-family:inherit}
.carte-p[aria-pressed="true"]{box-shadow:4px 4px 0 var(--indigo)}
.carte-p img,.carte-p .vide{width:100%;aspect-ratio:1;object-fit:cover;display:block;background:var(--creme)}
.carte-p .nom{font-size:.8rem;font-weight:800;padding:7px 8px 2px;line-height:1.25;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.carte-p .prix-p{font-family:Arch;font-size:.92rem;font-weight:900;padding:0 8px 8px}
.retour-direct{display:flex;align-items:center;gap:10px;background:var(--verm);color:#fff;border:3px solid var(--trait);
  border-radius:0;padding:11px 13px;margin:0 0 14px;font-family:Arch;font-size:.82rem;font-weight:900;
  text-transform:uppercase;width:100%;min-height:52px;cursor:pointer;text-align:left}
.note{font-size:.8rem;opacity:.7;margin-top:18px}
.pied{margin-top:26px;padding-top:16px;border-top:3px solid var(--trait);font-size:.76rem;line-height:1.5;opacity:.75;display:grid;gap:6px}
.centre{text-align:center}
.conditions{margin-top:18px;padding:14px;background:var(--creme);border:2px solid var(--trait);
  font-size:.78rem;line-height:1.5;white-space:pre-wrap;max-height:168px;overflow-y:auto}
/* Mise à l'antenne. Le seul mouvement de la page, parce que c'est le seul
   instant qui compte : le vendeur annonce un article, la page le dit aussi.
   L'état par défaut est déjà visible — sans JavaScript, rien n'est masqué. */
@keyframes revele{from{opacity:0;transform:scale(1.03);filter:blur(10px)}}
@keyframes monte{from{opacity:0;transform:translateY(12px)}}
#zone-produit.entre .galerie{animation:revele .5s cubic-bezier(.16,1,.3,1) both}
#zone-produit.entre .galerie+.corps>*{animation:monte .45s cubic-bezier(.16,1,.3,1) both}
#zone-produit.entre .galerie+.corps>:nth-child(2){animation-delay:.04s}
#zone-produit.entre .galerie+.corps>:nth-child(3){animation-delay:.08s}
#zone-produit.entre .galerie+.corps>:nth-child(n+4){animation-delay:.12s}

@media (prefers-reduced-motion:reduce){
  .pastille{animation:none}
  #zone-produit.entre .galerie,
  #zone-produit.entre .galerie+.corps>*{animation:none}
  *{scroll-behavior:auto !important}
}

/* ─── règles reprises des attributs `style` ──────────────────────────────────
 *
 * Elles vivaient en ligne dans les gabarits, et la CSP de `server.ts` les
 * bloquait TOUTES depuis le premier jour : `style-src 'self'` autorise une
 * feuille servie par cette origine, jamais un attribut `style`. Le commentaire
 * qui accompagne cette CSP affirmait « tout le style est servi depuis cette
 * origine » — ce n'était pas vrai, et c'est pourquoi personne ne l'a vu.
 *
 * Deux d'entre elles désignaient `--accent-doux` et `--encre-douce`, qui
 * n'existent pas ici : ce sont les variables de la console. Mortes deux fois.
 * Trois autres étaient redondantes (`.vendeur` est une grille `auto 1fr` et
 * pose déjà `min-width:0` sur son enfant) et ont simplement disparu. */

/* Écrans qui ne montrent qu'un message : live terminé, live à venir, panne,
   lien périmé. Deux valeurs parce qu'il y a deux situations — sous un en-tête
   vendeur, ou seul sur la page, où il faut compenser son absence. */
.ecran-message{padding-top:48px}
.ecran-seul{padding-top:56px}

/* Un lien qui a l'allure d'un bouton doit se centrer comme un bouton. Sans
   cela le texte se colle en haut à gauche de la boîte. */
a.principal,a.secondaire{display:flex;align-items:center;justify-content:center;
  text-decoration:none;line-height:1.2}

/* Deux respirations, nommées par ce qu'elles valent et pas par où elles
   servent : elles servent à quatre endroits sans rapport entre eux. */
.espace{margin-top:20px}
.espace-petit{margin-top:10px}

/* Le nom du produit dit à voix haute par le vendeur. Seul `audio` de la page. */
audio{width:100%;margin-top:10px}

/* Le récapitulatif pendant que Wave confirme : un fond distinct de l'état
   normal, sinon rien ne signale que ce n'est pas encore acquis. */
.recap-attente{background:var(--ocre-doux)}

/* Le wolof sous l'étape de livraison. En `rem` et non en pixels : la page doit
   tenir à 200 % de taille de police, et 14px n'y obéit pas. */
.frise-wolof{display:block;font-size:.82rem;font-weight:400;color:var(--gris)}

/* La dernière ligne du récapitulatif, détachée par un filet. */
.recap-ligne.total{border-top:1px solid var(--trait);padding-top:10px}

/* Le bandeau « vous regardez un produit déjà présenté », injecté par live.js :
   il se colle à la galerie qui le suit, donc pas de marge basse. En ligne, il
   était bloqué par la CSP comme les autres. */
.corps.sans-bas{padding-bottom:0}
/* La ligne de livraison : moins appuyée que les articles, parce qu'elle n'est
   pas de la marchandise — mais présente, parce que sans elle le total ne
   s'explique pas. 1 000 F manquaient à l'appel sur 51 commandes. */
.recap-ligne.livraison{font-weight:600;color:var(--gris)}
.recap-ligne.livraison>strong{font-weight:700}
