@import url('/css/tokens.css');

/* ==========================================================================
   Site de commande en ligne.

   Vitrine, pas outil : marque centrée, bannière d'accueil, rayons de plats
   qui défilent, barre d'onglets avec le panier au centre. Pensé d'abord
   pour un téléphone tenu d'une main dans une salle de restaurant.

   Les couleurs, les rayons et la typographie viennent de la charte
   commune (/css/tokens.css), celle de la caisse : le client et l'équipe
   voient le même logiciel, seule la mise en page diffère.

   Aucune police téléchargée : le site doit s'afficher intact sur le Wi-Fi
   du restaurant, même sans accès à internet.
   ========================================================================== */

:root {
  /* Les noms locaux restent, mais ils pointent tous sur la charte
     commune : une couleur ne se corrige qu'a un seul endroit, et les
     quatre interfaces bougent ensemble. */
  --ink:        var(--text);
  --ink-soft:   var(--text-2);
  --ink-faint:  var(--muted);
  --paper:      var(--bg);
  --line:       var(--border);
  --line-soft:  var(--surface-3);

  /* L'accent du site est celui de la caisse. */
  --gold:       var(--accent);
  --gold-deep:  var(--accent-dark);
  --gold-soft:  var(--accent-soft);
  --gold-line:  var(--border-strong);

  --green:      var(--success);
  --green-bg:   var(--success-soft);
  --danger-bg:  var(--danger-soft);

  /* Une ombre NEUTRE et courte. Le halo coloré qui tenait cette place
     faisait briller chaque bouton rond comme un néon : c'est l'effet le
     plus sûr pour qu'une interface ait l'air d'une maquette. Un objet
     posé projette une ombre grise, pas une lueur de sa propre couleur. */
  --shadow-gold: 0 1px 3px rgba(40, 34, 26, .18);

  /* Une seule famille, celle de la caisse : le site ne doit pas avoir
     l'air d'un autre logiciel. */
  --serif: var(--font);
  --sans:  var(--font);

  --top-h: 4.5rem;
  --bar-h: 4.25rem;
}

* { box-sizing: border-box; }

html { font-size: 16px; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--sans);
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }

a { color: var(--gold-deep); text-decoration: none; }

:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-radius: var(--r-sm); }

.hidden { display: none !important; }
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* =========================================================== Barre du haut */


/* ==================================================== COMME UNE APPLICATION

   Une fois posee sur l'ecran d'accueil, la page ne doit plus SE
   COMPORTER comme une page. Quatre detrompeurs, et ce sont eux qui font
   la difference entre << un site en plein ecran >> et << une
   application >> :

   1. L'ENCOCHE ET LA BARRE D'ETAT. `viewport-fit=cover` fait passer la
      page SOUS l'heure et la batterie. Sans garde, le titre se
      retrouvait derriere l'encoche.

   2. LE TIRE-POUR-RAFRAICHIR. Un doigt qui descend en haut de liste
      rechargeait la page entiere -- panier compris, sur un reseau de
      restaurant. Aucune application mobile ne fait cela.

   3. L'ELASTIQUE. Le rebond en fin de liste montre le fond du
      navigateur derriere la page : le decor de dessous trahit le site.

   4. LE FLASH BLEU au bout du doigt, et la selection de texte qui
      s'accroche quand on fait defiler. Le texte reste selectionnable la
      ou il sert -- un numero de telephone, une adresse.
   ========================================================================== */

html, body {
  overscroll-behavior-y: contain;
}
body {
  -webkit-tap-highlight-color: transparent;
}
/* Les commandes ne se selectionnent pas ; le contenu, si. */
button, .tab, .cat, .nav, .top, .tabbar, .bar, .sheet__head {
  -webkit-user-select: none; user-select: none;
}

/* La barre du haut passe sous l'encoche : elle garde sa hauteur, et
   pousse son contenu en dessous de la zone reservee par le systeme. */
