/* ---------- fonts.css ---------- */
/* Couches CSS (lot 5a). « site » contient toutes les feuilles, dans leur
   ordre de chargement ; « surcouches » vient après et l'emporte sur elle
   quelle que soit la spécificité : elle remplace les !important de
   catalog-compact.css et photos.css. Cette ligne doit précéder toute règle
   en couche, et fonts.css est la première feuille de chaque page. */
@layer site, surcouches;

/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* ============================================================
   Kabana Pizz — polices auto-hébergées
   ============================================================

   Les deux familles étaient chargées depuis fonts.googleapis.com, avec
   deux `preconnect` vers Google en tête de chaque page. Conséquence : à
   la toute première requête, avant le moindre contenu, le navigateur du
   visiteur contactait Google et lui transmettait son adresse IP, son
   agent utilisateur et le référent — sans consentement, et sans que la
   fonctionnalité en tire le moindre bénéfice.

   Les fichiers sont maintenant servis par le site lui-même, depuis
   /fonts/. Aucun tiers n'est contacté pour afficher une page, ce qui
   permet de resserrer la CSP sur `font-src 'self'` et `style-src 'self'`
   — deux autorisations vers Google en moins.

   Ce sont les fichiers .woff2 VARIABLES de Google Fonts (SIL Open Font
   License 1.1 pour les deux familles), sous-ensembles `latin` et
   `latin-ext` seulement : le site est en français, les jeux cyrillique,
   grec et vietnamien ne servaient à rien et pesaient le double.

   Un fichier variable par sous-ensemble remplace les quatre graisses
   statiques que demandait l'ancienne URL : 196 Ko au total, contre huit
   requêtes vers un tiers.

   `font-display: swap` est conservé tel quel : le texte reste lisible
   pendant le chargement, avec la police de repli déclarée dans
   css/tokens.css.

   Lot 6 : « œ » et « Œ » (U+0152-0153 : œufs, bœuf) figuraient dans les
   deux plages, latin et latin-ext. Le navigateur télécharge chaque police
   dont la plage croise le texte de la page : il prenait donc aussi
   inter-latin-ext (85 Ko, le plus gros fichier de l'accueil) pour deux
   lettres que la police latine contient déjà. Elles sont retirées de la
   plage latin-ext.
   ============================================================ */

/* Bricolage Grotesque — titres (var(--font-display)), graisses 500 à 800 */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 500 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/bricolage-grotesque-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;
}

@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 500 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/bricolage-grotesque-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-0151, U+0154-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;
}

/* Inter — texte courant (var(--font-body)), graisses 400 à 700 */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/inter-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;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-0151, U+0154-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;
}

} /* fin de @layer site */

/* ---------- tokens.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* ============================================================
   Kabana Pizz — Design tokens
   ============================================================
   Source unique des couleurs, échelles et rythmes du produit.
   Aucune valeur brute (#hex, px d'espacement) ne doit être écrite
   ailleurs : si une valeur manque ici, on l'ajoute ici.

   Contraste : chaque couleur de texte est annotée de son ratio
   mesuré sur --color-bg. Le seuil retenu est WCAG 2.2 AA, soit
   4.5:1 pour le texte courant et 3:1 pour les éléments non
   textuels (bordures d'état, icônes porteuses de sens).
   ============================================================ */

:root {

  /* ---------- Couleurs de fond ---------- */

  --color-bg: #fffdf8;            /* papier, fond de page */
  --color-bg-warm: #fff5e8;       /* aplat chaud, sections alternées */
  --color-surface: #ffffff;       /* cartes, panneaux, modales */
  --color-surface-sunken: #fbf5ec;/* champs, pistes de sélecteur */
  --color-overlay: rgba(36, 20, 14, 0.5);

  /* ---------- Couleurs de texte ---------- */

  --color-text: #24140e;          /* 17.49:1 — titres et texte principal */
  --color-text-muted: #6b5449;    /*  6.91:1 — descriptions, métadonnées */
  --color-text-subtle: #7d6558;   /*  5.34:1 — mentions discrètes, hints */
  --color-text-invert: #ffffff;

  /* ---------- Marque et actions ---------- */

  /* Le rouge historique (#e83f27) plafonnait à 4.06:1 avec du texte
     blanc : le bouton principal du site échouait au contraste. Cette
     version assombrie garde l'identité et passe AA dans les deux sens
     (5.05:1 en fond, 4.97:1 en texte sur papier). */
  --color-primary: #cf3418;
  --color-primary-hover: #b32810;
  --color-primary-active: #9b220d;
  /* Aplat de teinte, fonds de badge et d'onglet actif. Il portait #fdeae5,
     sur lequel le rouge ne tenait que 4.35:1 : relevé par
     tests/tokens.test.js (lot 5). Un cran plus clair, il tient 4.54:1. */
  --color-primary-soft: #fef0ec;

  /* ---------- Couleurs de marque des réseaux ----------
     Elles n'appartiennent pas à la palette du site : ce sont les couleurs
     officielles des plateformes, et elles ne servent qu'au survol des icônes
     du pied de page. Elles vivent ici quand même, parce que la règle du
     dépôt est qu'aucun hexadécimal ne s'écrit ailleurs.
     Le jaune Snapchat ne porte pas de blanc (1.1:1) : le logo passe en
     encre foncée sur ce fond, d'où la seconde variable. */
  --color-social-instagram: #c13584;
  --color-social-tiktok: #010101;
  --color-social-snapchat: #fffc00;
  --color-social-snapchat-ink: #24140e;
  --color-social-facebook: #0866ff;
  --color-primary-border: rgba(207, 52, 24, 0.28);
  --color-primary-ghost: rgba(207, 52, 24, 0.06);  /* filigrane décoratif,
                                     jamais derrière du texte à lire */

  --color-accent: #ffbc32;        /* fromage — décor et surlignage seulement,
                                     jamais en couleur de texte */

  /* ---------- États sémantiques ---------- */

  --color-success: #116b40;       /* 6.45:1 */
  --color-success-soft: #e4f3ea;
  --color-warning: #8a5200;       /* 6.28:1 */
  --color-warning-soft: #fdf0d8;
  --color-danger: #b32810;        /* 6.40:1 */
  --color-danger-soft: #fdeae7;
  --color-info: #1f5d8c;          /* 6.88:1 (annoncé 6.09 jusqu'au lot 5 : faux) */
  --color-info-hover: #184a70;
  --color-info-soft: #e6f0f8;

  /* ---------- Traits ---------- */

  --color-border: #e8ddd0;
  --color-border-strong: #d2c0ad; /* séparateurs appuyés — décor, pas contour */
  /* Contour des champs de saisie. --color-border-strong ne fait que 1.74:1
     sur le papier : un champ vide ne se distinguait pas assez de la page,
     sous les 3:1 qu'exige WCAG 1.4.11 pour repérer un composant (constat de
     la maquette du lot 5). 3.50:1 sur papier, 3.28:1 sur un fond en creux. */
  --color-border-field: #998474;
  /* QR code : noir sur blanc quel que soit le thème, un lecteur l'exige. */
  --color-qr-fond: #ffffff;
  --color-qr-module: #000000;
  --color-focus: #0d5aa8;         /* bleu franc : lisible sur papier comme
                                     sur les aplats rouges et verts */
  /* Anneau de focus unique (lot 5a). Il y en avait cinq : bleu de 3 px,
     tomate de 2 px dans le back-office, accent du Kabanito, rouge du
     sélecteur de quantité, rouge danger de la suppression de compte. Le
     rouge disparaissait sur les boutons rouges ; un seul anneau, partout,
     se reconnaît sans réfléchir. */
  --focus-width: 3px;
  --focus-offset: 2px;
  --focus-ring: var(--focus-width) solid var(--color-focus);

  /* ---------- Teintes de composants (surtout le back-office) ----------
     Elles vivaient en dur dans admin.css (78 hexadécimaux, 66 rgba(),
     CODE-02). Chacune garde sa valeur exacte : le rangement ne devait rien
     changer à l'écran, ce que vérifie une comparaison pixel par pixel. Les
     transparences s'écrivent à l'usage avec color-mix() sur ces bases. */

  --color-text-emphasis: #5b4034;   /* 9.27:1 — mention à ne pas manquer (allergènes détectés) */
  --color-primary-light: #e04023;   /* haut du dégradé des boutons principaux */
  --color-primary-glow: #e8722f;    /* fin de la barre de progression */
  --color-ink-raised: #3a2318;      /* haut du dégradé des boutons sombres */
  --color-success-light: #158a52;   /* haut du dégradé de l'interrupteur actif */
  --color-shadow-ink: #3a1e12;      /* teinte des ombres du back-office */
  --color-glass: #fffaf3;           /* barre supérieure translucide */
  --color-glass-warm: #fffbf5;      /* barre d'onglets translucide */
  --color-status-prep: #a8430f;     /* statut « en préparation » */

  /* Étiquettes : catégorie de produit, ingrédients d'une fiche. */
  --color-tag-bg: #fff0d4;
  --color-tag-border: #f0d8b8;
  --color-tag-text: #6b4416;
  --color-tag-label: #8a5a1a;

  /* Encadrés de formulaire : enregistrement réussi, base à migrer. */
  --color-note-success-bg: #e8f6ea;
  --color-note-success-border: #bcdfc3;
  --color-note-success-text: #205c2c;
  --color-note-warning-bg: #fff6ec;
  --color-note-warning-border: #f0c9a8;
  --color-note-warning-accent: #e07a2f;
  --color-note-warning-text: #6b3d18;
  --color-note-warning-title: #8a4a15;

  /* Site public : ombres et fonds de photo. */
  --color-shadow-warm: #3c2012;     /* teinte des ombres des cartes produit */
  --color-text-shadow: #000000;     /* ombre portée du texte posé sur la vidéo d'accueil */
  --color-photo-glow: #fff7ec;      /* centre du fond d'une photo absente */
  --color-photo-edge: #f3e6d6;      /* bord du même fond */
  --color-photo-edge-light: #f6eee4;
  --color-photo-bg: #f7efe6;        /* vignette en attente de sa photo */
  --color-photo-frame: #fff9f0;

  /* Uber Eats : couleurs officielles du bouton de commande, comme celles
     des réseaux plus haut — hors palette du site, rangées ici pour que
     rien ne s'écrive en dur ailleurs. Texte foncé sur le vert (contraste). */
  --color-brand-ubereats: #06c167;
  --color-brand-ubereats-hover: #05a659;
  --color-brand-ubereats-ink: #05261a;

  /* Ticket imprimé : noir sur blanc, quel que soit l'écran. */
  --color-print-ink: #000000;
  --color-print-muted: #444444;
  --color-print-rule: #bbbbbb;
  --color-print-accent: #1b2f6b;

  /* ---------- Typographie ---------- */

  --font-display: "Bricolage Grotesque", "Inter", system-ui, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, sans-serif;

  /* Chiffres et chemins techniques rendus tels qu'ils s'écrivent : la
     trace serveur du 404, et tout ce qui doit s'aligner colonne par
     colonne. Le back-office portait déjà sa propre pile, hors tokens. */
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;

  /* Échelle typographique. Le plancher est 0.8125rem (13px) : la carte
     produit descendait à 8.96px, illisible sur le device prioritaire. */
  --text-xs: 0.8125rem;   /* 13px — métadonnées, unités */
  --text-sm: 0.875rem;    /* 14px — descriptions produit */
  --text-base: 1rem;      /* 16px — texte courant, champs de saisie */
  --text-lg: 1.125rem;    /* 18px — titres de carte */
  --text-xl: 1.375rem;    /* 22px */
  --text-2xl: 1.75rem;    /* 28px — titres de section */
  --text-3xl: 2.25rem;    /* 36px — titre de page */
  --text-4xl: 2.75rem;    /* 44px — hero desktop */

  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-normal: 1.55;

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-black: 800;

  /* ---------- Espacement (base 4px) ---------- */

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;

  /* ---------- Rayons ---------- */

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 22px;
  --radius-pill: 999px;

  /* ---------- Ombres ---------- */

  /* Volontairement légères : le brief proscrit les ombres lourdes.
     Elles servent à décoller, pas à décorer. */
  --shadow-xs: 0 1px 2px rgba(60, 32, 18, 0.06);
  --shadow-sm: 0 2px 6px rgba(60, 32, 18, 0.07);
  --shadow-md: 0 6px 18px rgba(60, 32, 18, 0.09);
  --shadow-lg: 0 14px 36px rgba(60, 32, 18, 0.13);

  /* ---------- Zones tactiles et contrôles ---------- */

  /* WCAG 2.2 — 2.5.8 Target Size (Minimum) exige 24px. On tient 44px,
     seuil confortable au pouce et recommandation AAA (2.5.5). */
  --tap-min: 44px;
  /* Barre d'onglets mobile (lot 5f) : icône de 24 px et libellé de 13 px
     tiennent dans 56 px, au-dessus de la zone du geste d'accueil. */
  --tabbar-height: 56px;
  --control-height: 48px;
  --control-height-sm: 38px;
  --calendar-width: 384px;
  --chart-height: 112px;
  --border-width: 1px;

  /* ---------- Mouvement ---------- */

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --duration-fast: 120ms;
  --duration-base: 200ms;
  --duration-slow: 320ms;

  /* ---------- Gabarit ---------- */

  --content-max: 1180px;   /* largeur maximale des grilles */
  --prose-max: 68ch;       /* longueur de ligne confortable en lecture */
  --page-gutter: var(--space-4);

  /* ---------- Empilement ---------- */

  --z-base: 1;
  --z-sticky: 50;
  --z-header: 100;
  --z-overlay: 200;
  --z-drawer: 210;
  --z-toast: 300;
  --z-modal: 400;
}

/* ---------- Mode sombre du back-office (lot 5d) ----------
   Pour le service du soir, posé par le bouton « Mode sombre » d'admin.html
   (data-theme="sombre" sur <html>). Le site public ne s'en sert pas.
   Mêmes noms, autres valeurs : aucune règle d'admin.css ne change.
   Les rouges et les verts s'éclaircissent pour rester lisibles en texte
   sur fond sombre ; le texte posé sur eux passe donc en encre foncée
   (--color-text-invert). Contrastes vérifiés par tests/tokens.test.js. */
:root[data-theme="sombre"] {
  color-scheme: dark;

  --color-bg: #17110e;
  --color-bg-warm: #1c1511;
  --color-surface: #261d18;
  --color-surface-sunken: #1e1612;
  --color-overlay: rgba(0, 0, 0, 0.62);

  --color-text: #f6ece4;
  --color-text-muted: #d2bfb1;
  --color-text-subtle: #bba596;
  --color-text-invert: #1a0d08;

  --color-primary: #ff8a6b;
  --color-primary-hover: #ffa088;
  --color-primary-active: #ffb6a2;
  --color-primary-soft: #3b1d15;
  --color-primary-border: rgba(255, 138, 107, 0.35);
  --color-primary-ghost: rgba(255, 138, 107, 0.08);

  --color-success: #72d49e;
  --color-success-soft: #15291e;
  --color-warning: #f2b65c;
  --color-warning-soft: #2f2310;
  --color-danger: #ff8f7f;
  --color-danger-soft: #3b1a16;
  --color-info: #8fc5f0;
  --color-info-hover: #b2d7f5;
  --color-info-soft: #152737;

  --color-border: #3b2f28;
  --color-border-strong: #4f4037;
  --color-border-field: #8c786a;
  --color-focus: #7cb9ff;

  --color-text-emphasis: #f2d4c1;
  --color-primary-light: #ffa58e;
  --color-primary-glow: #ffab70;
  --color-ink-raised: #fffaf5;
  --color-success-light: #93e3b6;
  --color-shadow-ink: #000000;
  --color-glass: #241b16;
  --color-glass-warm: #271e18;
  --color-status-prep: #ffa477;

  --color-tag-bg: #33250f;
  --color-tag-border: #503b20;
  --color-tag-text: #f4d19c;
  --color-tag-label: #e9bf7e;

  --color-note-success-bg: #13281b;
  --color-note-success-border: #2c5337;
  --color-note-success-text: #a2e1b4;
  --color-note-warning-bg: #2d1e11;
  --color-note-warning-border: #5b3b1f;
  --color-note-warning-accent: #f0a262;
  --color-note-warning-text: #f6c99c;
  --color-note-warning-title: #f8ba7b;
}

@media (min-width: 768px) {
  :root { --page-gutter: var(--space-6); }
}

@media (min-width: 1024px) {
  :root { --page-gutter: var(--space-8); }
}

/* Le mouvement décoratif est neutralisé à la source : les durées
   passent à zéro, donc toute transition écrite avec ces tokens est
   désactivée sans avoir à la lister une par une. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0.01ms;
    --duration-base: 0.01ms;
    --duration-slow: 0.01ms;
  }
}

} /* fin de @layer site */

/* ---------- base.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* ============================================================
   Kabana Pizz — Socle et primitives
   ============================================================
   Reset, typographie et composants transverses : boutons, champs,
   cartes, badges, statuts, modales, notifications, états vides et
   de chargement.

   Ces primitives sont partagées par le site public et le back-office.
   Elles n'ont aucune connaissance de la page qui les utilise : rien
   ici ne doit dépendre d'un identifiant ou d'une section précise.

   Avant ce fichier, .btn, .form-error et .status-chip étaient écrits
   deux fois — dans style.css et dans admin.css — avec des valeurs
   divergentes. C'est cette duplication que le fichier remplace.

   Dépend de : tokens.css
   ============================================================ */

/* ============================================================
   1. Reset et socle
   ============================================================ */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* Compense le header collant lors d'un saut d'ancre : sans cela le
     titre de section atterrit derrière la barre fixe. */
  scroll-padding-top: var(--header-offset, 80px);
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  letter-spacing: -0.02em;
}

h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-lg); }

p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

img,
svg,
video,
iframe {
  display: block;
  max-width: 100%;
}

img { height: auto; }

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

a { color: var(--color-primary); }

ul, ol { margin: 0 0 var(--space-4); padding-left: var(--space-5); }

/* Masquage accessible : invisible à l'écran, lu par les technologies
   d'assistance. Sert aux libellés que le visuel rend redondants. */
.visually-hidden {
  /* stylelint-disable-next-line declaration-no-important -- un composant ne doit jamais
     remettre dans le flux un texte réservé aux lecteurs d'écran. */
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Lien d'évitement — WCAG 2.4.1 Bypass Blocks. */
.skip-link {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: var(--z-modal);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-text);
  color: var(--color-text-invert);
  font-weight: var(--weight-bold);
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform var(--duration-fast) var(--ease-out);
}

.skip-link:focus { transform: translateY(0); }

/* ============================================================
   2. Focus
   ============================================================
   Un seul style de focus pour tout le produit, en bleu : sur les
   surfaces rouges (bouton principal, badges) un halo rouge serait
   invisible. Visible au clavier uniquement — :focus-visible — pour
   ne pas parasiter le clic à la souris. */

:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-sm);
}

:focus:not(:focus-visible) { outline: none; }

/* ============================================================
   3. Boutons
   ============================================================
   Trois variantes seulement : primary (l'action de la page),
   outline (action secondaire), ghost (action tertiaire ou en
   barre d'outils). Toute autre intention passe par un token
   d'état, pas par une nouvelle variante. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--control-height);
  padding: 0 var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: none;
  color: inherit;
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  line-height: 1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
}

.btn:active { transform: scale(0.98); }

.btn[disabled],
.btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

.btn-primary {
  background: var(--color-primary);
  color: var(--color-text-invert);
  box-shadow: var(--shadow-sm);
}

.btn-primary:hover:not([disabled]) { background: var(--color-primary-hover); }
.btn-primary:active:not([disabled]) { background: var(--color-primary-active); }

.btn-outline {
  border-color: var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text);
}

.btn-outline:hover:not([disabled]) {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* Bouton d'action destructrice. La seule du site : la suppression de compte
   (compte.html). Il porte la couleur d'alerte en plein, et non en contour,
   parce qu'à ce stade l'utilisateur a déjà déplié un panneau, saisi son mot de
   passe et tapé « SUPPRIMER » — le bouton doit confirmer ce qu'il fait, pas le
   dissimuler. */
.btn-danger {
  border-color: var(--color-danger);
  background: var(--color-danger);
  color: var(--color-text-invert);
}

.btn-danger:hover:not([disabled]) {
  filter: brightness(0.92);
}

.btn-ghost {
  background: transparent;
  color: var(--color-text-muted);
}

.btn-ghost:hover:not([disabled]) {
  background: var(--color-surface-sunken);
  color: var(--color-text);
}

.btn-block {
  display: flex;
  width: 100%;
}

.btn-sm {
  min-height: var(--control-height-sm);
  padding: 0 var(--space-4);
  font-size: var(--text-sm);
}

/* État de chargement : le libellé reste en place (pas de saut de
   largeur) et un anneau tourne à sa gauche. aria-busy porte
   l'information pour les lecteurs d'écran. */
.btn[aria-busy="true"] {
  pointer-events: none;
  opacity: 0.75;
}

.btn[aria-busy="true"]::before {
  content: "";
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: kb-spin 700ms linear infinite;
}

@keyframes kb-spin { to { transform: rotate(360deg); } }

/* Bouton icône carré — fermeture de tiroir, navigation de calendrier. */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--text-xl);
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out);
}

.icon-btn:hover {
  background: var(--color-surface-sunken);
  color: var(--color-text);
}

/* Bouton présenté comme un lien — « Mot de passe oublié ? ». Garde une
   zone tactile réelle malgré son apparence textuelle. */
.link-btn {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-primary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

/* ============================================================
   4. Champs de formulaire
   ============================================================
   La taille de police des champs est verrouillée à 16px : en
   dessous, iOS zoome automatiquement à la mise au point et casse
   la mise en page. */

.field,
.setting-field,
.auth-form label,
.checkout-form label,
.contact-form label {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.field-label { font-weight: var(--weight-semibold); }

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="password"],
input[type="search"],
input[type="number"],
input[type="date"],
select,
textarea {
  width: 100%;
  min-height: var(--control-height);
  padding: var(--space-3) var(--space-4);
  /* Contour à 3.5:1 : le beige précédent (1.74:1) laissait un champ vide
     se fondre dans la page (WCAG 1.4.11). */
  border: 1px solid var(--color-border-field);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--text-base);
  font-weight: var(--weight-regular);
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}

textarea {
  min-height: 5rem;
  line-height: var(--leading-snug);
  resize: vertical;
}

select {
  appearance: none;
  padding-right: var(--space-10);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%236b5449' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  background-size: 12px;
}

input:hover:not([disabled]),
select:hover:not([disabled]),
textarea:hover:not([disabled]) { border-color: var(--color-text-subtle); }

input:focus,
select:focus,
textarea:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-soft);
}

input[disabled],
select[disabled],
textarea[disabled] {
  background: var(--color-surface-sunken);
  color: var(--color-text-subtle);
  cursor: not-allowed;
}

/* :user-invalid plutôt que :invalid : n'alerte qu'après une vraie
   tentative de saisie, pas au chargement du formulaire vide. */
input:user-invalid,
select:user-invalid,
textarea:user-invalid {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px var(--color-danger-soft);
}

.field-hint {
  color: var(--color-text-subtle);
  font-size: var(--text-xs);
  font-weight: var(--weight-regular);
}

/* Piège à robots : hors flux et hors ordre de tabulation, jamais
   présenté à l'utilisateur ni annoncé. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Interrupteur libellé — « Disponible à la commande ». */
.switch-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap-min);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
}

.switch-row input[type="checkbox"],
/* ============================================================
   5. Messages d'état
   ============================================================
   Couleur + icône + texte : jamais la couleur seule (WCAG 1.4.1).
   role="alert" / role="status" est porté par le HTML. */

.form-error,
.form-success {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.form-error {
  background: var(--color-danger-soft);
  color: var(--color-danger);
}

.form-success {
  background: var(--color-success-soft);
  color: var(--color-success);
}

.form-error::before { content: "⚠"; }
.form-success::before { content: "✓"; }

/* [hidden] doit l'emporter sur l'affichage flex/grid de ces blocs. */
/* stylelint-disable-next-line declaration-no-important -- hidden doit masquer, même face à
   un display posé par un composant. */
[hidden] { display: none !important; }

/* ============================================================
   6. Cartes et panneaux
   ============================================================ */

.surface,
.panel {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.panel {
  padding: var(--space-5);
  box-shadow: var(--shadow-xs);
}

/* ============================================================
   7. Badges, puces et statuts
   ============================================================ */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  line-height: 1.4;
  white-space: nowrap;
}

/* Statuts de commande — partagés entre le back-office et l'historique
   client, donc définis ici et pas dans admin.css.

   Chaque statut porte une pastille en préfixe : la forme et le texte
   suffisent à le distinguer si la couleur n'est pas perçue (WCAG 1.4.1). */
.status-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid currentColor;
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  white-space: nowrap;
}

.status-chip::before {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}

.status-pending   { background: var(--color-warning-soft); color: var(--color-warning); }
.status-confirmed { background: var(--color-info-soft);    color: var(--color-info); }
.status-in_prep   { background: var(--color-primary-soft); color: var(--color-primary); }
.status-delivered { background: var(--color-surface-sunken); color: var(--color-text-muted); }
.status-cancelled { background: var(--color-danger-soft);  color: var(--color-danger); }

/* « Prêt » est le statut qu'on cherche du regard en cuisine : il est
   le seul à porter un aplat plein, pour se détacher de la liste. */
.status-ready {
  border-color: transparent;
  background: var(--color-success);
  color: var(--color-text-invert);
}

/* Puce de filtre — alternative tactile au menu déroulant. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

.chip:hover { border-color: var(--color-text-subtle); color: var(--color-text); }

.chip[aria-pressed="true"] {
  border-color: transparent;
  background: var(--color-text);
  color: var(--color-text-invert);
}

/* ============================================================
   8. Modales et superpositions
   ============================================================ */

.overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--color-overlay);
}

.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: var(--color-overlay);
}

/* ============================================================
   9. Notifications
   ============================================================ */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--space-6) + env(safe-area-inset-bottom));
  z-index: var(--z-toast);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  max-width: calc(100vw - var(--space-8));
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-pill);
  background: var(--color-text);
  color: var(--color-text-invert);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  box-shadow: var(--shadow-lg);
  transform: translate(-50%, 0);
  opacity: 0;
  pointer-events: none;
  transition:
    opacity var(--duration-base) var(--ease-out),
    transform var(--duration-base) var(--ease-out);
}

.toast.show {
  opacity: 1;
  transform: translate(-50%, calc(-1 * var(--space-2)));
}

/* ============================================================
   10. États vides, chargement, indisponibilité
   ============================================================ */

.empty-state {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  padding: var(--space-10) var(--space-4);
  text-align: center;
  color: var(--color-text-muted);
}

.empty-state h3 { color: var(--color-text); }
.empty-state p { margin: 0; font-size: var(--text-sm); }

/* Conservé : plusieurs vues (panier, listes admin) écrivent encore ce
   libellé depuis le JS. Aligné sur .empty-state pour éviter deux
   rendus visuels du même état. */
.cart-empty {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-8) var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  text-align: center;
}

.cart-empty__title {
  margin: 0;
  color: var(--color-text);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
}

.cart-empty__text { margin: 0; }
.cart-empty .btn { margin-top: var(--space-2); }

/* Produit en rupture : grisé, non cliquable, et signalé par un
   libellé — l'opacité seule ne porte pas l'information. */
.is-unavailable {
  opacity: 0.6;
  filter: saturate(0.4);
}

.is-unavailable .add-btn { pointer-events: none; }

/* ============================================================
   11. Utilitaires de gabarit
   ============================================================ */

.container {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

/* ============================================================
   12. Garde-fou mouvement
   ============================================================
   Les durées à zéro (tokens.css) désactivent déjà les transitions
   écrites avec les tokens. Ce bloc neutralise en plus les animations
   en boucle et le défilement fluide, qui ne passent pas par une
   durée variabilisée. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    /* stylelint-disable declaration-no-important -- la demande de mouvement
       réduit l'emporte sur toute animation, quelle que soit sa règle. */
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
    /* stylelint-enable declaration-no-important */
  }
}

/* ============================================================
   13. Gestes d'application (lot 5f)
   ============================================================
   Sur téléphone, un double tap zoomait la page et chaque appui affichait
   le flash bleu du navigateur : deux signes de « site web ». Le retour à
   l'appui vient désormais de :active (boutons, puces, onglets), et le
   zoom au pincement reste possible. */

a, button, input, select, textarea, label, summary { touch-action: manipulation; }
a, button, summary { -webkit-tap-highlight-color: transparent; }

} /* fin de @layer site */

/* Passage d'une page à l'autre (accueil, espace client) en fondu, comme
   dans une application. Navigateurs récents seulement ; ailleurs, la page
   change comme avant. Coupé quand l'appareil demande moins de mouvement.
   Hors couche : cette règle n'entre en concurrence avec aucune autre. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}

/* ---------- site.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* ============================================================
   Kabana Pizz — Site public
   ============================================================
   Remplace css/style.css pour index.html, compte.html, 404.html
   et les pages légales. Charge après tokens.css puis base.css :
   ce fichier ne redéfinit ni .btn, ni les champs, ni .status-chip,
   ni .toast — ils vivent dans base.css.

   Deux choses ont disparu de l'ancien fichier :
   - les 766 lignes de styles admin (style.css:1765-2530), mortes
     depuis qu'admin.html ne charge plus que css/admin.css ;
   - les 400 lignes de rattrapage mobile « 3 produits par ligne »,
     rendues inutiles par une grille pensée mobile d'abord.
   ============================================================ */

/* ============================================================
   1. En-tête
   ============================================================
   L'ancien en-tête empilait une barre de marque et une barre de
   navigation : 124 px de haut sur un écran de 812 px, soit 15 %
   de l'écran occupés en permanence. Une seule rangée désormais,
   et les catégories descendent dans une barre collante propre.
   ============================================================ */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-header);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.site-header.is-scrolled {
  box-shadow: var(--shadow-sm);
}

/* Les pages secondaires posent leur .topbar dans le flux, sans le
   conteneur fixe .site-header : elle doit alors porter elle-meme son
   fond et son filet. */
body:not(:has(.site-header)) .topbar {
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  max-width: none;
  padding-left: max(var(--page-gutter), calc((100vw - var(--content-max)) / 2));
  padding-right: max(var(--page-gutter), calc((100vw - var(--content-max)) / 2));
}

.topbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 56px;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 var(--page-gutter);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-right: auto;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
}

.brand img {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
}

/* Navigation textuelle : réservée au desktop sur l'accueil, où la
   barre de catégories collante prend le relais. Les pages
   secondaires (compte, 404, légales) s'en servent à toutes les
   tailles, elles n'ont pas de barre de catégories. */
.topnav {
  display: none;
  gap: var(--space-1);
}

.topnav a {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
  text-decoration: none;
  white-space: nowrap;
}

.topnav a:hover { background: var(--color-surface-sunken); color: var(--color-text); }

.topnav a.active {
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-weight: var(--weight-semibold);
}

.account-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.account-link:hover { background: var(--color-surface-sunken); color: var(--color-text); }
.account-icon { display: inline-flex; }
.account-label { display: none; }

.cart-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: var(--color-text-invert);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}

.cart-btn:hover { background: var(--color-primary-hover); }
.cart-btn:active { background: var(--color-primary-active); }

.cart-count {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--color-text-invert);
  color: var(--color-primary);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

@media (min-width: 768px) {
  .topbar { min-height: 64px; gap: var(--space-3); }
  .topnav { display: flex; }
  .brand { font-size: var(--text-xl); margin-right: var(--space-4); }
  .brand img { width: 38px; height: 38px; }
  .account-label { display: inline; }
}

/* Sur l'accueil, la navigation textuelle laisse la place à la barre
   de catégories : deux navigations concurrentes sur le même écran
   forcent un arbitrage inutile. */
/* BUG-01 : le seuil était à 1023 px. Entre 1024 et 1120 px, la navigation, la
   pastille d'état, le lien Compte et le bouton Panier mesuraient 1 107 px pour
   1 009 disponibles : le Panier sortait de l'écran de 98 px sur une tablette
   en paysage. La navigation textuelle n'apparaît plus qu'à partir de 1280 px,
   où tout tient, et la barre de catégories s'efface à ce même seuil : une
   seule navigation par largeur, jamais deux. */
@media (max-width: 1279px) {
  .site-header .topnav { display: none; }
  /* Sans navigation pour occuper le milieu, la marge fixe de la marque
     (posée à partir de 768 px) laissait l'état, le compte et le panier
     agglutinés à gauche. La marge automatique les renvoie au bord droit,
     comme sur mobile. */
  .site-header .brand { margin-right: auto; }
}


/* ============================================================
   2. Barre de catégories collante
   ============================================================
   Sort de l'en-tête fixe : l'accueil démarre 68 px plus haut,
   et la barre reste accessible pendant tout le parcours carte.
   ============================================================ */

.catnav {
  position: sticky;
  /* --banner-offset vaut la hauteur du bandeau de fermeture replié, ou
     0 px quand la boutique est ouverte. Sans lui, les deux éléments
     collants se recouvrent. */
  top: calc(var(--header-offset, 56px) + var(--banner-offset, 0px));
  z-index: var(--z-sticky);
  display: flex;
  gap: var(--space-2);
  padding-block: var(--space-2);
  /* Alignée sur la colonne de contenu : le fond reste pleine largeur, mais
     à 1440 px la première puce démarrait au bord de la boîte de contenu
     et non sur son contenu, où vivent la marque et les cartes produit. */
  padding-inline: max(var(--page-gutter), calc((100% - var(--content-max)) / 2 + var(--page-gutter)));
  background: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.catnav::-webkit-scrollbar { display: none; }

/* À partir de 1280 px, la navigation de l'en-tête prend le relais (BUG-01).
   Placé après la règle de base de .catnav : à spécificité égale, c'est
   l'ordre du fichier qui décide. */
@media (min-width: 1280px) {
  .catnav { display: none; }
}

.catnav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-height-sm);
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  white-space: nowrap;
}

.catnav a:hover { border-color: var(--color-border-strong); color: var(--color-text); }

.catnav a.active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-text-invert);
  font-weight: var(--weight-semibold);
}

/* ============================================================
   3. Hero
   ============================================================
   Ancienne version : un titre-slogan rimé de trois lignes, sans le
   mot « pizzeria » ni la ville, qui repoussait la première pizza à
   1055 px. Le H1 dit maintenant ce que vend le commerce et où ;
   le slogan reste, en sous-titre.
   ============================================================ */

/* Pas de marge en haut tant que la pile est verticale : la photo pleine
   largeur se pose directement sous l'en-tete, comme l'affiche d'une
   devanture. Les ~20 px ainsi rendus sont repris sur ce que la photo a coute
   au bouton « Voir la carte », qui doit rester visible sans defiler. */
.hero {
  padding: 0 0 var(--space-5);
  background: var(--color-bg-warm);
  border-bottom: 1px solid var(--color-border);
}

@media (min-width: 768px) {
  .hero { padding-top: var(--space-5); }
}

.hero__inner {
  display: grid;
  gap: var(--space-5);
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 var(--page-gutter);
}

.hero__inner > * { min-width: 0; }

.hero__eyebrow {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-primary);
}

.hero__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
  letter-spacing: -0.02em;
  color: var(--color-text);
  text-wrap: balance;
}