.top {
  position: sticky; top: 0; z-index: 40;
  height: calc(var(--top-h) + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
  display: grid; grid-template-columns: 3rem 1fr auto; align-items: center;
  gap: .5rem;
  padding-right: 1rem; padding-left: 1rem;
  /* LE BLANC DE LA BARRE EST CELUI QUE LE MANIFESTE ANNONCE.

     Elle etait d'un beige tire de l'ancienne charte, alors que le
     manifeste declare `#ffffff` : sur Android, la barre d'etat prenait
     donc le blanc du manifeste, et une couture grise traversait le haut
     de l'ecran juste en dessous de l'heure. */
  background: rgba(255, 255, 255, .94);
  border-bottom: 1px solid var(--line-soft);
}
@supports (backdrop-filter: blur(8px)) {
  .top { backdrop-filter: blur(12px); }
}

.top__brand { text-align: center; min-width: 0; }

.brand__name {
  display: flex; align-items: baseline; justify-content: center; gap: .15rem;
  font-family: var(--font);
  font-size: 1.5rem; font-weight: 700; line-height: 1.1;
  letter-spacing: -.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Sur un telephone etroit, le nom deborderait et serait coupe a gauche :
   on le reduit plutot que de le tronquer. */
@media (max-width: 26rem) {
  .brand__name { font-size: 1.375rem; }
  .top { grid-template-columns: 2.5rem 1fr auto; padding: 0 .625rem; }
  .iconbtn { width: 2.5rem; height: 2.5rem; }
  .iconbtn--gold { width: 2.625rem; height: 2.625rem; }
}
@media (max-width: 22rem) {
  .brand__name { font-size: 1.1875rem; }
}

/* En bas de casse et en gris. Les petites capitales très espacées sous un
   nom sont la mise en forme par défaut de toute signature d'enseigne ;
   elles annoncent la maquette avant d'annoncer le restaurant. Le nom
   porte, la signature accompagne. */
.brand__tag {
  margin-top: .05rem;
  font-size: var(--t-xs); font-weight: 500;
  color: var(--ink-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.top__right { display: flex; align-items: center; gap: .35rem; }

.iconbtn {
  position: relative;
  width: 2.75rem; height: 2.75rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  color: var(--ink);
}
.iconbtn:hover { background: var(--surface-2); }
.iconbtn svg { width: 1.375rem; height: 1.375rem; }

/* La cloche des nouvelles se tient comme la loupe : un simple bouton
   d'icône. Elle était un disque plein, coloré et ombré — l'élément le
   plus voyant de la page, alors qu'elle n'annonce le plus souvent rien.
   C'est la PASTILLE qui signale une nouvelle, et elle seule : un point
   de couleur sur un bouton calme se remarque bien mieux qu'un point
   blanc sur un bouton déjà criard. */
.iconbtn--gold { color: var(--ink); }
.iconbtn--gold:hover { background: var(--surface-2); }

.dot {
  position: absolute; top: .3rem; right: .3rem;
  min-width: 1.125rem; height: 1.125rem; padding: 0 .28rem;
  display: flex; align-items: center; justify-content: center;
  font-size: .6875rem; font-weight: 700; line-height: 1;
  color: #fff; background: var(--danger);
  border: 2px solid var(--surface); border-radius: var(--r-pill);
}

/* ================================================================= Bandeau */

.notice {
  padding: .6rem 1rem;
  font-size: .8125rem; text-align: center;
  color: var(--gold-deep); background: var(--gold-soft);
  border-bottom: 1px solid var(--gold-line);
}
.notice--warn { color: #8a5a14; background: #fdf3e3; border-bottom-color: #f2e2c4; }

/* ==================================================================== Page */

.wrap { max-width: 64rem; margin: 0 auto; padding: 0 1rem; }

/* Le bouton du panier deborde de la barre du bas d'environ un rem et
   demi : sans cette garde, il se posait sur le dernier plat de la
   carte, et le client ne pouvait plus l'ajouter. */
.view { padding-bottom: calc(var(--bar-h) + 3rem); min-height: 60vh; }

/* =============================================================== Couverture */

.hero {
  position: relative;
  margin-top: .75rem;
  /* NEUF REM, ET NON QUATORZE. Le bandeau ne porte plus le nom du
     restaurant -- il est dans la barre du haut, qui ne bouge jamais --
     mais seulement la photo de la maison et l'etat du service. Ce qui
     interesse le client, ce sont les plats, et ils commencent juste
     en dessous. */
  height: 9.5rem;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #1c1a17;
  box-shadow: var(--shadow-1);
}

/* SANS PHOTO, PAS DE BANDEAU DU TOUT.

   Un aplat de couleur haut de dix rem qui ne porte que << Ouvert >> et
   un delai n'est pas une couverture : c'est un trou en haut de la
   carte, a la place des plats. Ces deux faits tiennent sur une ligne,
   et c'est tout ce qu'ils meritent. Des qu'une photo est posee dans les
   reglages, le vrai bandeau reprend sa place.

   Les blocs `.hero--nue` plus bas restent : une version ancienne de
   l'application, gardee en cache par un telephone, s'en sert encore. */
.service {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .3rem .875rem;
  margin-top: .75rem; padding: .625rem .875rem;
  font-size: var(--t-xs); color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
}
.service .fact--open { color: var(--green); font-weight: 600; }
.service .fact--shut { color: var(--danger); font-weight: 600; }
.service__mot {
  flex: 1 1 100%;
  color: var(--ink-faint);
}

/* SANS PHOTO, LE BANDEAU ETAIT UN RECTANGLE NOIR.

   Le fond sombre est fait pour tenir SOUS une photo de plat. Tant que le
   restaurant n'en a pas posé, il ne restait qu'un aplat noir de deux
   cent vingt pixels — le premier tiers de l'écran d'accueil, vide, et la
   première chose que voyait le client en ouvrant la carte.

   Il porte maintenant le bleu de l'enseigne, et il est plus court :
   rien à regarder ne mérite pas la moitié d'un écran. Dès qu'une photo
   est posée dans les réglages, c'est elle qui reprend la place. */
.hero--nue {
  height: 10.5rem;
  background:
    radial-gradient(120% 140% at 82% 12%, rgba(255, 255, 255, .22) 0%,
                    rgba(255, 255, 255, 0) 55%),
    radial-gradient(90% 120% at 8% 96%, rgba(255, 255, 255, .12) 0%,
                    rgba(255, 255, 255, 0) 60%),
    linear-gradient(142deg, var(--accent) 0%, var(--accent-dark) 62%, #0d3a89 100%);
}
/* Le voile sert à faire tenir le texte sur une photo. Sur l'aplat bleu
   il n'a rien à assombrir, et il ternirait la couleur de l'enseigne. */
.hero--nue .hero__veil {
  background: linear-gradient(to top,
    rgba(6, 26, 64, .42) 0%, rgba(6, 26, 64, .10) 46%, rgba(6, 26, 64, 0) 78%);
}
.hero__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
}
.hero__veil {
  position: absolute; inset: 0;
  /* Assez sombre au bas pour que le texte tienne, transparent en haut
     pour que le plat se voie. Le voile part du bas et non du côté : le
     texte est posé en pied d'image, comme une légende, plutôt qu'en
     travers de la photo. */
  background: linear-gradient(to top,
    rgba(20, 16, 12, .88) 0%, rgba(20, 16, 12, .62) 38%,
    rgba(20, 16, 12, .18) 70%, rgba(20, 16, 12, 0) 100%);
}
.hero__body {
  position: absolute; right: 0; bottom: 0; left: 0;
  display: flex; flex-direction: column;
  padding: 1rem;
  color: #fff;
}
.hero__title {
  font-size: 1.5rem; line-height: 1.15; font-weight: 700;
  letter-spacing: -.015em;
}
.hero__text {
  margin: .3rem 0 0;
  font-size: .8125rem; line-height: 1.45;
  color: rgba(255, 255, 255, .84);
}

/* Les faits : état du service, délai, repère. Des mentions sobres, sans
   pastille de couleur — le vert et le rouge sont réservés, dans tout le
   logiciel, à ce qui est encaissé et à ce qui est refusé. */
.hero__facts {
  display: flex; flex-wrap: wrap; gap: .25rem .875rem;
  margin-top: .55rem;
  font-size: var(--t-xs);
  color: rgba(255, 255, 255, .88);
}
.fact { display: inline-flex; align-items: center; gap: .3rem; }
.fact--open::before,
.fact--shut::before {
  content: ''; width: .4rem; height: .4rem; border-radius: 50%;
  background: #7fd1a0;
}
.fact--shut::before { background: #e8998f; }

/* ====================================================== Rail de catégories */

/* LES CATEGORIES ET LA RECHERCHE RESTENT SOUS LA MAIN.

   Elles partaient avec le defilement : sur une carte de cinquante
   plats, changer de categorie demandait de remonter tout en haut, puis
   de redescendre. Elles se collent maintenant sous la barre du titre,
   avec un fond opaque -- sans lui, les plats defileraient AU TRAVERS
   des boutons.

   `-1rem` de marge puis `1rem` de garde : la barre touche les deux
   bords de l'ecran, mais son contenu reste aligne sur le reste de la
   page. */
.barre {
  position: sticky; top: var(--top-h); z-index: 30;
  margin: 0 -1rem; padding: .5rem 1rem .125rem;
  background: var(--paper);
  border-bottom: 1px solid var(--line-soft);
}
.barre .search { margin-top: .5rem; margin-bottom: .5rem; }

.rail {
  display: flex; gap: .4375rem;
  margin: 0 -1rem; padding: .125rem 1rem .25rem;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }

/* La rangee des categories se coupe net au bord droit : rien ne disait
   qu'elle continue. Un degrade sur la derniere poignee de pixels le dit
   sans ajouter de fleche ni de texte. */
.rail__wrap { position: relative; }
.rail__wrap::after {
  content: ''; position: absolute; top: 0; right: 0; bottom: .25rem;
  width: 1.5rem; pointer-events: none;
  background: linear-gradient(to right, rgba(238, 242, 247, 0), var(--paper));
}

/* DES PASTILLES, ET NON DES CARTES.

   Chaque categorie etait un carre de quatre-vingt-douze pixels sur
   quatre-vingts, avec son icone : la rangee mangeait a elle seule le
   quart de l'ecran d'accueil, pour un simple filtre. Une pastille de
   texte fait le meme travail sur un tiers de la hauteur, et laisse la
   place aux plats. */
.cat {
  flex: none;
  min-height: 2.375rem;
  display: inline-flex; align-items: center; gap: .375rem;
  padding: .4375rem .8125rem;
  white-space: nowrap;
  font-size: .8125rem; font-weight: 500;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  transition: background-color .14s, border-color .14s, color .14s;
}
.cat svg { width: 1rem; height: 1rem; flex: none; color: var(--ink-soft); }
/* LE NOM EN ENTIER, SUR UNE SEULE LIGNE.

   << Accompagnements >> s'affichait << Accompagnem ents >>, coupe au
   milieu d'un mot, sur la rangee meme qui sert a choisir. Une pastille
   s'etire a la largeur de son texte : il n'y a plus rien a couper. */
.cat span { color: var(--ink); }
.cat:hover { border-color: var(--gold-line); }
.cat.is-active {
  background: var(--accent); border-color: var(--accent);
  box-shadow: var(--shadow-1);
}
.cat.is-active svg, .cat.is-active span { color: #fff; }

/* ------------------------------------------------- La carte du suivi

   Elle apparait sous l'etat de la commande, dans le panneau que le
   client garde ouvert en attendant. Une hauteur fixe : sans elle, la
   carte naissait a zero pixel et ne dessinait jamais ses tuiles. */
.suivi-carte { margin-top: 1rem; }
.suivi-carte .kmap {
  height: 15rem; width: 100%;
  border-radius: var(--r); overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.suivi-carte__mot {
  margin: .5rem 0 0;
  font-size: .8125rem; line-height: 1.45;
  color: var(--ink-soft); text-align: center;
}

/* ================================================================ Recherche */

.search { position: relative; margin-top: 1rem; }
.search svg {
  position: absolute; left: .875rem; top: 50%; transform: translateY(-50%);
  width: 1.0625rem; height: 1.0625rem; color: var(--ink-faint); pointer-events: none;
}
.search input {
  width: 100%;
  padding: .75rem 1rem .75rem 2.5rem;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
}
.search input::placeholder { color: var(--ink-faint); }
.search input:focus {
  outline: none; border-color: var(--gold-line); box-shadow: var(--shadow-1);
}

/* ========================================================== Titre de rayon */

.shead {
  display: flex; align-items: baseline; gap: .5rem;
  margin: 1.5rem 0 .625rem;
}
.shead__title {
  font-size: 1.0625rem; font-weight: 700; letter-spacing: -.01em;
  text-transform: uppercase;
  flex: none;
}
/* Le nombre de plats, en petit, a cote du titre. Il dit au client ce
   qui l'attend avant qu'il ne fasse defiler -- et il remplace le lien
   << Voir tout >>, qui menait a la meme liste. */
.shead__count {
  font-size: var(--t-xs); font-weight: 600;
  color: var(--ink-faint);
}
.shead__rule { flex: 1; }

/* ==================================================================== Plats

   UNE CARTE DE RESTAURANT SE LIT, ELLE NE SE FEUILLETTE PAS.

   Les plats etaient des vignettes rangees par deux, ou dans des rangees
   qui defilaient de cote. Onze plats faisaient six ecrans ; la photo
   prenait les trois quarts de chaque vignette ; ce qu'il y a DANS le
   plat n'etait jamais montre ; et une categorie qui ne comptait qu'un
   plat laissait la moitie de la rangee vide.

   Photo a gauche, nom, description, prix. Trois plats par ecran, et
   tous lisibles.
   ========================================================================== */

.plats {
  display: grid; gap: .5rem;
}

.plat {
  position: relative;
  display: grid;
  /* La troisieme colonne s'adapte : un simple << + >> quand le plat
     n'est pas au panier, un compteur encadre de ses deux boutons une
     fois qu'il y est. */
  grid-template-columns: 4.75rem 1fr auto;
  gap: .875rem;
  align-items: center;
  padding: .625rem;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  transition: box-shadow .15s, border-color .15s;
}
.plat:hover { box-shadow: var(--shadow-1); border-color: var(--gold-line); }
.plat:active { background: var(--surface-2); }
.plat--off { opacity: .6; }
.plat--off:hover { box-shadow: none; border-color: var(--line); }

.plat__media {
  position: relative;
  width: 4.75rem; height: 4.75rem;
  display: flex; align-items: center; justify-content: center;
  background: var(--tint, var(--surface-2));
  border-radius: var(--r-sm);
  overflow: hidden;
}
.plat__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.plat__media svg { width: 66%; height: 66%; }
.plat__media .dish__initials { font-size: 1.125rem; }

.plat__flag {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: .125rem;
  font-size: .625rem; font-weight: 700; text-align: center;
  letter-spacing: .03em; text-transform: uppercase;
  color: #fff; background: rgba(150, 26, 20, .94);
}

.plat__body { min-width: 0; }
.plat__name {
  font-size: .9375rem; font-weight: 600; line-height: 1.3;
}
/* CE QU'IL Y A DANS LE PLAT. La description existait dans la caisse et
   n'etait montree nulle part : le client lisait << Couscous poulet >>
   sans savoir ce qu'il y avait autour. */
.plat__desc {
  margin-top: .125rem;
  font-size: .8125rem; line-height: 1.35; color: var(--ink-soft);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.plat__price {
  margin-top: .3125rem;
  font-size: .9375rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.plat__act {
  display: flex; align-items: center; justify-content: flex-end;
}
.plat__off {
  font-size: var(--t-xs); color: var(--ink-faint); text-align: right;
}

.plat__add {
  flex: none;
  /* 44 px : c'est le geste central de la commande, il ne doit jamais se
     manquer, surtout d'une main en marchant. */
  width: 2.75rem; height: 2.75rem;
  display: flex; align-items: center; justify-content: center;
  color: #fff; background: var(--gold);
  border-radius: var(--r-pill);
  transition: background-color .14s;
}
.plat__add:hover { background: var(--gold-deep); }
.plat__add svg { width: 1.125rem; height: 1.125rem; }

/* DEJA AU PANIER : le compteur, encadre de ses deux boutons.

   Un nombre mort tenait cette place, et un second appui ne faisait
   rien : le client qui en voulait trois devait ouvrir le panier pour
   les ajouter un a un. A la caisse, on appuie trois fois. Ici aussi. */
.stepper--plat {
  flex: none;
  display: flex; align-items: center; gap: .125rem;
}
.stepper--plat button {
  width: 2.25rem; height: 2.25rem;
  display: flex; align-items: center; justify-content: center;
  color: var(--gold-deep); background: var(--gold-soft);
  border: 0; border-radius: var(--r-pill);
}
.stepper--plat button:hover { background: var(--accent); color: #fff; }
.stepper--plat button svg { width: .9375rem; height: .9375rem; }
.stepper--plat .stepper__value {
  min-width: 1.5rem; text-align: center;
  font-size: .9375rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------ La fiche du plat */

.fiche__media {
  height: 12rem; margin: -.25rem 0 1rem;
  display: flex; align-items: center; justify-content: center;
  position: relative;
  background: var(--tint, var(--surface-2));
  border-radius: var(--r); overflow: hidden;
}
.fiche__media img { width: 100%; height: 100%; object-fit: cover; }
.fiche__media svg { width: 45%; height: 45%; }
.fiche__desc {
  margin: 0;
  font-size: .9375rem; line-height: 1.5; color: var(--ink-soft);
}
.fiche__price {
  margin-top: .75rem;
  font-size: 1.125rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.fiche__cat {
  margin-top: .25rem;
  font-size: var(--t-xs); color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .04em;
}
.fiche__fav {
  display: inline-flex; align-items: center; gap: .4375rem;
  min-height: var(--touch-min); margin-top: .875rem; padding: 0 .875rem 0 .75rem;
  font-size: .875rem; color: var(--ink-soft);
  background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-pill);
}
.fiche__fav svg { width: 1rem; height: 1rem; }
.fiche__fav.is-on { color: #c0392b; border-color: #e8c5c1; background: #fdf1f0; }
.fiche__fav.is-on svg { fill: #c0392b; }

/* Le pied de la fiche : la quantite a gauche, l'ajout a droite, sur une
   seule ligne. Le bouton porte le total : le client sait ce qu'il
   ajoute avant d'appuyer. */
.fiche__pied { display: flex; align-items: center; gap: .625rem; }
.fiche__pied .btn { flex: 1; }
.stepper--lg { flex: none; }
.stepper--lg button { width: 2.5rem; height: 2.5rem; }
.stepper--lg .stepper__value { min-width: 2rem; font-size: 1rem; }

/* `.dish__initials` sert encore : c'est le repli quand un plat n'a pas
   de photo, pose par `media()`. Le reste des vignettes a disparu avec
   elles. */
.dish__initials { font-weight: 700; color: var(--ink-faint); }

/* SUR GRAND ECRAN, DEUX COLONNES DE LIGNES.

   Une seule colonne sur quatorze cents pixels laisserait les trois
   quarts de la page vides ; des lignes etirees sur toute la largeur
   mettraient le prix a dix centimetres du nom. Deux colonnes de lignes
   remplissent la page sans rien etirer. */
@media (min-width: 52rem) {
  .plats { grid-template-columns: 1fr 1fr; gap: .625rem; }
  .plat { grid-template-columns: 5.25rem 1fr auto; }
  .plat__media { width: 5.25rem; height: 5.25rem; }
  .fiche__media { height: 15rem; }
  /* Une photo etiree sur mille pixels de large et cent cinquante de
     haut n'est plus une photo, c'est une tranche. Le bandeau respire
     a la mesure de l'ecran. */
  .hero { height: 15rem; }
}

/* ============================================================ Barre du bas */

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  height: calc(var(--bar-h) + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  display: flex; align-items: stretch;
  background: rgba(255, 255, 255, .97);
  border-top: 1px solid var(--line);
}
@supports (backdrop-filter: blur(8px)) {
  .tabbar { backdrop-filter: blur(12px); }
}

.tab {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .1875rem;
  color: var(--ink-soft);
}
.tab svg { width: 1.375rem; height: 1.375rem; }
.tab span { font-size: .6875rem; }
.tab.is-active, .tab.is-active svg { color: var(--gold-deep); }

/* Le panier occupe le centre, en relief : c'est l'action qui compte. */
.tab--cart { position: relative; flex: 0 0 5rem; }

.fab {
  position: absolute; top: -1.125rem; left: 50%; transform: translateX(-50%);
  width: 3.625rem; height: 3.625rem;
  display: flex; align-items: center; justify-content: center;
  color: #fff; background: var(--gold);
  border: 4px solid var(--paper);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-gold);
  transition: background-color .14s;
}
.fab:hover { background: var(--gold-deep); }
.fab svg { width: 1.5rem; height: 1.5rem; }
.fab .dot { top: -.125rem; right: -.125rem; border-color: #fff; }

/* SUR ORDINATEUR, LA BARRE NE S'ETIRE PLUS D'UN BORD A L'AUTRE.

   C'etait une barre de telephone tiree sur quatorze cents pixels :
   quatre libelles perdus au milieu d'un ruban blanc, avec un bouton
   rond flottant au centre d'un ecran ou personne n'a le pouce. Elle
   devient une palette posee au bas de la page, a la largeur de son
   contenu -- elle a l'air voulue plutot qu'oubliee. */
@media (min-width: 52rem) {
  .tabbar {
    left: 50%; right: auto; bottom: 1.25rem;
    transform: translateX(-50%);
    width: auto; height: var(--bar-h);
    padding: 0 .5rem;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    box-shadow: var(--shadow-2);
  }
  .tab { flex: 0 0 6rem; }
  .tab--cart { flex: 0 0 5.5rem; }
  .fab { border-color: var(--surface); }
}

/* Installee, l'application descend jusqu'au bord de l'ecran : la
   barre du bas doit alors degager la zone que le systeme se reserve
   sous elle -- le trait de navigation d'Android, la barre d'accueil de
   l'iPhone. Sans cela, le dernier plat se retrouve dessous. */
@media (display-mode: standalone), (display-mode: fullscreen) {
  .view {
    padding-bottom: calc(var(--bar-h) + 3rem + env(safe-area-inset-bottom, 0px));
  }
}

/* ================================================================ Panneaux */

.sheet-bg {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(10, 22, 42, .45);
  animation: fade .16s ease-out;
}
@keyframes fade { from { opacity: 0; } }

.sheet {
  width: 100%; max-width: 32rem;
  max-height: 92vh;
  display: flex; flex-direction: column;
  background: var(--paper);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: var(--shadow-3);
  animation: rise .2s cubic-bezier(.22, .8, .3, 1);
}
@keyframes rise { from { transform: translateY(1.5rem); } }

.sheet__head {
  display: flex; align-items: center; gap: .5rem;
  padding: .875rem 1rem;
  border-bottom: 1px solid var(--line);
}
.sheet__title { font-size: 1.0625rem; font-weight: 700; flex: 1; }

.sheet__body {
  flex: 1; min-height: 0;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 1rem;
}

.sheet__foot {
  padding: .875rem 1rem calc(.875rem + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  border-top: 1px solid var(--line);
}

@media (min-width: 40rem) {
  .sheet-bg { align-items: center; padding: 1.5rem; }
  .sheet { border-radius: var(--r-lg); max-height: 86vh; }
  /* Sur grand ecran, la barre reste au centre : etiree sur 1400 px elle
     laisserait des vides ridicules entre les onglets. */
  .tabbar { justify-content: center; }
  .tab { flex: 0 0 7.5rem; }
  .tab--cart { flex: 0 0 7.5rem; }
}

/* ---------------------------------------------------------- Tiroir latéral */

.drawer-bg {
  position: fixed; inset: 0; z-index: 70;
  background: rgba(10, 22, 42, .45);
  animation: fade .16s ease-out;
}
.drawer {
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 17.5rem; max-width: 84vw;
  display: flex; flex-direction: column;
  background: var(--paper);
  box-shadow: var(--shadow-3);
  animation: slide .2s cubic-bezier(.22, .8, .3, 1);
}
@keyframes slide { from { transform: translateX(-1.5rem); opacity: .6; } }

.drawer__head { padding: 1.25rem 1.25rem 1rem; border-bottom: 1px solid var(--line); }
.drawer__body { flex: 1; overflow-y: auto; padding: .75rem; }
.drawer__foot {
  padding: .75rem 1.25rem calc(1rem + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line);
  font-size: .75rem; color: var(--ink-faint);
}

.dlink {
  display: flex; align-items: center; gap: .75rem;
  width: 100%; padding: .75rem .625rem;
  border-radius: var(--r);
  text-align: left;
}
.dlink:hover { background: var(--surface-2); }
.dlink svg { width: 1.125rem; height: 1.125rem; color: var(--gold-deep); flex: none; }
.dlink > span { flex: 1; min-width: 0; font-size: .9375rem; }
.dlink small { display: block; color: var(--ink-faint); font-size: .75rem; }

/* ============================================================ Lignes panier */

.line {
  display: flex; gap: .75rem; align-items: center;
  padding: .6875rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.line:last-child { border-bottom: 0; }

.line__media {
  flex: none; width: 3.25rem; height: 3.25rem;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; border-radius: var(--r);
  background: var(--tint, var(--surface-2));
}
.line__media img { width: 100%; height: 100%; object-fit: cover; }
.line__media svg { width: 75%; height: 75%; }

.line__body { flex: 1; min-width: 0; }
.line__name { font-weight: 600; font-size: .9375rem; }
.line__price { font-size: .8125rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }

.stepper {
  flex: none;
  display: flex; align-items: center; gap: .125rem;
  padding: .1875rem;
  background: var(--surface-2); border-radius: var(--r-pill);
}
.stepper button {
  width: 1.875rem; height: 1.875rem;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-pill);
}
.stepper button:hover { border-color: var(--gold-line); color: var(--gold-deep); }
.stepper button svg { width: .8125rem; height: .8125rem; }
.stepper__value {
  min-width: 1.75rem; text-align: center;
  font-size: .875rem; font-weight: 700; font-variant-numeric: tabular-nums;
}

/* ================================================================== Totaux */

.totals { padding-top: .5rem; }
.totals__row {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: .1875rem 0;
  font-size: .875rem; color: var(--ink-soft);
}
.totals__row span:last-child { font-variant-numeric: tabular-nums; }
.totals__row--save { color: var(--green); font-weight: 600; }
.totals__row--total {
  margin-top: .5rem; padding-top: .625rem;
  border-top: 1px solid var(--line);
  font-size: 1.125rem; font-weight: 700; color: var(--ink);
}

/* ================================================================= Boutons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
  padding: .75rem 1.125rem;
  font-size: .9375rem; font-weight: 600;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
  transition: border-color .14s, background-color .14s;
}
.btn:hover:not(:disabled) { border-color: var(--gold-line); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn svg { width: 1.0625rem; height: 1.0625rem; }

.btn--gold {
  color: #fff; background: var(--gold); border-color: var(--gold);
  box-shadow: var(--shadow-gold);
}
.btn--gold:hover:not(:disabled) { background: var(--gold-deep); border-color: var(--gold-deep); }

.btn--dark { color: #fff; background: #1c1a17; border-color: #1c1a17; }
.btn--dark:hover:not(:disabled) { background: #0a1626; border-color: #0a1626; }

.btn--ghost { background: transparent; border-color: transparent; color: var(--ink-soft); }
.btn--ghost:hover:not(:disabled) { background: var(--surface-2); border-color: transparent; }

.btn--danger { color: var(--danger); border-color: #eecfcc; background: var(--danger-bg); }

.btn--block { width: 100%; }
.btn--lg { padding: .9375rem 1.25rem; font-size: 1rem; }

/* ============================================================ Formulaires */

.field { margin-bottom: .875rem; }
.field label {
  display: block; margin-bottom: .3125rem;
  font-size: .8125rem; font-weight: 600; color: var(--ink-soft);
}
.field input, .field textarea, .field select {
  width: 100%;
  padding: .75rem .875rem;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--gold-line); box-shadow: var(--shadow-1);
}
.field__hint { margin-top: .3125rem; font-size: .75rem; color: var(--ink-faint); }
.field--half { display: inline-block; width: calc(50% - .28rem); }
.field--half + .field--half { margin-left: .5rem; }

.pinbox input {
  font-size: 1.5rem; font-weight: 700; letter-spacing: .6em;
  text-align: center; text-indent: .6em;
  padding: .75rem .5rem;
}

/* ========================================================== Mode de commande */

.modes {
  display: grid; gap: .5rem; margin-bottom: 1rem;
  /* Trois modes doivent tenir sur une seule ligne, meme sur un telephone
     etroit : un mode relegue seul sur une demi-ligne se lit mal. */
  grid-template-columns: repeat(auto-fit, minmax(6.25rem, 1fr));
}

.mode {
  display: flex; flex-direction: column; align-items: flex-start; gap: .125rem;
  padding: .6875rem .625rem;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
}
.mode:hover { border-color: var(--gold-line); }
.mode.is-active {
  border-color: var(--gold); background: var(--gold-soft);
  box-shadow: inset 0 0 0 1px var(--gold);
}
.mode svg { width: 1.25rem; height: 1.25rem; margin-bottom: .1875rem; color: var(--gold-deep); }
.mode strong { font-size: .875rem; font-weight: 600; line-height: 1.25; }
.mode small { font-size: .6875rem; color: var(--ink-soft); line-height: 1.25; }
.mode:disabled { opacity: .45; cursor: not-allowed; }

/* =============================================================== Duree */

.eta {
  display: flex; align-items: flex-start; gap: .5rem;
  margin-top: .75rem; padding: .625rem .75rem;
  font-size: .875rem;
  color: var(--gold-deep); background: var(--gold-soft);
  border-radius: var(--r);
}
.eta svg { width: 1.125rem; height: 1.125rem; flex: none; margin-top: .05rem; }
.eta span { display: flex; flex-direction: column; }
.eta small { font-size: .75rem; color: var(--ink-soft); }
.eta--vague { color: var(--ink-soft); background: var(--surface-2); }

/* ========================================================= Position exacte */

.geo { margin-top: .75rem; }

.geo--ok {
  display: flex; align-items: center; gap: .625rem;
  padding: .625rem .75rem;
  background: var(--green-bg);
  border: 1px solid #cfe3d6; border-radius: var(--r);
}
.geo--ok svg { width: 1.25rem; height: 1.25rem; flex: none; color: var(--green); }
.geo__body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.geo__body strong { font-size: .875rem; color: var(--green); }
.geo__body small { font-size: .75rem; color: var(--ink-soft); }
.geo__undo {
  flex: none; padding: .25rem .5rem;
  font-size: .75rem; color: var(--ink-soft);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--surface);
}
.geo__undo:hover { color: var(--danger); border-color: #eecfcc; }

.geo input {
  width: 100%;
  padding: .7rem .75rem;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
}
.geo input:focus { outline: none; border-color: var(--gold-line); }

/* ================================================================ Fidélité */

.loyal {
  padding: 1.25rem;
  color: #fff;
  background: #1c1a17;
  border-radius: var(--r-lg);
}
.loyal__label {
  font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold);
}
.loyal__points {
  font-size: 2.5rem; line-height: 1.05; font-weight: 800;
  font-variant-numeric: tabular-nums;
  margin-top: .25rem;
}
.loyal__tier {
  display: inline-flex; align-items: center; gap: .3125rem;
  margin-top: .4375rem; padding: .1875rem .625rem;
  font-size: .75rem; font-weight: 600;
  color: #fff; background: var(--gold);
  border-radius: var(--r-pill);
}
.loyal__tier svg { width: .8125rem; height: .8125rem; }
.loyal__bar {
  height: .3125rem; margin-top: .9375rem;
  background: rgba(255, 255, 255, .16); border-radius: var(--r-pill); overflow: hidden;
}
.loyal__bar span { display: block; height: 100%; background: var(--gold); }
.loyal__next { margin-top: .4375rem; font-size: .8125rem; color: rgba(255, 255, 255, .72); }

.reward {
  display: flex; align-items: center; gap: .75rem;
  width: 100%; padding: .75rem; margin-bottom: .5rem;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
}
.reward:hover:not(:disabled) { border-color: var(--gold); }
.reward.is-picked {
  border-color: var(--gold); background: var(--gold-soft);
  box-shadow: inset 0 0 0 1px var(--gold);
}
.reward__body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.reward__name { font-weight: 600; font-size: .9375rem; }
.reward__sub { font-size: .8125rem; color: var(--ink-soft); }
.reward__cost {
  flex: none;
  padding: .1875rem .5625rem;
  font-size: .75rem; font-weight: 700;
  color: var(--gold-deep); background: var(--gold-soft);
  border-radius: var(--r-pill); white-space: nowrap;
}

/* ========================================================= Suivi du livreur */

.card--track { border-color: var(--gold-line); }

.track-live {
  display: flex; align-items: center; gap: .5rem;
  padding: .625rem .75rem;
  font-size: .875rem; font-weight: 600;
  color: var(--green); background: var(--green-bg);
  border-radius: var(--r);
}
.track-live svg { width: 1.125rem; height: 1.125rem; flex: none; }
.track-live--wait { color: var(--ink-soft); background: var(--surface-2); }

.track-links { margin-top: .625rem; }

/* =================================================================== Suivi */

.track { text-align: center; padding: 1.25rem 0 .25rem; }
.track__num { font-size: 1.25rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.track__state { margin-top: .1875rem; font-size: .9375rem; color: var(--ink-soft); }

.steps { display: flex; margin: 1.5rem 0; }
.step { flex: 1; text-align: center; position: relative; }
.step::before {
  content: ''; position: absolute; top: .6875rem; left: -50%; right: 50%;
  height: 2px; background: var(--line);
}
.step:first-child::before { display: none; }
.step.is-done::before { background: var(--gold); }
.step__dot {
  position: relative; z-index: 1;
  width: 1.375rem; height: 1.375rem; margin: 0 auto .375rem;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface);
  border: 2px solid var(--line); border-radius: var(--r-pill);
}
.step__dot svg { width: .6875rem; height: .6875rem; color: #fff; opacity: 0; }
.step.is-done .step__dot { background: var(--gold); border-color: var(--gold); }
.step.is-done .step__dot svg { opacity: 1; }
.step.is-current .step__dot { border-color: var(--ink); box-shadow: 0 0 0 4px var(--surface-2); }
.step__label { font-size: .6875rem; line-height: 1.2; color: var(--ink-soft); }

/* Six etapes sur un telephone. On ne descend plus sous 11 px : le texte
   passe a la ligne, ce qui se lit, la ou 9,5 px ne se lisait pas. */
.steps--long .step__label {
  letter-spacing: -.01em; line-height: 1.15;
  hyphens: auto; -webkit-hyphens: auto;
}
.steps--long .step__dot { width: 1.25rem; height: 1.25rem; }
.steps--long .step::before { top: .625rem; }
.step.is-current .step__label { color: var(--ink); font-weight: 600; }

/* ========================================================== Ouverture */

/* Ce que le client voit avant la carte. Avant, c'etait une page blanche.

   L'animation reste SOBRE : le logo monte de quelques pixels et se pose.
   Rien ne tourne, rien ne rebondit, rien ne pulse -- un restaurant n'est
   pas un jeu, et un client qui attend son plat voit cet ecran plusieurs
   fois par semaine. Une animation qu'on remarque la premiere fois agace
   la dixieme.

   L'ecran ne dure que le temps du chargement, avec un plancher de 450 ms
   pour qu'il ne clignote pas quand la carte est deja en cache. */
.intro {
  position: fixed; inset: 0; z-index: 90;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: .875rem;
  background: var(--paper);
  transition: opacity .32s ease, visibility .32s ease;
}
.intro.is-gone { opacity: 0; visibility: hidden; pointer-events: none; }

.intro__mark {
  width: 5.5rem; height: 5.5rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-lg);
  overflow: hidden;
  animation: intro-pose .5s cubic-bezier(.22, .68, .3, 1) both;
}
.intro__mark img { width: 100%; height: 100%; object-fit: contain; }
/* Sans logo : l'initiale du nom, sur l'accent. Jamais un cadre vide. */
.intro__mark--lettre {
  font-size: 2.25rem; font-weight: 700;
  color: var(--accent-ink); background: var(--gold);
}

.intro__name {
  font-family: var(--font);
  font-size: 1.375rem; font-weight: 700; letter-spacing: -.01em;
  color: var(--ink);
  animation: intro-pose .5s cubic-bezier(.22, .68, .3, 1) .08s both;
}

/* Une barre qui avance, pas un rond qui tourne : elle dit qu'il se passe
   quelque chose sans promettre une duree qu'on ne connait pas. */
.intro__bar {
  width: 7.5rem; height: 3px;
  background: var(--line); border-radius: 2px; overflow: hidden;
  animation: intro-pose .5s cubic-bezier(.22, .68, .3, 1) .16s both;
}
.intro__bar i {
  display: block; width: 40%; height: 100%;
  background: var(--gold); border-radius: 2px;
  animation: intro-glisse 1.1s ease-in-out infinite;
}

@keyframes intro-pose {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes intro-glisse {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}

/* Certains clients ont demande a leur telephone de ne pas animer. On ne
   discute pas : le logo s'affiche, pose. */
@media (prefers-reduced-motion: reduce) {
  .intro__mark, .intro__name, .intro__bar { animation: none; }
  .intro__bar i { animation: none; width: 100%; opacity: .5; }
}

/* ============================================== Squelette de chargement */

/* A la toute premiere visite il n'y a rien en cache. Plutot qu'un vide,
   la forme de ce qui arrive : le client comprend qu'il attend une liste
   de plats, et l'affichage ne sursaute pas quand elle se pose.

   Les blocs reprennent exactement les mesures des vraies vignettes --
   sinon le contenu bougerait a l'arrivee, ce qui est pire que le vide. */
/* Le meme retrait que .wrap : le squelette occupe exactement la place
   que prendra la carte. */
.skel { max-width: 64rem; margin: 0 auto; padding: 0 1rem; }
.skel__title {
  height: 1.125rem; width: 8rem; margin: 1.25rem 0 .75rem;
  border-radius: var(--r-sm);
}
.skel__row { display: flex; gap: .75rem; overflow: hidden; }
.skel__card {
  flex: 0 0 9.5rem;
  border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; background: var(--surface);
}
.skel__media { height: 6.5rem; }
.skel__line { height: .75rem; margin: .625rem .625rem 0; border-radius: var(--r-sm); }
.skel__line--court { width: 55%; margin-bottom: .875rem; }

.skel__title, .skel__media, .skel__line {
  background: linear-gradient(90deg,
    var(--surface-2) 25%, var(--line-soft) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: skel-onde 1.4s ease-in-out infinite;
}
@keyframes skel-onde {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .skel__title, .skel__media, .skel__line {
    animation: none; background: var(--surface-2);
  }
}

/* ================================================================== Cartes */

.card {
  padding: 1rem;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
  margin-bottom: .75rem;
}
.card__title {
  font-size: .6875rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--gold-deep);
  margin-bottom: .625rem;
}

.rowlist { display: flex; justify-content: space-between; gap: 1rem; padding: .25rem 0; }
.rowlist span:last-child { color: var(--ink-soft); text-align: right; }

.order-card {
  display: flex; align-items: center; gap: .75rem;
  width: 100%; padding: .875rem; margin-bottom: .625rem;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
}
.order-card:hover { border-color: var(--gold-line); }
.order-card__body { flex: 1; min-width: 0; }
.order-card__num { font-weight: 600; font-size: .9375rem; }
.order-card__meta { font-size: .8125rem; color: var(--ink-soft); }
.order-card__total { font-weight: 700; font-variant-numeric: tabular-nums; }

.badge {
  display: inline-block; padding: .125rem .5rem;
  font-size: .6875rem; font-weight: 600;
  border-radius: var(--r-pill);
}
.badge--wait { color: #8a5a14; background: #fdf3e3; }
.badge--live { color: var(--gold-deep); background: var(--gold-soft); }
.badge--done { color: var(--green); background: var(--green-bg); }
.badge--off { color: var(--ink-soft); background: var(--surface-2); }

/* ==================================================================== Vide */

.empty { padding: 3rem 1rem; text-align: center; color: var(--ink-soft); }
.empty svg { width: 2.25rem; height: 2.25rem; color: var(--gold); margin-bottom: .625rem; }
.empty h3 {
  font-size: 1.0625rem; font-weight: 700;
  color: var(--ink); margin-bottom: .25rem;
}
.empty p { margin: 0 0 1rem; font-size: .875rem; }

/* ================================================================ Messages */

/* LES MESSAGES ARRIVENT PAR LE BAS, pres du pouce et pres de l'action
   qui vient de les provoquer. Ils tombaient du haut, sur la rangee des
   categories : << Votre panier est vide >> masquait les boutons memes
   qui servent a le remplir. */
.toast-zone {
  position: fixed; left: 50%; z-index: 80;
  bottom: calc(var(--bar-h) + 1.25rem + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  width: calc(100% - 2rem); max-width: 23rem;
  display: flex; flex-direction: column-reverse;
  pointer-events: none;
}
.toast {
  margin-bottom: .375rem; padding: .6875rem .875rem;
  font-size: .875rem; color: #fff;
  background: #1c1a17; border-radius: var(--r);
  box-shadow: var(--shadow-2);
  animation: drop .18s ease-out;
}
@keyframes drop { from { opacity: 0; transform: translateY(-.5rem); } }
.toast--bad { background: var(--danger); }
.toast--good { background: var(--green); }

/* ============================================================== Chargement */

.loading { padding: 4rem 1rem; text-align: center; color: var(--ink-faint); }
.spin {
  width: 1.5rem; height: 1.5rem; margin: 0 auto .625rem;
  border: 2px solid var(--line); border-top-color: var(--gold);
  border-radius: var(--r-pill);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .spin, .sheet, .drawer, .toast, .sheet-bg, .drawer-bg { animation: none; }
}

/* ============================================================ Pied de page */

.foot { padding: 2rem 0 1rem; font-size: .75rem; color: var(--ink-faint); text-align: center; }
.foot__rule { width: 2.5rem; height: 1px; margin: 0 auto 1rem; background: var(--gold-line); }

@media print {
  .top, .tabbar, .rail, .toast-zone { display: none !important; }
}


/* La carte de suivi, dans la page du client. */
.track-map {
  height: 14rem;
  margin-top: .625rem;
}


/* Choisir sa table quand le QR code manque : une grille de numéros, comme
   le plan de salle de la caisse en plus simple. */
.tables {
  display: flex; flex-wrap: wrap; gap: .5rem;
  margin: .375rem 0 .625rem;
}
.tables__room {
  margin-top: .5rem;
  font-size: .6875rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-soft);
}
.tablebtn {
  min-width: 3.25rem; min-height: 2.75rem;
  padding: .5rem .75rem;
  font: inherit; font-weight: 600;
  color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  cursor: pointer;
}
.tablebtn.is-active {
  color: #fff; background: var(--gold); border-color: var(--gold);
}


/* ====================================================== Journal des notifications

   Une liste de faits datés, pas un fil d'actualité : chaque ligne dit ce qui
   s'est passé et ramène à la commande concernée. */

.news {
  display: flex; align-items: center; gap: .75rem;
  width: 100%; padding: .75rem .25rem;
  font: inherit; text-align: left; color: var(--ink);
  background: none; border: 0;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}
.news:last-of-type { border-bottom: 0; }
.news > svg { width: 1rem; height: 1rem; flex: none; color: var(--ink-faint); }

.news__ico {
  display: flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem; flex: none;
  color: var(--gold); background: var(--gold-soft);
  border-radius: 50%;
}
.news__ico svg { width: 1.125rem; height: 1.125rem; }
.news__ico--done { color: var(--green); background: var(--green-bg); }
.news__ico--bad { color: var(--danger); background: var(--danger-bg); }

.news__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .0625rem; }
.news__title { font-size: .9375rem; font-weight: 600; }
.news__text { font-size: .8125rem; color: var(--ink-soft); }
.news__when { font-size: .6875rem; color: var(--ink-faint); }

/* Non lue : une pastille discrète, pas un fond coloré qui crierait. */
.news.is-new .news__title { font-weight: 700; }
.news.is-new .news__title::after {
  content: ''; display: inline-block;
  width: .4375rem; height: .4375rem; margin-left: .375rem;
  vertical-align: middle;
  background: var(--gold); border-radius: 50%;
}


/* Le logo du restaurant, sur le site du client. */
.brand__logo {
  flex: none; width: 1.75rem; height: 1.75rem;
  object-fit: contain; border-radius: var(--r-sm);
}
.hero__logo {
  display: block; max-width: 6rem; max-height: 3.25rem;
  object-fit: contain; margin-bottom: .6rem;
  /* Sur une photo sombre, un logo sombre disparait : on le pose sur une
     pastille claire, comme une enseigne eclairee. */
  padding: .3rem .45rem; background: rgba(255, 255, 255, .92);
  border-radius: var(--r-sm);
}