.hero__slogan {
  margin: var(--space-3) 0 0;
  max-width: 44ch;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
}

/* Ces puces défilaient horizontalement : à 375 px, « Paiement sur place »
   commençait à x=204 et se terminait à x=499, donc hors écran, sans aucune
   affordance de défilement. La mention la plus rassurante du hero passait
   inaperçue. Elles reviennent à la ligne. */
.hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

/* padding-inline resserré : à 375 px, le statut d'ouverture (179 px) et
   « Paiement sur place » (167 px) dépassaient de 11 px la largeur utile et
   tombaient sur trois lignes au lieu de deux. */
.hero__fact {
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  white-space: nowrap;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
}

/* Le paiement sur place est la question que se pose tout nouveau
   client, et le brief interdit de laisser croire à un paiement en
   ligne. Il est donc annoncé dès le premier écran, pas seulement
   au récapitulatif. */
.hero__fact--pay {
  border-color: var(--color-success);
  background: var(--color-success-soft);
  color: var(--color-success);
  font-weight: var(--weight-semibold);
}

.hero__fact--pay::before { content: "💶"; }

.hero__cta {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.hero__cta .btn { flex: 1 1 0; min-width: 0; }

/* Le visuel etait masque sous 640 px, pour gagner 170 px avant la premiere
   fiche produit. Le calcul etait juste et la conclusion fausse : sur un
   telephone, ouvrir le lien donnait un titre, un slogan et deux boutons —
   « on ne sait pas que c'est une pizzeria », rapporte le proprietaire. La
   grille de photos censee jouer ce role commence sous le pli, donc apres la
   decision de rester ou de partir.

   La photo passe donc EN PREMIER sur mobile (`order: -1`), pleine largeur,
   comme le fait n'importe quelle enseigne de pizza. En 16/9 elle coute
   environ 200 px : le prix d'une page qui dit ce qu'elle vend. */
.hero__media {
  position: relative;
  order: -1;
  /* Une hauteur, et non un rapport : en 16/9, la photo suivait la largeur et
     atteignait 394 px sur une petite tablette, ou elle remplissait l'ecran a
     elle seule. Un `max-height` sur un `aspect-ratio` retrecit la largeur au
     lieu de recadrer, et laissait un blanc a droite. La bande garde donc les
     proportions d'un 16/9 tant qu'elle tient sous 240 px, puis se recadre. */
  height: clamp(180px, 56vw, 240px);
  margin: 0 calc(var(--page-gutter) * -1);
  overflow: hidden;
  background: var(--color-surface-sunken);
}

/* 768 px, et non 640 : c'est la largeur ou le hero passe en deux colonnes.
   Entre les deux, la pile reste verticale — y remettre la photo apres le
   texte reproduisait le probleme sur une petite tablette. */
@media (min-width: 768px) {
  .hero__media {
    order: 0;
    height: auto;
    margin: 0;
    border-radius: var(--radius-lg);
  }
}

.hero__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
}

/* La vidéo se pose PAR-DESSUS la photo et reste invisible tant que la lecture
   n'est pas commencée (voir attachHeroVideo) : autoplay refusé ou fichier
   illisible, la photo reste, jamais de rectangle noir.

   `object-fit` suffit ici, là où l'ancien lecteur Vimeo — un iframe, donc pas
   un média — demandait de calculer un débordement à la main. */
.hero__media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
  opacity: 0;
  transition: opacity 400ms ease;
  pointer-events: none;
}

.hero__media video.is-playing { opacity: 1; }

/* Le passage en deux colonnes attendait 900 px : entre 768 et 899 le visuel
   restait pleine largeur (720x315) et le hero occupait 613 px, soit 60 % d'un
   écran de tablette avant la première pizza. La tablette a désormais sa vraie
   mise en page, pas un mobile agrandi. */
@media (min-width: 768px) {
  .hero { padding: var(--space-8) 0; }
  .hero__inner {
    grid-template-columns: 1.05fr 0.95fr;
    align-items: center;
    gap: var(--space-6);
  }
  .hero__cta { flex-wrap: wrap; }
  .hero__cta .btn { flex: 0 0 auto; }
  .hero__media { aspect-ratio: 4 / 3; }
}

@media (min-width: 900px) {
  .hero { padding: var(--space-10) 0 var(--space-8); }
  .hero__inner { gap: var(--space-8); }
  .hero__title { font-size: var(--text-4xl); }
  .hero__slogan { font-size: var(--text-lg); }
}

/* Badge ouvert / fermé — l'information la plus périssable de la
   page. La couleur ne porte jamais seule le sens : une pastille
   pleine double le message (WCAG 1.4.1). */
.open-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--weight-semibold);
  color: var(--color-success);
}

.open-badge::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.open-badge.closed { color: var(--color-danger); }

/* ============================================================
   4. Bandeau de fermeture
   ============================================================ */

/* Une bande de 46 px en texte fin passait pour un bandeau de cookies.
   L'information la plus décisive de la page — on ne peut pas commander —
   occupe désormais un bloc qu'on ne saute pas. */
.closed-banner {
  /* Collant sous l'en-tête fixe : l'information disparaissait dès qu'on
     défilait vers la carte. */
  position: sticky;
  top: var(--header-offset, 56px);
  z-index: var(--z-sticky);
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  padding-block: var(--space-6);
  padding-inline: max(var(--page-gutter), calc((100% - var(--content-max)) / 2 + var(--page-gutter)));
  background: var(--color-warning-soft);
  border-bottom: 3px solid var(--color-warning);
  color: var(--color-warning);
  text-align: center;
}

.closed-banner__icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--color-surface);
  font-size: var(--text-2xl);
  line-height: 1;
}

.closed-banner__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
}

.closed-banner__message {
  margin: 0;
  max-width: 42ch;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
}

.closed-banner__hint {
  margin: 0;
  max-width: 46ch;
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  color: var(--color-text-muted);
}

.closed-banner__hint a { color: var(--color-text); }

@media (min-width: 768px) {
  .closed-banner:not(.is-compact) { padding: var(--space-8) var(--page-gutter); }
  .closed-banner:not(.is-compact) .closed-banner__title { font-size: var(--text-2xl); }
}

/* Replié : une seule ligne, le message de l'exploitant reste lisible. */
.closed-banner.is-compact {
  grid-template-columns: auto minmax(0, 1fr);
  justify-items: start;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--page-gutter);
  text-align: left;
}

.closed-banner.is-compact .closed-banner__icon {
  width: 30px;
  height: 30px;
  font-size: var(--text-base);
}

.closed-banner.is-compact .closed-banner__title {
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
}

.closed-banner.is-compact .closed-banner__message {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  font-size: var(--text-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.closed-banner.is-compact .closed-banner__title,
.closed-banner.is-compact .closed-banner__hint { display: none; }

@media (min-width: 560px) {
  .closed-banner.is-compact { grid-template-columns: auto auto minmax(0, 1fr); }
  .closed-banner.is-compact .closed-banner__title { display: block; }
  .closed-banner.is-compact .closed-banner__message { grid-column: 3; }
}

/* ============================================================
   5. Sections de la carte
   ============================================================ */

.menu-section {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-5) var(--page-gutter) var(--space-8);
}

@media (min-width: 768px) {
  .menu-section { padding-top: var(--space-8); }
}

.section-head { margin-bottom: var(--space-4); }

@media (max-width: 559px) {
  .section-head .section-eyebrow { display: none; }
}

.section-eyebrow {
  margin: 0 0 var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-primary);
}

.section-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
}

.section-sub {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* ---------- Recherche globale ----------

   Placée au-dessus des trois sections, pas à l'intérieur des pizzas :
   elle porte sur toute la carte, sa position doit le dire. */

.catalog-search {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-4) var(--page-gutter) 0;
}

.catalog-search__field { position: relative; }

.catalog-search input[type="search"] {
  padding-right: var(--space-12);
  -webkit-appearance: none;
  appearance: none;
}

.catalog-search input[type="search"]::-webkit-search-cancel-button { display: none; }

.search-clear {
  position: absolute;
  right: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
}

.search-clear:hover { background: var(--color-primary-soft); color: var(--color-primary); }

.search-summary {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.search-summary.is-empty {
  padding: var(--space-3);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

/* ---------- Puces de filtre ---------- */

.filter-chips {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}

.filter-chips::-webkit-scrollbar { display: none; }
.filter-chips .chip { flex: none; }

.no-results {
  grid-column: 1 / -1;
  padding: var(--space-8) var(--space-4);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  text-align: center;
  color: var(--color-text-muted);
}

.no-results p { margin: 0 0 var(--space-4); }

/* ============================================================
   6. Grilles et cartes produit
   ============================================================
   Le prix restait masqué par défaut (.card-price { display:none })
   et n'était rendu que par deux media queries tardives. Il est
   maintenant toujours affiché, à toutes les tailles.
   ============================================================ */

.grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

@media (min-width: 560px) { .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); } }
@media (min-width: 900px) { .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.grid-simple { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 640px) { .grid-simple { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .grid-simple { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ---------- Carte pizza ---------- */

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  overflow: hidden;
}

/* Le carre n'est pas un choix esthetique tardif : c'est ce que la carte a
   toujours affiche. Le 4/3 declare ici ne s'appliquait a aucune fiche, parce
   que l'image en flux normal imposait ses propres proportions au conteneur
   (voir la regle suivante) et que TOUTES les photos du depot sont carrees.
   Le ratio est donc aligne sur ce qui etait rendu, pas l'inverse. */
.card-img-wrap {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--color-surface-sunken);
}

.card-img-wrap picture {
  position: absolute;
  inset: 0;
  display: block;
}

/* L'image est sortie du flux, comme le <picture> juste au-dessus.

   En flux normal, son `height: 100%` ne se resolvait pas : le conteneur est
   un element flex dont la hauteur depend de son contenu, donc un pourcentage
   n'a pas de reference et retombe sur `auto`. Chaque photo s'affichait a ses
   proportions naturelles et le bandeau la suivait — le `aspect-ratio`
   ci-dessus ne servait que de plancher.

   Invisible tant que le dossier images/ n'a contenu que des carres. Depuis
   que l'administration accepte des photos envoyees, une photo en 3/2 donnait
   un bandeau de 199 px la ou ses voisines faisaient 265 px : titre, prix et
   bouton d'ajout decales d'une fiche a l'autre sur la meme rangee.

   En absolu, c'est le conteneur qui impose sa forme et `object-fit: cover`
   qui recadre. N'importe quelle photo entre dans le meme gabarit. */
.card-img-wrap > img {
  position: absolute;
  inset: 0;
}

.card-img-wrap img,
.card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.base-chip {
  position: absolute;
  left: var(--space-2);
  bottom: var(--space-2);
  padding: 3px var(--space-2);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--color-surface) 94%, transparent);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-text);
  text-transform: lowercase;
}

.stock-chip {
  position: absolute;
  right: var(--space-2);
  top: var(--space-2);
  padding: 3px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-danger);
  color: var(--color-text-invert);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

.card-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1;
  padding: var(--space-3);
}

.card-title-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
}

.card-title-row h3 {
  margin: 0;
  flex: 1;
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
}

.badge-signature {
  flex: none;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
}

/* 10.88 px auparavant. Le plancher de l'échelle est 13 px. */
.card-ingredients {
  margin: 0;
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  color: var(--color-text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Depuis le retrait de l'encart reglementaire en bas de carte, cette ligne
   est le seul porteur de l'information allergenes avant la commande
   (reglement UE 1169/2011) : elle ne peut plus etre masquee nulle part. La
   liste complete reste dans l'attribut title. */
.card-allergens {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.allergen-tag {
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
}

.card-controls {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-2);
}

/* Le choix de taille a quitté la fiche pour le sélecteur unique en tête de
   section (.size-switch) : la carte n'affiche plus que le prix du format
   courant, rappelé sous le montant pour qu'il reste lisible hors contexte. */
.card-price {
  display: block;
  white-space: nowrap;
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-tight);
}

.card-price small {
  display: block;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-text-subtle);
}

.add-btn {
  display: inline-grid;
  place-items: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border: 0;
  border-radius: 50%;
  background: var(--color-primary);
  color: var(--color-text-invert);
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  line-height: 1;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}

.qty-stepper {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: var(--tap-min);
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--color-primary-soft);
}

.qty-stepper[hidden] { display: none; }

.qty-stepper button {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-primary);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  line-height: 1;
  cursor: pointer;
}

.qty-stepper button:hover { background: var(--color-primary); color: var(--color-text-invert); }

/* Le compteur n'affichait plus qu'un nombre : passer de 1 a 12 demandait
   onze appuis sur « + ». C'est un champ, on peut y taper la quantite —
   sans perdre le pouce sur « + », qui reste le geste courant. */
/* input[type="number"] de base.css porte une largeur de 100 %, une hauteur de
   champ de formulaire et 16 px de padding : sans selecteur d'egale
   specificite, le chiffre sortait du compteur et devenait invisible. */
input.qty-input {
  flex: 0 0 auto;
  width: 44px;
  min-width: 0;
  height: 34px;
  min-height: 0;
  padding: 0 2px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  text-align: center;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  /* Le rouge de marque sur son aplat clair plafonne a 4.35:1 : sous le
     seuil AA. La quantite est une donnee, elle se lit en texte courant. */
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  appearance: textfield;
  transition: border-color var(--duration-fast) var(--ease-out),
              background var(--duration-fast) var(--ease-out);
}

/* Les fleches natives de Chrome doublent les boutons « − » et « + » dans
   40 px de large : elles deviennent inatteignables et brouillent le motif. */
.qty-input::-webkit-outer-spin-button,
.qty-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Sur la vignette, le champ partage la rangée avec le prix : 34 px suffisent
   à deux chiffres, au-delà le prix passait à la ligne. */
input.qty-input--card { width: 34px; }

/* Sous 16 px, iOS zoome sur le champ des qu'on le touche et laisse la page
   agrandie : le client se retrouve a faire defiler lateralement une carte
   qu'il parcourait tres bien. Le pas de 14 px ne vaut que la souris. */
@media (pointer: coarse) {
  input.qty-input { font-size: 16px; }
}

input.qty-input:hover { border-color: var(--color-border-strong); }

input.qty-input:focus {
  outline: none;
  border-color: var(--color-primary);
  background: var(--color-surface);
  box-shadow: none;
}

.qty-input:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

.add-btn[hidden] { display: none; }

/* La fiche accompagnement/boisson est une rangée : ses contrôles ne
   forment pas de grille comme sur la carte pizza. */
.card-simple .card-controls {
  display: flex;
  align-items: center;
  padding: 0;
  margin: 0;
}

.add-btn:hover:not([disabled]) { background: var(--color-primary-hover); }
.add-btn:active:not([disabled]) { transform: scale(0.92); }
.add-btn.added { background: var(--color-success); }
.add-btn[disabled] { background: var(--color-border-strong); cursor: not-allowed; }

/* ---------- Carte simple (accompagnements, boissons) ---------- */

/* min-height : la fiche accompagnement montait a 95 px (ligne allergenes)
   et la fiche boisson tombait à 82 px. Deux hauteurs pour un même composant,
   côte à côte dans la même page. */
.card-simple {
  display: grid;
  grid-template-columns: 72px 1fr auto;
  align-items: center;
  gap: var(--space-3);
  min-height: 96px;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

/* `contain`, et non `cover` : les photos de boissons sont des packshots
   verticaux — une canette fait 609 × 1400. Recadrées en carré, elles ne
   montraient qu'une bande d'étiquette agrandie, où un Perrier et un Canada
   Dry devenaient deux rectangles verts indistincts. La vignette garde sa
   forme carrée pour que la grille reste alignée ; c'est la bouteille qui se
   pose dedans, entière. 72 px et non 56 : sous cette taille, une bouteille
   contenue dans un carré ne fait plus que 25 px de large. */
.card-simple picture,
.card-simple .thumb,
.card-simple .emoji-thumb {
  width: 72px;
  height: 72px;
  border-radius: var(--radius-md);
  object-fit: contain;
  background: var(--color-surface-sunken);
}

/* Fond blanc, et non le fond des champs : les packshots sont détourés sur
   blanc et affichaient sinon leur propre rectangle blanc dans la vignette
   crème. L'emoji, lui, garde le fond crème : c'est ce qui distingue une
   vignette sans photo. Le padding évite que la bouteille touche le bord
   arrondi ; il n'est pas posé sur <picture>, dont l'image fille déborderait
   du carré une fois le contenu rétréci par la marge intérieure. */
.card-simple .thumb {
  padding: var(--space-1);
  background: var(--color-surface);
}

.emoji-thumb {
  display: grid;
  place-items: center;
  font-size: var(--text-2xl);
}

.card-simple .info { min-width: 0; }

.card-simple h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
}

.card-simple .price {
  display: block;
  margin-top: 2px;
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

.stock-inline {
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-danger);
}

/* ============================================================
   7. Infos, horaires, adresse
   ============================================================ */

.infos {
  display: grid;
  gap: var(--space-5);
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-8) var(--page-gutter);
}

@media (min-width: 768px) { .infos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.infos-col {
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.infos-col h2 {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-xl);
}

.infos-col p { font-size: var(--text-sm); color: var(--color-text-muted); }
.infos-col .btn { margin-top: var(--space-3); }

.pay-note {
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-success-soft);
  color: var(--color-success);
  font-weight: var(--weight-semibold);
}

.hours {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.hours th,
.hours td {
  padding: var(--space-2) 0;
  text-align: left;
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text-muted);
}

.hours th { font-weight: var(--weight-medium); color: var(--color-text); }
.hours tr:last-child th, .hours tr:last-child td { border-bottom: 0; }

.hours .today th,
.hours .today td {
  color: var(--color-primary);
  font-weight: var(--weight-semibold);
}

/* ---------- Panneau « nous trouver » ---------- */

.visit-panel {
  display: grid;
  gap: var(--space-5);
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

@media (min-width: 768px) {
  .visit-panel { grid-column: 1 / -1; grid-template-columns: 1fr 1fr; align-items: start; }
}

.visit-copy h2 { margin: 0 0 var(--space-2); font-family: var(--font-display); font-size: var(--text-xl); }

/* ---------- Formulaire de contact ---------- */

.contact-panel {
  display: grid;
  gap: var(--space-8);
  padding: var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}

@media (min-width: 768px) {
  .contact-panel {
    grid-column: 1 / -1;
    grid-template-columns: 1fr 1.3fr;
    gap: var(--space-10);
    padding: var(--space-8);
  }
}

.contact-panel h2,
.contact-panel h3 { margin: 0 0 var(--space-2); font-family: var(--font-display); }

/* ---------- Colonne de gauche : accroche + citation ---------- */

.contact-panel__aside {
  display: flex;
  flex-direction: column;
}

.contact-panel__headline {
  font-size: var(--text-3xl);
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
  letter-spacing: -0.01em;
}

.contact-panel__headline span { color: var(--color-primary); }

/* Pas « .contact-panel > p » : ce sélecteur l'emporterait sur
   .section-eyebrow (une classe + un type bat une classe seule), qui perdrait
   sa couleur d'accent et sa taille — un bug qui existe déjà ailleurs sur le
   site (.infos-col p fait la même chose aux eyebrows de Horaires/Commander,
   vérifié au navigateur) et qu'il n'y a aucune raison de reproduire ici. */
.contact-panel__lead {
  max-width: 32rem;
  color: var(--color-text-muted);
}

.contact-quote {
  margin: var(--space-6) 0 0;
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg-warm);
}

.contact-quote p {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-base);
  line-height: var(--leading-snug);
  color: var(--color-text);
}

.contact-quote strong { color: var(--color-primary); }

.contact-quote cite {
  font-size: var(--text-xs);
  font-style: normal;
  color: var(--color-text-subtle);
}

/* ---------- Colonne de droite : formulaire ---------- */

.contact-panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.contact-panel__badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-bg-warm);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.contact-panel__dot {
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  background: var(--color-success);
  flex: none;
}

.contact-panel__title {
  font-size: var(--text-2xl);
  font-weight: var(--weight-black);
}

.contact-form { max-width: none; }

.contact-form__row {
  display: grid;
  gap: var(--space-4);
}

@media (min-width: 480px) {
  .contact-form__row { grid-template-columns: 1fr 1fr; }
}

.contact-form__required { color: var(--color-primary); }

.contact-form__submit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

.contact-form__note {
  margin: 0;
  max-width: 22rem;
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

.contact-trust {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin: var(--space-6) 0 0;
  padding: var(--space-4) 0 0;
  border-top: 1px solid var(--color-border);
  list-style: none;
}

.contact-trust li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
}

.contact-trust__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-pill);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

.address-line {
  margin: 0 0 var(--space-4);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
}

.visit-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.btn-google:hover,
.btn-google:focus-visible { border-color: var(--color-text-subtle); }

.google-review {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-warm);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.google-mark { font-weight: var(--weight-bold); color: var(--color-text); }
.google-stars { color: var(--color-warning); letter-spacing: 1px; }

/* ---------- Avis Google — preuve sociale ---------- */

.reviews {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-8) var(--page-gutter);
  overflow-x: clip;
  min-width: 0;
}

.infos .reviews {
  grid-column: 1 / -1;
  max-width: none;
  margin: 0;
  padding: var(--space-8) 0 0;
  border-top: 1px solid var(--color-border);
}

.reviews-intro {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
}

.reviews-intro h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.reviews-score {
  display: grid;
  justify-items: center;
  gap: var(--space-1);
}

.reviews-score__brand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-subtle);
}

.google-g {
  display: block;
  flex: none;
}

.reviews-score__stars {
  margin: 0;
  color: var(--color-warning);
  font-size: var(--text-xl);
  letter-spacing: 0.18em;
  line-height: 1;
}

.reviews-score__value {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  line-height: 1;
}

.reviews-score__rating {
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 8vw, 3.25rem);
  font-weight: var(--weight-black);
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}

.reviews-score__denom {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
}

.reviews-score__count {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--color-text);
}

.reviews-lead {
  margin: var(--space-1) 0 0;
  max-width: 36ch;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

.reviews-stage {
  min-width: 0;
}

.reviews-viewport {
  overflow: hidden;
}

.reviews-track {
  position: relative;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  gap: var(--space-4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
}

.reviews-track::-webkit-scrollbar { display: none; }

.review-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
  height: 100%;
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

@media (hover: hover) and (pointer: fine) {
  .review-card {
    transition:
      transform var(--duration-base) var(--ease-out),
      box-shadow var(--duration-base) var(--ease-out);
  }

  .review-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
  }
}

.review-card__stars {
  color: var(--color-warning);
  letter-spacing: 0.12em;
  font-size: var(--text-base);
  line-height: 1;
  white-space: nowrap;
}

.review-card__identity {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.review-card__name {
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  color: var(--color-text);
}

.review-card__badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  padding: 2px 8px 2px 6px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.review-card__quote {
  margin: 0;
  flex: 1;
}

/* Date de publication de l'avis : obligation de l'article L.111-7-2 du code
   de la consommation. Discrète, mais pas décorative — la date absolue est en
   infobulle sur l'élément <time>. */
.review-card__date {
  display: block;
  margin-top: var(--space-3);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.review-card__quote p {
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
  min-height: calc(var(--leading-normal) * 4em);
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  line-height: var(--leading-normal);
  color: var(--color-text);
  text-wrap: pretty;
}

/* Flèche, points, flèche : les points peuvent passer à la ligne quand les
   avis sont nombreux, jamais les flèches, qui restent aux deux bouts. */
.reviews-toolbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.reviews-toolbar .reviews-dots {
  flex: 0 1 auto;
  min-width: 0;
}

.reviews-nav {
  display: inline-grid;
  flex: none;
  place-items: center;
  width: var(--tap-min);
  height: var(--tap-min);
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

.reviews-nav:hover:not([disabled]) {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

.reviews-nav[disabled] {
  opacity: 0.4;
  box-shadow: none;
  cursor: not-allowed;
}

.reviews-dots {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 2px;
}

.reviews-dot {
  display: grid;
  place-items: center;
  width: var(--tap-min);
  height: var(--tap-min);
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.reviews-dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-border-strong);
  transition:
    width var(--duration-base) var(--ease-out),
    background-color var(--duration-base) var(--ease-out);
}

.reviews-dot[aria-current="true"]::before {
  width: 22px;
  background: var(--color-primary);
}

.reviews-foot {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: var(--space-6) 0 0;
}

.reviews-foot .btn { width: 100%; }

.reviews-publish {
  margin: var(--space-4) 0 0;
  text-align: center;
}

.reviews-publish__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: 0 var(--space-5);
  border-radius: var(--radius-pill);
  background: var(--color-info);
  color: var(--color-text-invert);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: background-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out);
}

.reviews-publish__link:hover,
.reviews-publish__link:focus-visible {
  background: var(--color-info-hover);
  box-shadow: var(--shadow-md);
}

@media (min-width: 768px) {
  .reviews-track {
    grid-auto-columns: calc((100% - var(--space-4)) / 2);
  }

  .review-card__quote p {
    -webkit-line-clamp: 5;
    line-clamp: 5;
    min-height: calc(var(--leading-normal) * 5em);
  }

  .reviews-foot {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
  }

  .reviews-foot .btn { width: auto; min-width: 12.5rem; }
}

@media (min-width: 1024px) {
  .reviews-track {
    grid-auto-columns: calc((100% - (var(--space-4) * 2)) / 3);
  }

  .review-card { padding: var(--space-5) var(--space-5) var(--space-4); }
}

@media (prefers-reduced-motion: reduce) {
  .reviews-track { scroll-behavior: auto; }

  .review-card:hover { transform: none; }
}

.visit-map {
  position: relative;
  min-height: 260px;
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  overflow: hidden;
}

.visit-map iframe { width: 100%; height: 100%; min-height: 260px; border: 0; }

/* ---------- Retrait du consentement ----------

   Le choix d'afficher la carte survit désormais à la fermeture de l'onglet
   (initMapConsent dans js/app.js). Un accord durable n'en est un que s'il se
   reprend aussi simplement qu'il s'est donné : ce bouton efface le choix et
   rétablit l'écran d'attente.

   Il se pose sur la carte, en haut à droite, sur un fond opaque — au-dessus
   d'une photo satellite, un bouton translucide devient illisible. */

.map-hide {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  z-index: 1;
  min-height: var(--tap-min);
  padding: 0 var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--color-shadow-ink) 12%, transparent), 0 4px 12px -2px color-mix(in srgb, var(--color-shadow-ink) 18%, transparent);
}

.map-hide:hover {
  border-color: var(--color-text);
}

/* ---------- Carte : écran d'attente avant chargement ----------

   La carte Google Maps ne se charge plus d'elle-même (voir index.html et
   initMapConsent dans js/app.js) : tant que le visiteur n'a pas cliqué,
   c'est ce bloc — entièrement local, aucune requête vers un tiers — qui
   occupe la place. Il porte l'adresse en toutes lettres, de sorte que
   refuser la carte ne prive de rien.

   Les dimensions sont celles de l'iframe (min-height: 260px) pour que le
   passage de l'un à l'autre ne décale pas la mise en page. */

.visit-map--placeholder {
  border: 1px solid var(--color-border);
}

.map-consent {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-2);
  height: 100%;
  min-height: 260px;
  padding: var(--space-5);
  text-align: center;
}

.map-consent__pin { color: var(--color-primary); }

.map-consent__title {
  margin: 0;
  font-weight: var(--weight-semibold);
}

.map-consent__text {
  margin: 0;
  max-width: 44ch;
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
}

.map-consent__btn { margin-top: var(--space-2); }

.map-consent__note {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* ---------- Suppression du compte (compte.html) ----------

   Panneau replié par défaut : le geste est irréversible, il n'a pas à être à
   portée de clic distrait. Le liseré d'alerte le distingue des autres cartes
   de la colonne sans le rendre alarmant tant qu'il reste fermé. */

.account-danger { border-color: var(--color-danger); }

.danger-zone__summary {
  cursor: pointer;
  list-style: none;
}

.danger-zone__summary::-webkit-details-marker { display: none; }

.danger-zone__summary::after {
  content: "Afficher";
  display: block;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-danger);
  text-decoration: underline;
}

.danger-zone[open] .danger-zone__summary::after { content: "Masquer"; }

/* WCAG 2.2 — 2.4.7 : <summary> est focusable, l'anneau doit rester visible. */
.danger-zone__summary:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-sm);
}

.danger-zone__body { margin-top: var(--space-4); }

.danger-zone__lead {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
}

/* ============================================================
   8. Pied de page
   ============================================================ */

.footer {
  margin-top: var(--space-10);
  padding: var(--space-8) var(--page-gutter);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.footer p { margin: 0 0 var(--space-4); }

/* Mention sanitaire obligatoire (art. L2133-1 du code de la santé
   publique) : discrète comme le reste du pied de page, jamais illisible —
   la loi impose sa présence, pas sa taille exacte. */
.footer-health {
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

.footer-health__icon {
  display: inline;
  vertical-align: -2px;
  margin-right: 4px;
  color: var(--color-success);
}

.footer-health a {
  color: inherit;
}

/* Réseaux sociaux. Une pastille de 44 px : c'est le minimum tactile de la
   WCAG (2.5.8), et un logo de 22 px seul se rate au pouce. La couleur de
   marque n'arrive qu'au survol et au focus — quatre aplats colorés alignés
   dans un pied de page discret feraient plus de bruit que le reste de la
   page n'en fait. */
.footer-social {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-5);
}

.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-bg-warm);
  color: var(--color-text-muted);
  transition: color 150ms ease, border-color 150ms ease, background-color 150ms ease;
}

.social-link svg { display: block; }

.social-link:hover,
.social-link:focus-visible {
  border-color: currentColor;
  background: var(--color-surface);
}

.social-link--instagram:hover,
.social-link--instagram:focus-visible { color: var(--color-social-instagram); }

.social-link--tiktok:hover,
.social-link--tiktok:focus-visible { color: var(--color-social-tiktok); }

.social-link--snapchat:hover,
.social-link--snapchat:focus-visible {
  color: var(--color-social-snapchat-ink);
  background: var(--color-social-snapchat);
  border-color: var(--color-social-snapchat-ink);
}

.social-link--facebook:hover,
.social-link--facebook:focus-visible { color: var(--color-social-facebook); }

.footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

/* WCAG 2.2 — 2.5.8 : ces liens ne sont pas « en ligne dans une
   phrase », l'exception ne s'applique donc pas. */
.footer-links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-height-sm);
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-bg-warm);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
}

.footer-links a:hover {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

.footer-links a[aria-current="page"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-text-invert);
  font-weight: var(--weight-semibold);
}

/* Crédit du réalisateur : la dernière ligne, plus discrète que les liens
   légaux, mais une cible tactile entière comme eux. */
.footer .footer-credit {
  margin: var(--space-5) 0 0;
  font-size: var(--text-xs);
}

.footer-credit a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  color: var(--color-text-subtle);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}

.footer-credit a:hover,
.footer-credit a:focus-visible {
  color: var(--color-text);
}

.footer-credit__logo {
  display: block;
  flex: none;
}

/* ============================================================
   9. Panier flottant et tiroir
   ============================================================ */

.mini-cart {
  position: fixed;
  left: var(--page-gutter);
  right: var(--page-gutter);
  bottom: var(--space-4);
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  max-width: 520px;
  margin: 0 auto;
  min-height: 56px;
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: var(--color-text-invert);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-lg);
}

.mini-cart:hover { background: var(--color-primary-hover); }
.mini-cart span { display: grid; min-width: 0; }
.mini-cart strong { font-size: var(--text-sm); font-weight: var(--weight-semibold); }

.mini-cart small {
  font-size: var(--text-xs);
  /* A11Y-04 : le blanc voilé à 85 % sur le rouge tombait sous 4,5:1. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mini-cart b { font-size: var(--text-lg); font-variant-numeric: tabular-nums; }

.drawer-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--color-overlay);
}

.drawer {
  position: fixed;
  z-index: var(--z-drawer);
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  /* Feuille du bas sur mobile : le pouce atteint le bord inférieur,
     pas le haut d'un panneau latéral. */
  /* --keyboard-inset : hauteur masquée par le clavier virtuel, mesurée au
     runtime depuis visualViewport (setupViewportInsets). Sans elle, le pied
     du tiroir — donc le bouton de commande — passe derrière le clavier dès
     qu'un champ du checkout prend le focus.
     dvh et non vh : vh ignore la barre d'URL rétractable sur mobile. */
  inset: auto 0 var(--keyboard-inset, 0px) 0;
  max-height: calc(92dvh - var(--keyboard-inset, 0px));
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  transform: translateY(100%);
  transition: transform var(--duration-slow) var(--ease-out);
  box-shadow: var(--shadow-lg);
}

.drawer.open { transform: none; }

/* Pendant le geste, le panneau suit le doigt sans retard d'animation. */
.drawer.is-dragging { transition: none; }

/* Poignée du panneau du bas : elle dit qu'on peut le tirer pour le
   fermer. Décor seulement — la croix reste la voie annoncée. */
@media (max-width: 767px) {
  .drawer::before {
    content: "";
    position: absolute;
    top: var(--space-2);
    left: 50%;
    width: 40px;
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--color-border-strong);
    transform: translateX(-50%);
    pointer-events: none;
  }

  .drawer-head { touch-action: none; padding-top: var(--space-5); }
}
.drawer[aria-hidden="true"] { visibility: hidden; }
.drawer.open[aria-hidden="false"] { visibility: visible; }

@media (min-width: 768px) {
  .drawer {
    inset: 0 0 var(--keyboard-inset, 0px) auto;
    width: min(440px, 100%);
    max-height: none;
    border-radius: 0;
    transform: translateX(100%);
  }
}

.drawer-step { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.drawer-step[hidden] { display: none; }

.drawer-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4) var(--space-3);
  border-bottom: 1px solid var(--color-border);
}

.drawer-head h2 {
  flex: 1;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-xl);
}

.drawer-head .icon-btn:last-child { margin-left: auto; }

.drawer-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--space-4);
}

/* Action rare et destructive : elle était présentée en bouton bordé, juste
   au-dessus du CTA principal, avec lequel elle rivalisait. Elle garde sa
   zone tactile de 44 px mais prend l'apparence d'un lien discret. */
.drawer-clear-row {
  padding: 0 var(--space-4);
  text-align: right;
}

.drawer-clear-row[hidden] { display: none; }

.btn-clear-cart {
  min-height: var(--tap-min);
  padding: 0 var(--space-2);
  border-color: transparent;
  background: none;
  color: var(--color-text-subtle);
  font-size: var(--text-sm);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.btn-clear-cart:hover:not([disabled]) {
  border-color: transparent;
  background: var(--color-danger-soft);
  color: var(--color-danger);
}

.drawer-foot {
  padding: var(--space-4);
  padding-bottom: max(var(--space-4), env(safe-area-inset-bottom));
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
}

/* Cet encart bordé pesait 82 px dans un pied de 221 px, et ne laissait que
   453 px au formulaire pour 793 px de contenu. La mention reste obligatoire
   avant validation : elle passe sous le CTA, en une ligne, où elle se lit en
   même temps que le bouton plutôt qu'au-dessus des totaux. */
.pay-notice {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-1);
  margin: var(--space-2) 0 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-success);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  text-align: center;
}

.pay-notice strong { font-weight: var(--weight-bold); }

/* Montant porté par le CTA lui-même : « Reserver ma commande · 35 € ». */
.btn-amount { font-variant-numeric: tabular-nums; }

/* Résumé replié dans l'étape coordonnées, à la place de l'ancienne
   troisième étape. */
.checkout-summary { margin-bottom: var(--space-4); }

.checkout-summary .recap-section {
  margin: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.checkout-summary summary {
  padding: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  list-style-position: inside;
}

.checkout-summary .recap-line { padding: var(--space-2) var(--space-3); }
.checkout-summary .recap-line:last-child { border-bottom: 0; }
.checkout-summary .recap-note { padding: 0 var(--space-3) var(--space-3); }

.cart-total-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--space-3);
  font-size: var(--text-base);
}

.cart-total-row strong {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

/* ---------- Lignes du panier ---------- */

.cart-line {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
}

.cart-line:last-child { border-bottom: 0; }

.line-info { min-width: 0; grid-column: 1; grid-row: 1; }
.line-name { font-weight: var(--weight-semibold); font-size: var(--text-sm); }

/* Porte désormais le prix unitaire : « 3× Kabana — 30 € » ne disait pas
   si la pizza valait 10 € ou si le total était faux. */
.line-size { font-size: var(--text-xs); color: var(--color-text-muted); }

.cart-line .qty { grid-column: 1; grid-row: 2; justify-self: start; }

.line-price {
  grid-column: 2;
  grid-row: 2;
  justify-self: end;
  font-weight: var(--weight-bold);
  font-size: var(--text-base);
  font-variant-numeric: tabular-nums;
}

/* Retirer un article demandait de décrémenter jusqu'à zéro. */
.line-remove {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  display: grid;
  place-items: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--color-text-subtle);
  cursor: pointer;
}

.line-remove:hover { background: var(--color-danger-soft); color: var(--color-danger); }

.qty {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 3px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
}

.qty button {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: var(--color-surface-sunken);
  color: var(--color-text);
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  line-height: 1;
  cursor: pointer;
}

.qty button:hover { background: var(--color-primary-soft); color: var(--color-primary); }
.qty input.qty-input { width: 46px; height: 32px; font-weight: var(--weight-semibold); }

/* Le total de la ligne change sans que rien ne bouge autour quand la
   quantite est tapee : un halo bref signale le recalcul. */
.line-price.is-updated,
.card-price.is-updated,
.featured-card__price.is-updated,
.co-total.is-updated { animation: price-flash var(--duration-slow) var(--ease-out); }

@keyframes price-flash {
  0%   { color: var(--color-primary); transform: scale(1.06); }
  100% { color: inherit; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .line-price.is-updated,
  .card-price.is-updated,
  .featured-card__price.is-updated,
  .co-total.is-updated { animation: none; }
}

/* ---------- Formulaire de commande ---------- */

.mode-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  border: 0;
}

.mode-group legend {
  flex: 1 0 100%;
  padding: 0;
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.mode-pill {
  flex: 1 1 140px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-height);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.mode-pill input { position: absolute; opacity: 0; pointer-events: none; }

.mode-pill:has(input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-weight: var(--weight-semibold);
}

.mode-pill:has(input:focus-visible) { outline: var(--focus-ring); outline-offset: var(--focus-offset); }

/* ---------- Code de réduction ---------- */

.promo-field { display: grid; gap: var(--space-2); margin-bottom: var(--space-4); }

.promo-field label {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.promo-field__row { display: flex; gap: var(--space-2); }
.promo-field__row input { flex: 1 1 auto; min-width: 0; text-transform: uppercase; }
.promo-field__row .btn { flex: 0 0 auto; }
.promo-field input[readonly] { background: var(--color-success-soft); border-color: var(--color-success); }

.promo-feedback { margin: 0; }
.promo-feedback[hidden] { display: none; }

/* Ligne de remise, entre le sous-total et le total à régler. */
.discount-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-success);
}

.discount-row[hidden] { display: none; }
.discount-row strong { font-variant-numeric: tabular-nums; }

/* ---------- Livraison externe ----------

   Deux emplacements, deux poids : une ligne dans la page pour qui cherche
   « comment je recupere ma commande », un encart au moment ou la question
   se pose vraiment. Aucun des deux ne doit rivaliser avec « Reserver ma
   commande » : la commande directe ne prend pas de commission. */

.delivery-inline {
  display: flex;
  /* Le scooter se cale sur la premiere ligne : centre, il flottait au
     milieu d'un texte qui passe sur deux lignes en colonne etroite. */
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* Le badge rond officiel remplace l'emoji : c'est la marque qu'on
   reconnait, pas un scooter generique. Taille fixe, jamais deformee — la
   charte d'Uber l'interdit. */
.delivery-inline__icon {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  margin-top: 1px;
}

.delivery-inline a {
  font-weight: var(--weight-semibold);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
}

.delivery-inline a:hover { text-decoration-color: currentColor; }

/* Le pointille faisait « note technique collee au formulaire ». Un aplat
   chaud, un filet plein et un liseré a gauche : l'encart se lit comme une
   alternative offerte, pas comme un avertissement. */
.delivery-note {
  margin: 0;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-md);
  background: var(--color-bg-warm);
}

.delivery-note__lead picture { flex: 0 0 auto; display: block; font-size: 0; }
.delivery-inline picture { flex: 0 0 auto; display: block; font-size: 0; }

.delivery-note__lead {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--color-text-muted);
}

.delivery-note__lead strong { color: var(--color-text); }

/* Le badge est deja rond et porte son propre fond vert : ni pastille
   blanche, ni ombre, ni rognage autour de lui. */
.delivery-note__icon {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
}

/* Aux couleurs d'Uber Eats, pas a celles du site : le client doit
   reconnaitre ou il va avant de cliquer. Le vert le distingue aussi du
   rouge de marque, donc de l'action principale de l'ecran — la hierarchie
   tient par la couleur autant que par la taille. */
.delivery-note__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: 0 var(--space-5);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-brand-ubereats);
  color: var(--color-brand-ubereats-ink);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: background var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}

.delivery-note__cta:hover {
  background: var(--color-brand-ubereats-hover);
  transform: translateY(-1px);
}

.delivery-note__cta:active { transform: translateY(0); }

/* Le nom de la marque se detache du verbe qui le precede, sans pour autant
   imiter la typographie officielle. */
.delivery-note__brand {
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
}

.delivery-note__cta svg { flex: 0 0 auto; }

.delivery-note__hint {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

/* ---------- Récapitulatif ---------- */

.recap-section { margin-bottom: var(--space-5); }

.recap-section h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

.recap-line {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
}

.recap-line:last-child { border-bottom: 0; }

.recap-note {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.confirm-check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  cursor: pointer;
}

/* ---------- Confirmation de commande ---------- */

.order-success {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: var(--page-gutter);
  background: var(--color-overlay);
}

.order-success-card {
  width: min(420px, 100%);
  padding: var(--space-6);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  text-align: center;
  box-shadow: var(--shadow-lg);
}

.order-success-card h2 { margin: var(--space-3) 0; font-family: var(--font-display); font-size: var(--text-2xl); }
.order-success-card p { font-size: var(--text-sm); color: var(--color-text-muted); }
.order-success-card .btn { margin-top: var(--space-3); }

/* Le récapitulatif peut allonger la fenêtre : elle défile plutôt que de
   sortir de l'écran sur un petit téléphone. */
.order-success-card { max-height: calc(100dvh - 2 * var(--page-gutter)); overflow-y: auto; overscroll-behavior: contain; }

.order-recap { display: grid; gap: var(--space-2); margin-top: var(--space-4); text-align: left; }
.order-recap:empty { display: none; }
.order-success-card .order-recap__creneau { color: var(--color-text); font-weight: var(--weight-semibold); }
.order-recap__articles { display: grid; gap: var(--space-1); margin: 0; padding: 0; list-style: none; font-size: var(--text-sm); }
.order-recap__totaux { display: grid; gap: var(--space-1); margin: 0; padding-top: var(--space-2); border-top: 1px dashed var(--color-border-strong); font-size: var(--text-sm); }
.order-recap__totaux div { display: flex; justify-content: space-between; gap: var(--space-3); }
.order-recap__totaux dd { margin: 0; font-variant-numeric: tabular-nums; }
.order-recap__totaux .is-total { font-weight: var(--weight-bold); font-size: var(--text-base); }

.order-success-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.order-success-actions .btn { padding-inline: var(--space-3); }

/* Session expirée (lot 5c) : encadré d'avertissement au-dessus de la
   connexion, là où le regard arrive. */
.session-expired {
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-warning-soft);
  color: var(--color-warning);
  font-weight: var(--weight-semibold);
}

.session-expired[hidden] { display: none; }

/* ---------- Erreurs de champ (lot 5b) ---------- */

.field-error {
  margin: calc(-1 * var(--space-1)) 0 0;
  color: var(--color-danger);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.field-error[hidden] { display: none; }

[aria-invalid="true"] { border-color: var(--color-danger); }

/* ---------- Rendu différé hors écran (lot 6) ----------
   Le profil d'un chargement sur téléphone moyen donnait 1,6 s de calcul de
   mise en page : la page entière — 22 fiches de pizza, Kabanito, boissons,
   horaires, avis, pied de page — était mise en page à chaque arrivée de
   données (carte, réglages, avis), alors que l'écran n'en montre que le
   haut. content-visibility: auto laisse le navigateur sauter ce qui est
   loin de l'écran, et le faire au moment où on s'en approche.
   La hauteur réservée en attendant vient des mesures à 375, 768 et
   1280 px ; « auto » retient ensuite la vraie, une fois affichée, pour que
   la barre de défilement et les ancres (Boissons, Horaires) restent justes.
   Aucun élément fixe ou collant ne vit dans ces blocs : la limitation de
   rendu qu'impose content-visibility n'y change donc rien. */
.grid > .card { content-visibility: auto; contain-intrinsic-size: auto none auto 340px; }
#kabanito { content-visibility: auto; contain-intrinsic-size: auto none auto 700px; }
#accompagnements { content-visibility: auto; contain-intrinsic-size: auto none auto 350px; }
#boissons { content-visibility: auto; contain-intrinsic-size: auto none auto 900px; }
#infos { content-visibility: auto; contain-intrinsic-size: auto none auto 2700px; }
.footer { content-visibility: auto; contain-intrinsic-size: auto none auto 330px; }

@media (min-width: 768px) {
  .grid > .card { contain-intrinsic-size: auto none auto 400px; }
  #kabanito { contain-intrinsic-size: auto none auto 610px; }
  #boissons { contain-intrinsic-size: auto none auto 760px; }
  #infos { contain-intrinsic-size: auto none auto 2260px; }
  .footer { contain-intrinsic-size: auto none auto 230px; }
}

@media (min-width: 1024px) {
  .grid > .card { contain-intrinsic-size: auto none auto 430px; }
  #kabanito { contain-intrinsic-size: auto none auto 480px; }
  #infos { contain-intrinsic-size: auto none auto 2060px; }
}

/* ---------- Squelettes de la carte (lot 5b) ---------- */

.card-squelette {
  display: grid;
  align-content: start;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.card-squelette span {
  display: block;
  height: var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
}

.card-squelette span:first-child { height: auto; aspect-ratio: 4 / 3; border-radius: var(--radius-md); }
.card-squelette span:nth-child(3) { width: 70%; }
.card-squelette span:last-child { width: 40%; height: var(--space-8); }

.card-squelette--ligne span:first-child { aspect-ratio: auto; height: var(--space-4); width: 55%; border-radius: var(--radius-pill); }

@media (prefers-reduced-motion: no-preference) {
  .card-squelette span { animation: squelette-respire 1.2s var(--ease-in-out) infinite alternate; }
}

@keyframes squelette-respire {
  to { background: var(--color-border); }
}

/* BUG-02 : remise non appliquée. Encadré et non simple ligne grise : c'est
   la seule information de cet écran qui change ce que le client va payer. */
.order-success-card .order-success-notice {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-warning-soft);
  color: var(--color-warning);
  font-weight: 600;
  text-align: left;
}

.done-check {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin: 0 auto;
  border-radius: 50%;
  background: var(--color-success-soft);
  color: var(--color-success);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
}

/* ---------- Retour d'ajout au panier ---------- */

.cart-toast {
  position: fixed;
  left: 50%;
  bottom: 84px;
  z-index: var(--z-toast);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-pill);
  background: var(--color-text);
  color: var(--color-text-invert);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  box-shadow: var(--shadow-md);
  transform: translate(-50%, 12px);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-out);
}

.cart-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* Deux lignes : l'action confirmee, puis l'article exact. */
.cart-toast small {
  display: block;
  font-weight: var(--weight-regular);
}

.toast-check {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--color-success);
  font-size: var(--text-xs);
}

/* ============================================================
   10. Pages compte et authentification
   ============================================================ */

.auth-page {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-8) var(--page-gutter);
}

.auth-card {
  width: min(560px, 100%);
  margin: 0 auto;
  padding: var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.auth-card[hidden] { display: none; }
.auth-head { margin-bottom: var(--space-5); }

.auth-head h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
}

.auth-tabs {
  display: flex;
  gap: 3px;
  margin-bottom: var(--space-5);
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
}

.auth-tab {
  flex: 1;
  min-height: var(--control-height-sm);
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
  cursor: pointer;
}

.auth-tab[aria-selected="true"] {
  background: var(--color-surface);
  color: var(--color-text);
  font-weight: var(--weight-semibold);
  box-shadow: var(--shadow-xs);
}

.auth-form { display: grid; gap: var(--space-4); }
.auth-form[hidden] { display: none; }
.auth-alt { margin: 0; text-align: center; font-size: var(--text-sm); }

/* ---------- Attente de validation d'adresse ---------- */

.auth-pending {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.auth-pending[hidden] { display: none; }

.pending-badge {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-primary);
}

.auth-pending .section-sub { margin: 0; }
.profile-saved { margin: 0; font-size: var(--text-sm); color: var(--color-success); font-weight: var(--weight-semibold); }

.account-created-message {
  margin: var(--space-3) 0 0;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-success-soft);
  color: var(--color-success);
  font-size: var(--text-sm);
}

.account-dashboard { width: min(920px, 100%); }

.account-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.account-hero .auth-head { margin: 0; }
.account-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.account-layout { display: grid; gap: var(--space-5); }

@media (min-width: 900px) {
  /* L'historique passe a gauche et prend la place : c'est ce que le client
     vient chercher sur cette page, le formulaire d'infos se consulte
     rarement deux fois. */
  .account-layout { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); align-items: start; }
}

.account-panel {
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
}

.panel-title-row { margin-bottom: var(--space-4); }
.orders-title { margin: 0; font-family: var(--font-display); font-size: var(--text-xl); }
.orders-list { display: grid; gap: var(--space-3); }

/* ---------- Carte de commande client ---------- */

.client-order {
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.co-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.co-ref {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.co-items-list { margin: 0; padding: 0; list-style: none; }

.co-item-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-2);
  padding: var(--space-1) 0;
  font-size: var(--text-sm);
}

.co-item-qty { font-weight: var(--weight-semibold); color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.co-item-price { font-variant-numeric: tabular-nums; }

.co-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.co-total { font-size: var(--text-lg); color: var(--color-text); font-variant-numeric: tabular-nums; }

/* Ce que le statut implique pour le client : « Prête à retirer » sans
   « vous pouvez venir la chercher » ne dit pas quoi faire. */
.co-hint {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.co-actions { margin-top: var(--space-3); }
.co-reorder { width: 100%; }
.co-feedback { margin: var(--space-3) 0 0; }
.co-feedback[hidden] { display: none; }

/* ============================================================
   11. Pages légales et 404
   ============================================================
   Trois documents longs (mentions, CGV, confidentialité) : le
   visiteur doit pouvoir les scanner, sauter à une section, et
   passer d'un document à l'autre. Le 404 réutilise .legal-doc
   dans un conteneur plus étroit.
   ============================================================ */

.legal-page {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-6) var(--page-gutter) var(--space-12);
}

.legal-hero {
  margin-bottom: var(--space-8);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-border);
}

.legal-hero h1 {
  margin: 0;
  max-width: 22ch;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--weight-black);
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.legal-hero .legal-lead {
  max-width: 58ch;
  margin: var(--space-4) 0 0;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
}

.legal-updated {
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-subtle);
}

/* Famille des trois documents : on sait où on est, on saute aux
   deux autres sans redescendre au pied de page. */
.legal-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-6);
}

.legal-tabs a {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-height-sm);
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
}

.legal-tabs a:hover {
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.legal-tabs a[aria-current="page"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-text-invert);
  font-weight: var(--weight-semibold);
}

.legal-layout {
  display: grid;
  gap: var(--space-8);
}

@media (min-width: 900px) {
  .legal-layout {
    grid-template-columns: minmax(200px, 240px) minmax(0, 1fr);
    align-items: start;
    gap: var(--space-10);
  }
}

.legal-toc {
  margin: 0;
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

@media (min-width: 900px) {
  .legal-toc {
    position: sticky;
    top: var(--space-4);
  }
}

.legal-toc h2 {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-subtle);
}

.legal-toc ol {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 2px;
  counter-reset: legal-toc;
}

.legal-toc li { counter-increment: legal-toc; }

.legal-toc a {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  min-height: var(--tap-min);
  padding: var(--space-1) var(--space-2);
  margin: 0 calc(var(--space-2) * -1);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  text-decoration: none;
}

.legal-toc a::before {
  content: counter(legal-toc, decimal-leading-zero);
  flex: none;
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-primary);
}

.legal-toc a:hover {
  background: var(--color-surface-sunken);
  color: var(--color-text);
}

.legal-doc {
  max-width: var(--prose-max);
  margin: 0 auto;
}

.legal-layout .legal-doc {
  max-width: none;
  margin: 0;
}

.legal-doc h1 {
  margin: 0 0 var(--space-4);
  font-family: var(--font-display);
  font-size: var(--text-3xl);
}

.legal-doc h2 {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  scroll-margin-top: var(--space-5);
}

.legal-doc h3 {
  margin: var(--space-5) 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
}

.legal-doc p,
.legal-doc li {
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text);
}

.legal-doc li { color: var(--color-text-muted); }
.legal-doc li strong { color: var(--color-text); }

.legal-doc ul,
.legal-doc ol { margin: 0 0 var(--space-4); }

.legal-doc a { text-underline-offset: 2px; }

.legal-doc code {
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  font-size: 0.9em;
}

.legal-doc > section {
  padding: var(--space-6) 0;
  border-top: 1px solid var(--color-border);
}

.legal-doc > section:first-child {
  padding-top: 0;
  border-top: 0;
}

/* Fiche d'identité : dt en petite capitale, dd en lecture courante.
   Deux colonnes dès qu'il y a la place, pile sinon. */
.legal-doc dl {
  display: grid;
  grid-template-columns: minmax(8rem, 11rem) minmax(0, 1fr);
  gap: var(--space-2) var(--space-5);
  margin: var(--space-4) 0 0;
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg-warm);
}

.legal-doc dt {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-subtle);
  padding-top: 2px;
}

.legal-doc dd {
  margin: 0;
  color: var(--color-text);
  overflow-wrap: anywhere;
}

@media (max-width: 639px) {
  .legal-doc dl {
    grid-template-columns: 1fr;
    gap: var(--space-1);
  }

  .legal-doc dd { margin-bottom: var(--space-3); }
  .legal-doc dd:last-child { margin-bottom: 0; }
}

.legal-doc > section.legal-contact {
  margin-top: var(--space-6);
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.legal-contact h2 { margin-bottom: var(--space-4); }

.legal-contact p { margin-top: var(--space-4); color: var(--color-text-muted); }

.legal-contact__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-3);
}

.legal-contact__list li {
  display: grid;
  gap: 2px;
  color: var(--color-text);
}

.legal-contact__list span {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-subtle);
}

.legal-back {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-border);
}

/* ---------- Page 404 ---------- */

/* La page reprend le gabarit des sections du site plutôt que celui d'un
   document légal : le visiteur arrivé ici n'a rien à lire, il a une
   destination à retrouver. D'où un hero, des raccourcis, un contact. */

.error-hero {
  position: relative;
  overflow: hidden;
  padding: var(--space-10) var(--page-gutter) var(--space-12);
  background:
    radial-gradient(115% 85% at 12% 0%, var(--color-bg) 0%, transparent 62%),
    var(--color-bg-warm);
  border-bottom: 1px solid var(--color-border);
}

/* Le « 404 » en filigrane porte le message d'erreur sans l'écrire une
   deuxième fois. Purement décoratif : hors du flux, hors du calque
   d'accessibilité, et sans effet sur la sélection de texte. */
.error-hero__mark {
  position: absolute;
  right: -2vw;
  bottom: -12vw;
  font-family: var(--font-display);
  font-size: clamp(16rem, 38vw, 30rem);
  font-weight: var(--weight-black);
  line-height: 0.8;
  letter-spacing: -0.06em;
  color: var(--color-primary-ghost);
  pointer-events: none;
  user-select: none;
}

.error-hero__inner {
  position: relative;
  display: grid;
  gap: var(--space-10);
  align-items: center;
  max-width: var(--content-max);
  margin: 0 auto;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
}

.error-hero h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(var(--text-3xl), 6vw, var(--text-4xl));
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
  letter-spacing: -0.03em;
  color: var(--color-text);
  text-wrap: balance;
}

.error-lede {
  margin: var(--space-4) 0 0;
  max-width: 44ch;
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

.error-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
}

/* Sous 480 px, « Appeler la pizzeria » (190 px) et « Voir la carte »
   (150 px) ne tiennent pas sur une ligne : les deux boutons tombaient
   l'un sous l'autre à des largeurs différentes, et l'action principale
   se retrouvait la plus petite. Ils passent pleine largeur. */
@media (max-width: 479px) {
  .error-actions .btn,
  .error-panel__actions .btn { flex: 1 1 100%; }
}

/* Le chemin demandé, rendu comme une trace serveur : c'est la seule
   information technique de la page, et elle rassure celui qui se
   demande s'il a mal recopié un lien. */
.error-trace {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-6) 0 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

.error-trace code {
  padding: 2px var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  font-family: inherit;
  font-size: inherit;
  letter-spacing: 0.02em;
}

/* La fiche fantôme reprend .card à l'identique : même gabarit, mêmes
   chips, même bandeau de prix que sur la carte. C'est ce qui fait la
   blague — une pizza qui n'existe pas, servie dans le vrai composant. */
.error-card {
  width: min(340px, 100%);
  justify-self: center;
  animation: error-card-tilt 9s var(--ease-in-out) infinite;
}

@keyframes error-card-tilt {
  0%, 100% { transform: rotate(-1.2deg); }
  50%      { transform: rotate(1.2deg); }
}

/* Le bloc global de base.css ramène la durée à 0.01ms, ce qui figerait
   la fiche sur la première image — donc penchée. On la remet à plat. */
@media (prefers-reduced-motion: reduce) {
  .error-card { animation: none; }
}

.error-card .card { box-shadow: var(--shadow-lg); }

/* Hachures à la place de la photo : le vide est montré, pas masqué par
   un visuel d'emprunt qui laisserait croire au produit. */
.error-card__void {
  display: grid;
  place-content: center;
  gap: var(--space-2);
  padding: var(--space-5);
  text-align: center;
  background: repeating-linear-gradient(
    45deg,
    var(--color-surface-sunken) 0 var(--space-3),
    var(--color-bg) var(--space-3) var(--space-6)
  );
}

.error-card__void p {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

.error-card__void p:first-of-type {
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Le bouton d'ajout est ici un décor : rien à ajouter au panier. Il
   garde la forme du vrai bouton, jamais sa couleur d'action. */
.error-card .add-btn {
  background: var(--color-border-strong);
  cursor: default;
}

.error-section {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-10) var(--page-gutter) 0;
}

.error-section h2 {
  margin: 0 0 var(--space-5);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
}

/* Les raccourcis passaient en liste empilée pleine largeur : quatre
   blocs de 44 px qui repoussaient le contact sous la ligne de flottaison
   sur mobile. En pastilles, ils tiennent en deux lignes. */
.error-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* WCAG 2.2 — 2.5.8 : ce sont des cibles de navigation, pas des liens
   en ligne dans une phrase. L'exception ne s'applique pas. */
.error-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  transition: border-color var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

.error-links a:hover {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

.error-panel {
  display: grid;
  gap: var(--space-6);
  align-items: center;
  padding: var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}

.error-panel h2 {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-xl);
}

.error-panel p {
  margin: 0;
  max-width: 46ch;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

.error-panel .address-line {
  margin: var(--space-4) 0 0;
  font-size: var(--text-sm);
}

.error-panel__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* Vert WhatsApp du site, en aplat doux : le bouton reste secondaire
   derrière l'appel, qui est la voie la plus rapide vers la pizzeria. */
.btn-whatsapp {
  border-color: var(--color-success);
  background: var(--color-success-soft);
  color: var(--color-success);
}

.btn-whatsapp:hover:not([disabled]) {
  background: var(--color-surface);
  border-color: var(--color-success);
}

/* Champ que l'exploitant doit compléter : surligné pour qu'un oubli
   se voie en relecture plutôt qu'en production. */
/* ============================================================
   12. Reveals
   ============================================================
   Le seul mouvement conservé : une apparition sobre à l'arrivée
   dans le viewport. Neutralisée par les tokens sous
   prefers-reduced-motion.
   ============================================================ */

.reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
}

.reveal.visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

/* ============================================================
   13. Décalage sous l'en-tête fixe
   ============================================================
   Seule l'accueil porte un en-tête fixe (.site-header). Les pages
   secondaires affichent une .topbar dans le flux : leur appliquer
   ce décalage ouvrirait 56 px de vide en haut de page.
   --header-offset est mesuré au runtime par setupSiteHeader().
   ============================================================ */

body:has(.site-header) {
  padding-top: var(--header-offset, 56px);
}

/* Cible d'ancre : il faut dégager l'en-tête fixe ET la barre de
   catégories collante, sinon le titre de section atterrit dessous. */
.menu-section,
.infos,
.reviews,
.visit-panel {
  scroll-margin-top: calc(var(--header-offset, 56px) + 64px);
}

/* Le mini-panier flottant ne doit pas masquer la dernière carte. */
body:has(.mini-cart:not([hidden])) .footer {
  padding-bottom: calc(var(--space-8) + 72px);
}

/* ---------- Panier : avis de mise à jour ----------

   Le panier vit dans localStorage et gardait le prix du jour où l'article y
   a été ajouté : une carte modifiée entre-temps affichait l'ancien montant
   et la caisse encaissait le nouveau. Le panier est désormais recalé sur le
   catalogue à chaque chargement, et ce bandeau dit ce qui a changé — un
   réalignement silencieux serait aussi désagréable qu'un prix faux. */
.cart-notice {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-md);
  background: var(--color-warning-soft);
  color: var(--color-text);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

.cart-notice__title {
  margin: 0;
  font-weight: 600;
}

.cart-notice ul {
  margin: 0;
  padding-left: var(--space-4);
  color: var(--color-text-muted);
}

/* ============================================================
   Refonte carte — sélecteur de format, signature, horaires,
   barre d'onglets. Voir « Kabana Pizz — Refonte » (Claude Design).
   ============================================================ */

/* ---------- Pastille d'état dans l'en-tête ---------- */

/* Le badge du hero disparaît dès qu'on descend dans la carte. Celui-ci
   reste : « c'est ouvert ? » se repose au moment de valider le panier. */
.status-pill {
  display: none;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-success-soft);
  color: var(--color-success);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  white-space: nowrap;
}

.status-pill::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  background: currentColor;
}

.status-pill.is-closed {
  background: var(--color-warning-soft);
  color: var(--color-warning);
}

/* Sous 560 px, l'en-tête porte déjà la marque, le compte et le panier :
   une quatrième pastille les compresserait. Le hero garde l'information. */
@media (min-width: 560px) {
  .status-pill:not([hidden]) { display: inline-flex; }
}

/* ---------- Sélecteur de format ---------- */

.section-head--split {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

@media (min-width: 640px) {
  .section-head--split {
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
  }
}

.size-switch__label {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-subtle);
}

.size-switch__track {
  display: inline-flex;
  gap: var(--space-1);
  padding: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
}

.size-switch__option {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  font-family: var(--font-body);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}

.size-switch__option strong {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.size-switch__option span {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

.size-switch__option[aria-pressed="true"] {
  background: var(--color-text);
  color: var(--color-bg);
}

/* ---------- Format choisi sur la fiche ----------

   Le meme motif que .size-switch, en plus petit et pose dans la vignette :
   arrive au bas d'une carte de vingt pizzas, remonter en tete de section
   pour changer de format puis redescendre retrouver sa pizza etait le geste
   le plus couteux de la page. */

.card-sizes {
  display: flex;
  gap: 4px;
  margin: var(--space-2) 0 0;
  padding: 3px;
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.card-size {
  flex: 1 1 0;
  min-width: 0;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  min-height: 38px;
  padding: 2px var(--space-1);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  font-family: var(--font-body);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

/* nowrap : dans une vignette de 110 px, « 32 cm » se coupait en deux lignes
   et la pastille doublait de hauteur. */
.card-size strong {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  white-space: nowrap;
}

.card-size span {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-tight);
  white-space: nowrap;
}

.card-size:hover { background: var(--color-bg-warm); }

.card-size[aria-pressed="true"] {
  background: var(--color-text);
  color: var(--color-bg);
}

/* La fiche indisponible garde son selecteur lisible mais inerte : rien
   n'est commandable dans aucun format. */
.is-unavailable .card-sizes { opacity: 0.55; }
.is-unavailable .card-size { pointer-events: none; }

/* Sur la carte large de la signature, le selecteur ne s'etire pas sur
   toute la largeur : deux formats sur 700 px donneraient deux pavés. */
.featured-card .card-sizes {
  align-self: start;
  width: fit-content;
  margin: var(--space-3) 0 0;
}

.featured-card .card-size { padding: 2px var(--space-4); }

/* ---------- Compteurs portés par les puces de filtre ---------- */

.chip-count {
  margin-left: var(--space-2);
  padding: 1px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-subtle);
}

.chip[aria-pressed="true"] .chip-count {
  background: var(--color-surface);
  color: var(--color-primary);
}

.chip[disabled] { opacity: 0.45; cursor: not-allowed; }

/* ---------- Carte signature ---------- */

.featured-card {
  display: flex;
  flex-direction: column;
  margin-bottom: var(--space-4);
  border-radius: var(--radius-xl);
  background: var(--color-text);
  color: var(--color-bg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}

@media (min-width: 720px) {
  .featured-card { flex-direction: row; }
  .featured-card__media { flex: 0 0 300px; }
}

/* Sur mobile le visuel est un bandeau, pas un carre : la fiche signature
   doit tenir dans un ecran avec son texte et son bouton, sinon elle pousse
   toute la grille sous la ligne de flottaison. */
.featured-card__media {
  position: relative;
  aspect-ratio: 16 / 9;
  max-height: 140px;
  background: color-mix(in srgb, var(--color-bg) 6%, transparent);
}

@media (min-width: 720px) {
  .featured-card__media { aspect-ratio: auto; max-height: none; min-height: 200px; }
}

.featured-card__media picture { position: absolute; inset: 0; display: block; }

/* Meme correctif que pour .card-img-wrap, et pour la meme raison : une photo
   non carree imposait sa hauteur au bandeau au lieu de se laisser recadrer. */
.featured-card__media > img { position: absolute; inset: 0; }

.featured-card__media img,
.featured-card__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

.featured-card__scribble {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  z-index: 1;
  margin: 0;
  padding: 0;
  max-width: 11rem;
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  color: var(--color-bg);
  text-align: right;
  text-shadow: 0 2px 10px color-mix(in srgb, var(--color-text-shadow) 45%, transparent);
  transform: rotate(-3deg);
}

.featured-card__caption {
  position: absolute;
  left: var(--space-4);
  bottom: var(--space-4);
  z-index: 1;
  margin: 0;
  padding-left: var(--space-4);
  border-left: 2px solid color-mix(in srgb, var(--color-bg) 70%, transparent);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-bg);
  text-shadow: 0 2px 10px color-mix(in srgb, var(--color-text-shadow) 45%, transparent);
}

@media (max-width: 719px) {
  .featured-card__scribble,
  .featured-card__caption,
  .featured-card__tagline { display: none; }

  .featured-card__body { padding: var(--space-4); gap: var(--space-1); }
  .featured-card__ing { padding-top: 0; }
  .featured-card__meta { padding-top: var(--space-2); }
  .featured-card__size-label { margin-top: 0; }
  .featured-card .card-sizes { margin: var(--space-2) 0 0; }
  .featured-card__foot { padding-top: var(--space-3); }
}

.featured-card__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
  min-width: 0;
}

.featured-card__badge {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
}

.featured-card__body h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
}

.featured-card__tagline {
  margin: 0;
  max-width: 46ch;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: color-mix(in srgb, var(--color-bg) 86%, transparent);
}

.featured-card__ing {
  margin: 0;
  max-width: 46ch;
  padding-top: var(--space-2);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: color-mix(in srgb, var(--color-bg) 78%, transparent);
}

.featured-card__meta {
  margin: 0;
  padding-top: var(--space-3);
  border-top: 1px solid color-mix(in srgb, var(--color-bg) 14%, transparent);
  font-size: var(--text-xs);
  color: color-mix(in srgb, var(--color-bg) 62%, transparent);
}

.featured-card__size-label {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: color-mix(in srgb, var(--color-bg) 86%, transparent);
}

.featured-card__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: auto;
  padding-top: var(--space-4);
}

.featured-card__price {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

.featured-card__size { font-size: var(--text-xs); color: color-mix(in srgb, var(--color-bg) 66%, transparent); }

/* Le « + » rond ne se lit pas sur un aplat sombre de cette taille : la
   signature porte un bouton libellé. */
.add-btn--wide {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  width: auto;
  height: var(--control-height);
  padding: 0 var(--space-5);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.qty-stepper--light {
  background: color-mix(in srgb, var(--color-bg) 12%, transparent);
  border-color: transparent;
}

.qty-stepper--light input.qty-input { color: var(--color-bg); }
.qty-stepper--light input.qty-input:focus { background: color-mix(in srgb, var(--color-surface) 12%, transparent); border-color: var(--color-bg); }
.qty-stepper--light button { background: var(--color-bg); color: var(--color-danger); }

.featured-card__perks {
  display: grid;
  gap: var(--space-4);
  margin: var(--space-2) 0 0;
  padding: var(--space-4) 0 0;
  border-top: 1px solid color-mix(in srgb, var(--color-bg) 14%, transparent);
  list-style: none;
}

@media (min-width: 480px) {
  .featured-card__perks { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 719px) {
  .featured-card__perks { display: none; }
}

.featured-card__perks li {
  display: grid;
  gap: 2px;
  padding-left: var(--space-4);
  border-left: 2px solid color-mix(in srgb, var(--color-bg) 20%, transparent);
}

.featured-card__perks strong {
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  color: var(--color-bg);
}

.featured-card__perks span {
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  color: color-mix(in srgb, var(--color-bg) 62%, transparent);
}

.featured-card.is-unavailable { opacity: 0.6; }

/* ---------- Panneau horaires ---------- */

.hours-status {
  margin: 0 0 var(--space-4);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--color-success);
}

.hours-status.is-closed { color: var(--color-warning); }

.hours th,
.hours td { vertical-align: middle; }

.hours td { text-align: right; }

.hours-chip {
  display: inline-flex;
  align-items: center;
  margin-left: var(--space-1);
  padding: var(--space-1) var(--space-3);
  margin-bottom: var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  font-size: var(--text-sm);
  color: var(--color-text);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.hours-chip--off { color: var(--color-text-subtle); }

/* La ligne du jour est surlignée sur toute sa largeur : chercher « on est
   quel jour » dans une colonne de sept lignes est le geste qu'elle évite. */
.hours .today th,
.hours .today td {
  background: var(--color-primary-soft);
  color: var(--color-text);
  font-weight: var(--weight-bold);
  border-bottom-color: transparent;
}

.hours .today th { border-radius: var(--radius-sm) 0 0 var(--radius-sm); padding-left: var(--space-2); }
.hours .today td { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; padding-right: var(--space-2); }
.hours .today .hours-chip { background: var(--color-surface); }

.hours-today {
  font-weight: var(--weight-medium);
  font-size: var(--text-xs);
  color: var(--color-primary);
}

.hours-note {
  margin: var(--space-4) 0 0;
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

/* ---------- Icônes (lot 5f) ----------
   Le jeu est intégré en tête de index.html (symboles i-…). Un seul trait
   pour toutes : 1,8 px sur la grille de 24, arrondi. */

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.i {
  width: 24px;
  height: 24px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.btn .i { width: 20px; height: 20px; }

/* ---------- Barre d'onglets mobile (lot 5f) ----------
   Carte · Panier · Ma commande · Compte. Panier et Ma commande ouvrent le
   tiroir ; Carte est l'onglet de cette page. L'onglet courant se repère à
   l'icône pleine et à la pastille, en plus de la couleur. */

.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-sticky);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  height: calc(var(--tabbar-height) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: color-mix(in srgb, var(--color-bg) 94%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--color-border);
}

@media (min-width: 768px) { .tabbar { display: none; } }

.tabbar__item {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 2px;
  min-width: 0;
  min-height: var(--tabbar-height);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  /* Une seule ligne : « Ma commande » passait sur deux lignes à 375 px
     dans la maquette, et le bas des libellés sortait de la barre. */
  line-height: 1.2;
  white-space: nowrap;
  color: var(--color-text-muted);
  text-decoration: none;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.tabbar__icon {
  position: relative;
  display: grid;
  place-items: center;
  width: 52px;
  height: 28px;
  border-radius: var(--radius-pill);
  transition:
    background-color var(--duration-base) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
}

.tabbar__item:active .tabbar__icon { transform: scale(0.9); }
.tabbar__item:focus-visible { outline: none; }
.tabbar__item:focus-visible .tabbar__icon { box-shadow: 0 0 0 var(--focus-width) var(--color-focus); }

.tabbar__item .i-actif { display: none; }
.tabbar__item[aria-current="page"] { color: var(--color-primary); font-weight: var(--weight-bold); }
.tabbar__item[aria-current="page"] .tabbar__icon { background: var(--color-primary-soft); }
.tabbar__item[aria-current="page"] .i { stroke-width: 2; }
.tabbar__item[aria-current="page"] .i-repos { display: none; }
.tabbar__item[aria-current="page"] .i-actif { display: inline; }

/* Positionnée sur l'onglet et non plus sur l'icône (lot 5b, A11Y-01 : la
   pastille suit le mot « Panier » dans le document). L'icône fait 52 px
   de large, centrée, et le contenu de l'onglet (46 px) est centré dans
   ses 56 px : la pastille retombe à l'angle haut droit de l'icône. */
.tabbar__item { position: relative; }

.tabbar__badge {
  position: absolute;
  top: calc(50% - 29px);
  right: calc(50% - 28px);
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: var(--color-text-invert);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  line-height: 20px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 0 0 2px var(--color-bg);
}

.tabbar__badge.is-bump { animation: tabbar-rebond var(--duration-slow) var(--ease-out); }
@keyframes tabbar-rebond { 40% { transform: scale(1.35); } }

/* Sur mobile, l'onglet Panier et sa pastille remplacent le panier
   flottant : un bandeau fixe de moins (UX-02). Le pied de page laisse la
   hauteur de la barre, et la notification d'ajout se pose juste au-dessus
   (BUG-05 : elle ne recouvre rien). */
@media (max-width: 767px) {
  .mini-cart { display: none; }
  .cart-toast { bottom: calc(var(--tabbar-height) + var(--space-3) + env(safe-area-inset-bottom)); }
  .footer { padding-bottom: calc(var(--space-8) + var(--tabbar-height)); }
}

/* ---------- Ma commande (lot 5f) ---------- */

.order-panel { display: grid; gap: var(--space-5); align-content: start; }

.order-track { display: grid; gap: var(--space-4); }
.order-track h3 { font-size: var(--text-xl); }
.order-track p { margin: 0; color: var(--color-text-muted); }
.order-track__head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); }
.order-track__ref { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--color-text-subtle); white-space: nowrap; }

.order-steps { list-style: none; margin: 0; padding: 0; display: grid; }
.order-step {
  position: relative;
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: var(--space-3);
  align-items: start;
  min-height: 56px;
}
.order-step::before {
  content: "";
  position: absolute;
  left: 13px;
  top: 28px;
  bottom: 0;
  width: 2px;
  background: var(--color-border);
}
.order-step:last-child { min-height: 0; }
.order-step:last-child::before { display: none; }
.order-step__dot {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--color-border-field);
  background: var(--color-surface);
}
.order-step__dot .i { width: 16px; height: 16px; stroke-width: 3; }
.order-step__label { padding-top: 2px; font-weight: var(--weight-semibold); color: var(--color-text); }
.order-step__label small { display: block; font-size: var(--text-xs); font-weight: var(--weight-regular); color: var(--color-text-subtle); }
.order-step.is-done .order-step__dot { background: var(--color-success); border-color: var(--color-success); color: var(--color-text-invert); }
.order-step.is-done::before { background: var(--color-success); }
.order-step.is-current .order-step__dot { border-color: var(--color-primary); }
.order-step.is-current .order-step__dot::after {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-primary);
  animation: suivi-pouls 1.6s ease-in-out infinite;
}
.order-step.is-current .order-step__label { color: var(--color-primary); }
@keyframes suivi-pouls { 50% { transform: scale(1.5); opacity: 0.5; } }
@media (prefers-reduced-motion: reduce) { .order-step.is-current .order-step__dot::after { animation: none; } }

.order-track__lines { display: grid; gap: var(--space-2); padding-top: var(--space-3); border-top: 1px solid var(--color-border); }
.order-track__line { display: flex; justify-content: space-between; gap: var(--space-3); font-variant-numeric: tabular-nums; }
.order-track__total { display: flex; justify-content: space-between; align-items: baseline; font-weight: var(--weight-bold); }
.order-track__total strong { font-family: var(--font-display); font-size: var(--text-xl); font-variant-numeric: tabular-nums; }
.order-track__note { padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); font-weight: var(--weight-semibold); }
.order-track__note--ready { background: var(--color-success-soft); color: var(--color-success); }
.order-track__reorder { display: grid; gap: var(--space-2); margin-top: var(--space-4); }

/* « Me prévenir quand elle est prête » (notifications). */
.order-notify { display: grid; gap: var(--space-2); margin-top: var(--space-4); }
.order-notify[hidden] { display: none; }
.order-notify__status:empty { display: none; }
.order-notify__status { margin: 0; color: var(--color-success); font-weight: var(--weight-semibold); }
.order-notify__hint { margin: 0; color: var(--color-text-muted); font-size: var(--text-sm); }
.order-track__note--cancelled { background: var(--color-danger-soft); color: var(--color-danger); }

.contact-card {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
}
.contact-card h3 { font-size: var(--text-lg); }
.contact-card p { margin: 0; color: var(--color-text-muted); }
.contact-card__phone { font-weight: var(--weight-semibold); color: var(--color-text); font-variant-numeric: tabular-nums; }
.contact-card__actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-top: var(--space-2); }
.contact-card__actions .btn { padding-inline: var(--space-3); }
.contact-card__hours { justify-self: start; margin-top: var(--space-1); color: var(--color-primary); font-weight: var(--weight-semibold); }

/* Le tiroir défile seul : arrivé en bout de liste, la page derrière ne
   prend pas le relais (elle est déjà verrouillée, mais le rebond iOS
   faisait encore bouger l'arrière-plan). */
.drawer-body { overscroll-behavior: contain; }

/* ---------- En-tête et catégories sur mobile (lot 5f, UX-02) ----------
   Au repos, en-tête, catégories et onglets occupaient 168 px sur 812
   (20,7 %). Objectif du plan : 18 % au plus. En-tête de 46 + 1 px de
   filet, catégories de 43 px, onglets de 56 px : 146 px, 18,0 %. Et quand
   on descend dans la carte, les catégories se rétractent sous l'en-tête
   (setupCatnavRetractable dans app.js) : il ne reste que 103 px. */
@media (max-width: 767px) {
  .site-header .topbar { min-height: 46px; }

  /* L'onglet Panier et l'onglet Compte de la barre du bas les remplacent.
     Le lien Compte était de surcroît une zone de 44 px sans rien
     d'affiché : son libellé est masqué sous 768 px. */
  .site-header .cart-btn,
  .site-header .account-link { display: none; }

  /* La pastille d'état reprend la place libérée : « c'est ouvert ? » se
     repose au moment de choisir. Ses textes sont courts (« Ouvert »,
     « Ouvre à 18:30 », « Ferme dans 30 min »). */
  .site-header .status-pill:not([hidden]) {
    display: inline-flex;
    padding: var(--space-1) var(--space-3);
  }

  .catnav {
    padding-block: var(--space-1);
    transition: transform var(--duration-base) var(--ease-out);
  }
  .catnav a { min-height: 34px; }
  .catnav a:active { transform: scale(0.96); }

  /* Rétractée sous l'en-tête, qui est au-dessus d'elle (z-header). */
  .catnav.is-retracted { transform: translateY(calc(-100% - 1px)); }
}

/* ---------- Grille pizzas en vignettes sur mobile ----------

   La maquette pose trois colonnes dès 390 px : on voit neuf recettes d'un
   coup au lieu de quatre, ce qui compte sur une carte de vingt-trois. La
   fiche se resserre en conséquence — sans descendre sous --text-xs, le
   plancher de lisibilité fixé dans tokens.css. */

@media (max-width: 559px) {
  /* :not(.grid-simple) — cette regle vient apres .grid-simple dans le fichier
     et l'ecrasait : les accompagnements et les boissons, qui sont des rangees
     « vignette + nom + bouton », se retrouvaient dans des colonnes de 107 px
     pour un contenu de 185 px. Chaque fiche debordait de sa cellule et la
     page entiere defilait lateralement sur telephone. */
  .grid:not(.grid-simple) { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }

  .grid .card { border-radius: var(--radius-md); }
  .grid .card-img-wrap { aspect-ratio: 1 / 1; }
  .grid .base-chip { display: none; }
  .grid .card-body { gap: var(--space-1); padding: var(--space-2); }

  .grid .card-title-row h3 {
    font-size: var(--text-xs);
    line-height: var(--leading-snug);
  }

  /* Deux lignes de garniture : de quoi reconnaître la recette, pas de quoi
     pousser le bouton d'ajout hors de l'écran. */
  .grid .card-ingredients {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: var(--text-xs);
    line-height: var(--leading-snug);
  }

  /* La ligne d'allergènes était masquée ici, l'information étant reprise par
     l'encart réglementaire en bas de carte. Cet encart a été retiré : elle
     redevient obligatoire sur la vignette, en deux lignes plutôt qu'en une,
     faute de place pour tenir sur 110 px. */
  .grid .card-allergens {
    white-space: normal;
    text-overflow: clip;
    /* overflow:visible laissait « Allergènes » — 65 px insecables — sortir de
       la vignette : a 320 px la page entiere defilait lateralement. Le mot
       reste entier, mais la boite le contient et le passe a la ligne. */
    overflow: hidden;
    overflow-wrap: anywhere;
    font-size: 0.68rem;
    line-height: var(--leading-snug);
  }

  .grid .card-controls {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
  }

  .grid .card-sizes { padding: 2px; gap: 2px; }
  .grid .card-size { min-height: 34px; padding: 2px 0; }
  .grid .card-size strong,
  .grid .card-size span { font-size: 0.68rem; }

  .grid .card-price { font-size: var(--text-sm); }
  .grid .card-price small { display: none; }

  /* Cible tactile pleine largeur : c'est le geste principal de la vignette. */
  .grid .add-btn,
  .grid .qty-stepper {
    width: 100%;
    border-radius: var(--radius-sm);
  }

  /* Dans une colonne de 110 px, deux boutons de 38 px ne laissaient que
     25 px au champ : le nombre y était coupé. Les boutons cèdent 4 px
     chacun, le champ prend ce qui reste. */
  .grid .qty-stepper button { width: 34px; height: 34px; }

  .grid input.qty-input {
    flex: 1 1 auto;
    width: auto;
    min-width: 30px;
  }
}

/* ---------- Page compte : colonne laterale et carte fidelite ---------- */

.account-side {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-width: 0;
}

.loyalty-card {
  background: var(--color-text);
  border-color: transparent;
  color: var(--color-bg);
}

.loyalty-card .orders-title { color: var(--color-bg); }
.loyalty-card__eyebrow { color: var(--color-accent); }

.loyalty-card__lead {
  margin: 0 0 var(--space-4);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: color-mix(in srgb, var(--color-bg) 72%, transparent);
}

.loyalty-card__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px dashed color-mix(in srgb, var(--color-bg) 35%, transparent);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-bg) 10%, transparent);
}

.loyalty-card__row code {
  flex: 1;
  min-width: 0;
  font-size: var(--text-base);
  letter-spacing: 0.06em;
  overflow-wrap: anywhere;
}

.loyalty-card__copy {
  flex: 0 0 auto;
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-text);
  font-weight: var(--weight-bold);
}

.loyalty-card__done {
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
  color: var(--color-accent);
}

/* ---------- Progression d'une commande en cours ---------- */

/* Un statut seul ne dit pas ce qu'il reste : « Confirmée » se lit pareil
   qu'on soit deuxieme ou dernier de la file. La barre situe l'etape. */
.co-progress {
  display: flex;
  gap: var(--space-2);
  margin: var(--space-3) 0;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.co-step {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.co-step::before {
  content: "";
  height: 5px;
  border-radius: var(--radius-pill);
  background: var(--color-border);
}

.co-step span {
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
  line-height: var(--leading-snug);
}

.co-step.is-done::before,
.co-step.is-current::before { background: var(--color-primary); }

.co-step.is-done span { color: var(--color-text-muted); font-weight: var(--weight-semibold); }

.co-step.is-current span {
  color: var(--color-danger);
  font-weight: var(--weight-bold);
}

.co-step__now {
  font-size: var(--text-xs);
  font-style: normal;
  color: var(--color-text-subtle);
}

/* La barre est reconstruite a chaque changement de statut : la transition
   ne peut pas porter sur la largeur, elle porte sur l'apparition du segment
   nouvellement atteint. */
.co-step.is-current::before {
  animation: step-fill var(--duration-slow) var(--ease-out);
  transform-origin: left center;
}

@keyframes step-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* ---------- Suivi en direct du statut ---------- */

.panel-title-row--live {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.orders-live {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.orders-live[hidden] { display: none; }

.orders-live__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-success);
  animation: live-pulse 2s var(--ease-out) infinite;
}

.orders-live.is-error { color: var(--color-danger); }
.orders-live.is-error .orders-live__dot { background: var(--color-danger); animation: none; }

@keyframes live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); box-shadow: 0 0 0 0 var(--color-success-soft); }
  50%      { opacity: 0.55; transform: scale(0.85); }
}

/* Le statut change tout seul, sans geste du client : la carte concernee
   s'allume quelques secondes, sinon la mise a jour passe inapercue sur une
   page qu'on ne regarde pas fixement. */
.client-order.is-status-changed {
  animation: order-updated 2.4s var(--ease-out);
}

@keyframes order-updated {
  0%   { box-shadow: 0 0 0 0 var(--color-primary); border-color: var(--color-primary); }
  30%  { box-shadow: 0 0 0 4px var(--color-primary-soft); border-color: var(--color-primary); }
  100% { box-shadow: 0 0 0 0 transparent; border-color: var(--color-border); }
}

.status-chip.is-changed { animation: chip-flip 620ms var(--ease-out); }

@keyframes chip-flip {
  0%   { transform: translateY(-6px) scale(0.9); opacity: 0; }
  60%  { transform: translateY(0) scale(1.06); opacity: 1; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

/* Respect de prefers-reduced-motion : le changement reste signale par la
   couleur, la pastille et le message, sans mouvement. */
@media (prefers-reduced-motion: reduce) {
  .co-step.is-current::before,
  .client-order.is-status-changed,
  .status-chip.is-changed,
  .orders-live__dot { animation: none; }
}

} /* fin de @layer site */

/* ---------- kabanito.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* ---------- Kabanito ---------- */

.kabanito-card {
  display: grid;
  gap: var(--space-5);
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

@media (min-width: 800px) {
  .kabanito-card {
    grid-template-columns: minmax(0, 1.1fr) minmax(16rem, 0.9fr);
    align-items: start;
    gap: var(--space-6);
  }
}

.kabanito-card__badge {
  display: inline-block;
  margin: 0 0 var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.kabanito-card__offer h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
}

.kabanito-card__formula {
  margin: var(--space-2) 0 var(--space-4);
  font-size: var(--text-base);
  line-height: var(--leading-snug);
  color: var(--color-text-muted);
}

.kabanito-card__bases {
  margin: 0 0 var(--space-4);
  padding: 0;
  border: 0;
}

.kabanito-card__bases legend {
  margin-bottom: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.kabanito-card__choices,
.kabanito-card__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.kabanito-choice,
.kabanito-chip {
  cursor: pointer;
}

.kabanito-choice input,
.kabanito-chip input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.kabanito-choice span,
.kabanito-chip span {
  display: inline-block;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-bg);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.kabanito-choice input:checked + span,
.kabanito-chip input:checked + span {
  border-color: var(--color-text);
  background: var(--color-text);
  color: var(--color-bg);
}

.kabanito-choice input:focus-visible + span,
.kabanito-chip input:focus-visible + span {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

.kabanito-card__buy {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.kabanito-card__buy .price {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

.kabanito-card__toppings-label {
  margin: 0 0 var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

@media (min-width: 800px) {
  .kabanito-card__toppings {
    padding-left: var(--space-5);
    border-left: 1px solid var(--color-border);
  }
}

.kabanito-card__photo {
  display: block;
  width: 100%;
  height: 10rem;
  margin: 0 0 var(--space-3);
  object-fit: cover;
  border-radius: var(--radius-md);
}

@media (min-width: 800px) {
  .kabanito-card__photo {
    height: 12rem;
  }
}

} /* fin de @layer site */

/* ---------- photos.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* Photos de la carte : cadre fixe, image entière, jamais écrasée ni recadrée. */

.card-img-wrap,
.featured-card__media {
  background: var(--color-surface-sunken);
  overflow: hidden;
}

.card-img-wrap img,
.card-img-wrap > img,
.card-img,
.featured-card__media img,
.featured-card__img {
  max-width: 100%;
  max-height: 100%;
}

/* Ne plus étirer la photo signature sur toute la hauteur de la fiche. */
.featured-card__media {
  max-height: 220px;
  flex-shrink: 0;
}

@media (min-width: 720px) {
  .featured-card__media {
    width: 280px;
    max-width: 42%;
    align-self: center;
  }
}

.kabanito-card__photo {
  display: block;
  width: 100%;
  height: auto;
  max-height: 16rem;
  aspect-ratio: 4 / 3;
  margin: 0 0 var(--space-3);
  background: var(--color-surface-sunken);
  border-radius: var(--radius-md);
}


.photo-preview,
.gallery-item {
  background: var(--color-photo-frame);
  overflow: hidden;
}

.photo-preview img,
.gallery-item img {
  width: 100%;
  height: 100%;
}

} /* fin de @layer site */

/* Ce qui portait !important : la couche « surcouches » vient après « site »
   et l'emporte sur elle quelle que soit la spécificité, comme le faisait
   !important, sans en avoir les effets de bord. */
@layer surcouches {

  .card-img-wrap img,
  .card-img-wrap > img,
  .card-img,
  .featured-card__media img,
  .featured-card__img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
  }

  .featured-card__media {
    aspect-ratio: 4 / 3;
  }

  @media (min-width: 720px) {
    .featured-card__media {
      flex: 0 0 280px;
      max-height: none;
      min-height: 0;
      aspect-ratio: 4 / 3;
    }
  }

  .kabanito-card__photo {
    object-fit: contain;
    object-position: center;
  }

  .card-simple picture,
  .card-simple img,
  .card-simple .thumb {
    object-fit: contain;
    object-position: center;
  }

  .photo-preview img,
  .gallery-item img {
    object-fit: contain;
    object-position: center;
  }

}

/* ---------- catalog-compact.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* Carte vitrine — dense (2–3 / 4 colonnes) et plus soignée. */

#pizzas,
#accompagnements,
#boissons {
  padding-bottom: var(--space-8);
}

/* ---------- Grilles ---------- */

.grid {
  gap: 0.85rem;
}

@media (min-width: 720px) {
  .grid {
    gap: 1.1rem;
  }
}


.grid-simple {
  gap: 0.65rem;
}

@media (min-width: 720px) {
  .grid-simple {
    gap: 1rem;
  }
}

/* ---------- Fiches pizza ---------- */

.grid .card {
  position: relative;
  border: 1px solid color-mix(in srgb, var(--color-border-strong) 65%, transparent);
  border-radius: 18px;
  background: var(--color-surface);
  box-shadow: 0 8px 22px color-mix(in srgb, var(--color-shadow-warm) 6%, transparent);
  overflow: hidden;
  transition: transform var(--duration-base) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out),
              border-color var(--duration-base) var(--ease-out);
}

.grid .card:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--color-primary) 28%, transparent);
  box-shadow: 0 16px 34px color-mix(in srgb, var(--color-shadow-warm) 12%, transparent);
}

.grid .card-img-wrap {
  aspect-ratio: 5 / 4;
  background:
    radial-gradient(circle at 50% 42%, var(--color-photo-glow) 0%, var(--color-photo-edge) 72%);
}

.grid .card-img-wrap img,
.grid .card-img-wrap > img,
.grid .card-img {
  transform: scale(1.02);
  transition: transform 420ms var(--ease-out);
}

.grid .card:hover .card-img-wrap img {
  transform: scale(1.07);
}

.grid .base-chip {
  left: 0.65rem;
  bottom: 0.65rem;
  padding: 0.2rem 0.55rem;
  background: color-mix(in srgb, var(--color-bg) 94%, transparent);
  box-shadow: 0 1px 4px color-mix(in srgb, var(--color-text) 12%, transparent);
  font-size: 0.68rem;
  letter-spacing: 0.02em;
}

.grid .card-body {
  gap: 0.4rem;
  padding: 0.85rem 0.9rem 0.95rem;
}

.grid .card-title-row h3 {
  font-family: var(--font-display);
  font-size: 1.02rem;
  font-weight: var(--weight-bold);
  letter-spacing: -0.02em;
}

.grid .card-ingredients {
  color: var(--color-text-muted);
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.grid .card-allergens {
  color: var(--color-text-subtle);
  font-size: 0.7rem;
  letter-spacing: 0.01em;
  /* A11Y-04 : une opacité de 0,82 ramenait --color-text-subtle sous 4,5:1.
     La couleur seule est déjà la plus discrète qui reste lisible. */
}

.grid .card-sizes {
  margin: 0.15rem 0 0;
  padding: 3px;
  background: var(--color-photo-bg);
  border-radius: 999px;
}

.grid .card-size {
  min-height: 30px;
  border-radius: 999px;
  padding: 0 0.2rem;
}

.grid .card-size strong {
  font-size: 0.68rem;
  font-weight: var(--weight-semibold);
}

.grid .card-size span {
  font-size: 0.68rem;
  /* A11Y-04 : plus d'opacité, qui faisait tomber le prix sous 4,5:1. */
}

.grid .card-size[aria-pressed="true"] {
  background: var(--color-text);
  color: var(--color-bg);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--color-text) 20%, transparent);
}

.grid .card-controls {
  grid-template-columns: 1fr auto;
  align-items: center;
  padding-top: 0.45rem;
  margin-top: 0.15rem;
  border-top: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
}

.grid .card-price {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: var(--weight-black);
  letter-spacing: -0.03em;
  color: var(--color-text);
}

.grid .card-price small {
  display: none;
}

.grid .add-btn,
.grid .qty-stepper {
  width: auto;
}

.grid .add-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  box-shadow: 0 6px 14px color-mix(in srgb, var(--color-primary) 28%, transparent);
}

.grid .add-btn:hover:not([disabled]) {
  transform: scale(1.06);
}

@media (max-width: 719px) {
  .grid .card-body {
    padding: 0.7rem 0.7rem 0.8rem;
    gap: 0.28rem;
  }

  .grid .card-title-row h3 {
    font-size: 0.92rem;
  }

  .grid .badge-signature {
    display: none;
  }

  .grid .card-ingredients {
    -webkit-line-clamp: 1;
    line-clamp: 1;
  }

  .grid .card-price {
    font-size: 1.02rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .grid .card,
  .grid .card-img-wrap img,
  .grid .add-btn {
    transition: none;
  }

  .grid .card:hover {
    transform: none;
  }
}

/* ---------- Accompagnements & boissons ---------- */

.card-simple {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) 36px;
  align-items: center;
  column-gap: 0.55rem;
  min-height: 0;
  padding: 0.55rem 0.55rem 0.55rem 0.5rem;
  border: 1px solid color-mix(in srgb, var(--color-border-strong) 65%, transparent);
  border-radius: 16px;
  background: var(--color-surface);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--color-shadow-warm) 5%, transparent);
  overflow: hidden;
}

.card-simple picture,
.card-simple .thumb,
.card-simple .emoji-thumb {
  min-width: 52px;
  border-radius: 12px;
  background:
    radial-gradient(circle at 50% 45%, var(--color-surface) 0%, var(--color-photo-edge-light) 70%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-border-strong) 35%, transparent);
}

.card-simple .info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.12rem;
  min-width: 0;
  overflow: hidden;
}

.card-simple h3 {
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  overflow-wrap: anywhere;
  word-break: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-simple .price {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: var(--weight-black);
  letter-spacing: -0.02em;
  color: var(--color-text);
  white-space: nowrap;
}

.card-simple .card-allergens {
  display: none;
}

.card-simple .card-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  width: 36px;
}

.card-simple .add-btn {
  min-width: 36px;
  box-shadow: 0 4px 10px color-mix(in srgb, var(--color-primary) 24%, transparent);
}

.card-simple .qty-stepper {
  height: 36px;
  gap: 0;
}

.card-simple .qty-stepper button {
  width: 28px;
  height: 28px;
}

.card-simple input.qty-input {
  width: 1.6rem;
  min-width: 0;
}

@media (min-width: 720px) {
  .card-simple {
    grid-template-columns: 64px minmax(0, 1fr) 40px;
    column-gap: 0.75rem;
    padding: 0.7rem 0.75rem;
  }

  .card-simple picture,
  .card-simple .thumb,
  .card-simple .emoji-thumb {
    min-width: 64px;
    border-radius: 14px;
  }

  .card-simple h3 {
    font-size: 0.92rem;
    overflow-wrap: break-word;
    word-break: normal;
  }

  .card-simple .price {
    font-size: 1.05rem;
  }

}

/* ---------- Kabanito : un peu plus de tenue ---------- */

.kabanito-card {
  border-radius: 20px;
  box-shadow: 0 10px 28px color-mix(in srgb, var(--color-shadow-warm) 7%, transparent);
}

.kabanito-card__photo {
  border-radius: 14px;
  background:
    radial-gradient(circle at 50% 42%, var(--color-photo-glow) 0%, var(--color-photo-edge) 72%);
}

} /* fin de @layer site */

/* Ce qui portait !important : la couche « surcouches » vient après « site »
   et l'emporte sur elle quelle que soit la spécificité, comme le faisait
   !important, sans en avoir les effets de bord. */
@layer surcouches {

  .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  @media (min-width: 720px) {
    .grid {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }

  @media (min-width: 1120px) {
    #grid-pizzas.grid {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
  }

  .grid-simple {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  @media (min-width: 720px) {
    .grid-simple {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }

  .grid .card-img-wrap img,
  .grid .card-img-wrap > img,
  .grid .card-img {
    object-fit: cover;
    object-position: center 45%;
  }

  .card-simple picture,
  .card-simple .thumb,
  .card-simple .emoji-thumb {
    width: 52px;
    height: 52px;
    object-fit: contain;
  }

  .card-simple .add-btn {
    width: 36px;
    height: 36px;
  }

  @media (min-width: 720px) {
    .card-simple picture,
    .card-simple .thumb,
    .card-simple .emoji-thumb {
      width: 64px;
      height: 64px;
    }
  }

  @media (min-width: 720px) {
    .card-simple .card-controls,
    .card-simple .add-btn {
      width: 40px;
      height: 40px;
    }
  }

}

/* ---------- pwa.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* ============================================================
   Kabana Pizz — Interface PWA
   ============================================================
   Bandeau d'installation, bandeau de mise à jour et ajustements
   du mode autonome (application épinglée). Feuille séparée : ces
   règles ne servent qu'aux appareils qui savent installer le site,
   et n'ont rien à faire dans la feuille du back-office.
   ============================================================ */

.pwa-banner {
  position: fixed;
  /* Les elements fixes ignorent la marge de securite posee sur <body> :
     en paysage sur un ecran a encoche, ils passeraient dessous. */
  left: max(var(--page-gutter), env(safe-area-inset-left));
  right: max(var(--page-gutter), env(safe-area-inset-right));
  /* Sous le panier flottant dans la pile, jamais au-dessus d'une
     modale de commande. */
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom));
  z-index: var(--z-sticky);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  max-width: 520px;
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity var(--duration-base) var(--ease-out),
    transform var(--duration-base) var(--ease-out);
}

.pwa-banner.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Le panier flottant occupe déjà le bas de l'écran d'accueil :
   le bandeau se pose au-dessus tant qu'il est affiché. */
body:has(.mini-cart:not([hidden])) .pwa-banner {
  bottom: calc(var(--space-4) + 56px + var(--space-3) + env(safe-area-inset-bottom));
}

/* Un tiroir ouvert (panier, commande) prend toute l'attention :
   le bandeau ne doit pas flotter par-dessus. */
body:has(.drawer-overlay:not([hidden])) .pwa-banner {
  display: none;
}

.pwa-banner__icon {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
}

.pwa-banner__text {
  flex: 1 1 12rem;
  min-width: 0;
}

.pwa-banner__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  color: var(--color-text);
}

.pwa-banner__hint {
  margin: var(--space-1) 0 0;
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  color: var(--color-text-muted);
}

.pwa-banner__actions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.pwa-banner__close {
  display: grid;
  place-items: center;
  /* 44 px : même zone tactile que les autres commandes du site. */
  width: var(--tap-min);
  height: var(--tap-min);
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--text-xl);
  line-height: 1;
  cursor: pointer;
}

.pwa-banner__close:hover {
  background: var(--color-surface-sunken);
  color: var(--color-text);
}

.pwa-banner__steps {
  flex: 1 0 100%;
  margin: 0;
  padding: var(--space-3) 0 0 var(--space-5);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
}

.pwa-banner__steps li + li { margin-top: var(--space-1); }

.pwa-banner--update {
  border-color: var(--color-primary-border);
  background: var(--color-primary-soft);
}

@media (prefers-reduced-motion: reduce) {
  .pwa-banner { transition: none; }
}

/* ============================================================
   Mode autonome (application installée)
   ============================================================ */

/* Sans barre d'adresse, l'en-tête colle à l'encoche et à la barre
   d'état : on rend la marge de sécurité au contenu. */
@media (display-mode: standalone) {
  .topbar { padding-top: env(safe-area-inset-top); }
  .footer { padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom)); }

  /* Lot 5f : sur l'accueil de l'application installée, le pied de page
     « site » (réseaux, crédits, liens légaux) disparaît, comme dans une
     application. Les mentions légales, les CGV et la confidentialité
     restent en bas de l'onglet Compte (compte.html), qui garde son pied
     de page : deux appuis depuis n'importe où. */
  body:has(#tabbar) .footer { display: none; }
}

/* En paysage sur un écran à encoche, `viewport-fit=cover` laisse le
   contenu passer sous l'arrondi : ces marges valent 0 ailleurs. */
@media (orientation: landscape) {
  body {
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
}

/* Même raison pour le panier flottant, seul autre élément fixe du site :
   `viewport-fit=cover` (ajouté pour le mode autonome) laisse désormais le
   contenu s'étendre sous l'encoche. Les valeurs valent 0 partout ailleurs. */
@media (orientation: landscape) {
  .mini-cart {
    left: max(var(--page-gutter), env(safe-area-inset-left));
    right: max(var(--page-gutter), env(safe-area-inset-right));
  }
}

} /* fin de @layer site */

/* ---------- dialogue.css ---------- */
/* Couche « site » : l'ordre des couches est posé en tête de fonts.css. */
@layer site {

/* ============================================================
   Boîte de confirmation (confirmer(), js/utilitaires-dom.js)
   ============================================================
   Feuille à part parce qu'elle sert au site, à l'espace client et au
   back-office, et qu'admin.css ne charge pas base.css.

   États : Annuler (contour), Valider (rouge de l'enseigne), Danger
   (rouge d'alerte). Les deux boutons sont écartés aux deux bords : le
   choix destructeur n'est jamais là où tombe le pouce par habitude. */

.confirm-dialog {
  width: min(28rem, calc(100vw - 2 * var(--space-4)));
  padding: 0;
  border: 0;
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-lg);
}

.confirm-dialog::backdrop { background: var(--color-overlay); }

.confirm-dialog__corps {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-6);
}

.confirm-dialog__titre {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: var(--leading-tight);
}

.confirm-dialog__texte {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

.confirm-dialog__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.confirm-dialog__btn {
  flex: 0 1 auto;
  min-width: 8rem;
  min-height: var(--control-height);
  padding: 0 var(--space-5);
  border: var(--border-width) solid var(--color-border-field);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--ease-out);
}

.confirm-dialog__btn:active { transform: scale(0.98); }

.confirm-dialog__btn--valider {
  border-color: transparent;
  background: var(--color-primary);
  color: var(--color-text-invert);
}

.confirm-dialog__btn--danger {
  border-color: transparent;
  background: var(--color-danger);
  color: var(--color-text-invert);
}

/* Sur un téléphone, les deux boutons s'empilent en pleine largeur, le
   choix sans risque en bas, sous le pouce. */
@media (max-width: 420px) {
  .confirm-dialog__actions { flex-direction: column-reverse; }
  .confirm-dialog__btn { width: 100%; }
}

@media (prefers-reduced-motion: no-preference) {
  .confirm-dialog[open] { animation: confirm-entree var(--duration-base) var(--ease-out); }
}

@keyframes confirm-entree {
  from { opacity: 0; transform: translateY(var(--space-2)) scale(0.98); }
}

} /* fin de @layer site */
