/* ==========================================================================
   Toque Chef — feuille de style
   Palette pastel d'inspiration italienne : tomate adoucie, basilic, croûte
   dorée, crème. Formes très arrondies, ombres douces, peu de texte.
   ========================================================================== */

/* La marque a enfin un dessin, et non une liste de vœux.
 *
 * Avant, elle était écrite « Iowan Old Style, sinon Palatino, sinon Georgia,
 * sinon un serif quelconque » : joli sur iPhone, loterie partout ailleurs. Un
 * fichier de quarante kilo-octets règle cela pour tout le monde.
 *
 * Servi depuis le site, jamais depuis Google : c'est plus rapide, cela évite
 * un tiers dans le RGPD, et la politique de sécurité de l'application refuse
 * de toute façon ce qui vient d'ailleurs — une fonte en data: comprise.
 *
 * Le fichier ne porte que le latin de base : « Toque Chef » n'a jamais eu
 * besoin d'autre chose, et c'est la seule chose qu'il écrit. Il est variable
 * sur la taille optique seulement, la graisse étant figée à 700 — d'où le
 * font-weight ci-dessous, qu'il faut demander tel quel.
 *
 * Pas de ?v= sur son adresse : son nom dit quelle fonte c'est, et une autre
 * fonte porterait un autre nom.
 */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/bricolage-grotesque.woff2) format("woff2");
}

:root {
  --bg:          #FBF6EE;
  --bg-soft:     #F5ECDF;
  --surface:     #FFFFFF;
  --surface-2:   #FDF9F3;

  --tomato:      #E08A76;
  --tomato-deep: #C2604A;
  --tomato-soft: #FBE4DC;

  --basil:       #8FB89A;
  --basil-deep:  #4E7D62;
  --basil-soft:  #E4F0E7;

  --crust:       #EFC98D;
  --crust-soft:  #FBEDD6;

  --ink:         #3B322B;
  --ink-soft:    #6E635A;
  --ink-faint:   #A79B8F;
  --line:        #EADFD1;
  /* Le trait qui sépare deux sujets. Plus soutenu que --line, parce qu'il se
     pose sur le fond crème et non sur une carte blanche. */
  --trait:       #DCCDB8;

  --shadow:      0 2px 4px rgba(88, 64, 44, .04), 0 8px 24px rgba(88, 64, 44, .07);
  --shadow-lg:   0 4px 8px rgba(88, 64, 44, .05), 0 18px 44px rgba(88, 64, 44, .11);

  /* Le vide autour de la colonne, sur un écran de bureau. Assez sombre pour
     que la colonne s'en détache, assez chaud pour rester de la même famille. */
  --hors-champ:  #D9C7A9;
  /* Le trait qui ferme la colonne sur un grand écran. Plus soutenu que --trait :
     il ne sépare pas deux blocs de la page, il dit où la page s'arrête. */
  --contour:     #B39C7C;

  /* La hauteur de la barre du haut. Elle était écrite en dur à trois endroits,
     dont deux qui la comptaient double : la changer d'un point demandait de se
     souvenir des trois. */
  --barre:       72px;

  --radius:      22px;
  --radius-sm:   14px;
  --radius-lg:   32px;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  /* La marque, et elle seule. Une variable à part de --font-display parce que
     ce ne sont pas les mêmes travaux : les titres et les chiffres se lisent,
     le nom se reconnaît. Le repli est la pile sans empattement, pas la pile
     serif : le temps que la fonte arrive, mieux vaut une lettre de la même
     famille de formes qu'un serif qui sautera au chargement. */
  --font-marque: "Bricolage Grotesque", var(--font);

  /* La couleur d'un rayon. Ce n'est pas de la décoration : on traverse le
     magasin dans cet ordre-là, et retrouver son rayon à la teinte va plus vite
     qu'à la lecture. La crèmerie et la poissonnerie sont deux bleus du même
     bord — ce sont les deux rayons froids —, la crèmerie plus soutenue :
     même famille, deux teintes, on ne les confond plus. */
  --rayon-primeur:      #E1EFE6; --rayon-primeur-i:      #3F6B51;
  --rayon-cremerie:     #CFE0F0; --rayon-cremerie-i:     #29527A;
  --rayon-charcuterie:  #F5DFDC; --rayon-charcuterie-i:  #97372F;
  --rayon-poissonnerie: #E3EDF7; --rayon-poissonnerie-i: #2F5D8A;
  --rayon-epicerie:     #E9E5DE; --rayon-epicerie-i:     #665C53;
  --rayon-divers:       #E9E5DE; --rayon-divers-i:       #665C53;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:          #201B18;
    --bg-soft:     #2A2320;
    --surface:     #2B2421;
    --surface-2:   #332A26;
    --ink:         #F3EAE0;
    --ink-soft:    #C6B8AA;
    --ink-faint:   #8E8175;
    --line:        #3E352F;
    --trait:       #4C423B;
    --tomato-soft: #45302B;
    --basil-soft:  #2D3B32;
    --crust-soft:  #3E3327;
    --hors-champ:  #14100E;
    --contour:     #574B42;
    --shadow:      0 2px 4px rgba(0,0,0,.2), 0 8px 24px rgba(0,0,0,.3);
    --shadow-lg:   0 4px 8px rgba(0,0,0,.25), 0 18px 44px rgba(0,0,0,.4);

    --rayon-primeur:      #22322A; --rayon-primeur-i:      #9CC7AC;
    --rayon-cremerie:     #26364A; --rayon-cremerie-i:     #AFCDE8;
    --rayon-charcuterie:  #38241F; --rayon-charcuterie-i:  #E0A49C;
    --rayon-poissonnerie: #202B38; --rayon-poissonnerie-i: #9EC0DE;
    --rayon-epicerie:     #2C2724; --rayon-epicerie-i:     #BCB0A4;
    --rayon-divers:       #2C2724; --rayon-divers-i:       #BCB0A4;
  }
}

* { box-sizing: border-box; }

/* Caché veut dire caché. Le navigateur attache « display: none » à l'attribut
   hidden, mais la moindre classe qui pose un display — et elles en posent
   toutes — l'emporte sur lui. On a perdu deux fois à ce jeu : un thermomètre
   qui restait visible sur les étapes sans température, un bouton d'effacement
   qui survivait au dernier repère effacé. La règle vaut pour tout le reste. */
[hidden] { display: none !important; }

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

/* Toute l'échelle typographique tient à cette racine : les rem en découlent,
   donc un seul chiffre règle la densité de l'application entière. 15 px plutôt
   que 16 — assez pour gagner une ligne par carte, trop peu pour qu'un écran
   devienne pénible à lire à bout de bras.
   Les champs de saisie, eux, gardent 16 px : en dessous, Safari zoome sur le
   formulaire dès qu'on touche un champ, et il faut ensuite repincer l'écran. */
html { font-size: 15px; }

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

/* --- Sur un écran de bureau ------------------------------------------------
   L'application est faite pour un téléphone et garde sa colonne de 560 points.
   Sur un grand écran, cette colonne flottait au milieu d'un aplat de la même
   couleur qu'elle : on ne voyait plus où l'application commençait. Le fond
   passe donc au sombre autour, et la colonne garde le sien — comme un
   téléphone posé sur une table.

   Un seul point de bascule, à 720 points : en dessous, la colonne occupe
   presque tout et l'encadrer n'aurait aucun sens. */
@media (min-width: 720px) {
  body { background: var(--hors-champ); }
  /* Le contour ferme la colonne, l'ombre la décolle : on doit voir du premier
     coup d'œil ce qui est l'application et ce qui est le bureau autour. */
  .topbar, .shell, .tabbar {
    background: var(--bg);
    box-shadow: 0 0 0 1px var(--contour), var(--shadow-lg);
  }
  .topbar { backdrop-filter: none; }
  /* La barre du bas est en position fixe : sans cette largeur elle s'étalerait
     sous tout l'écran, hors de la colonne qu'elle sert. */
  .tabbar { background: var(--surface); }
  /* La colonne descend jusqu'en bas, même quand la page est courte : un pan de
     fond clair qui s'arrête au milieu du vide ferait plus désordre que rien. */
  .shell { min-height: calc(100vh - var(--barre)); }
}


h1, h2, h3 { font-family: var(--font-display); font-weight: 600; letter-spacing: -.01em; margin: 0; }
h1 { font-size: 1.55rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.05rem; }

a { color: var(--tomato-deep); }

/* --- Ossature ------------------------------------------------------------ */

/* Application pensée pour le téléphone uniquement. Sur un écran large on
   garde la même colonne, simplement centrée : jamais de mise en page de
   bureau, pour que ce qu'on voit au bureau soit ce qu'on aura en main. */
/* Le bas laisse passer la barre des étapes — 63 px — et pas davantage : chaque
   pixel repris ici est un pixel de contenu qui tient sans dérouler. */
/* Le souffle sous la barre du haut : sans lui, le premier bloc de l'accueil
   touchait le trait de séparation et les deux se lisaient comme un seul. */
.shell { max-width: 560px; margin: 0 auto; padding: 18px 16px calc(76px + env(safe-area-inset-bottom)); }

.topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 12px;
  max-width: 560px; margin: 0 auto;
  position: relative;
  min-height: var(--barre);
  /* Quatre points en haut et en bas : le logo occupe la hauteur de la barre au
     lieu de flotter au milieu d'elle. */
  padding: 4px 16px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.topbar__logo { width: 64px; height: 64px; flex: none; display: block; }

/* La marque porte la pastille : dans l'application ouverte, le logo tient le
   rôle de l'icône installée sur l'écran d'accueil. Le liseré autour du rond
   rouge le décolle du dessin, sinon il se confond avec la sauce tomate. */
.topbar__mark { position: relative; flex: none; display: block; }
.topbar__mark .pastille {
  position: absolute; top: -5px; right: -7px;
  box-shadow: 0 0 0 2px var(--surface);
}
/* Le nom de l'application ne se coupe jamais : c'est le seul texte de la barre
   qui doit rester lisible d'un coup d'œil, et il est court. Ce qui vient à sa
   droite se serre ou se tronque avant lui. */
/* Le nom prend toute la place que ses voisins lui laissent, et se centre
   dedans. Centré sur la barre entière il se cognait à la droite dès qu'elle
   était chargée — la liste de courses à 360 points le montrait de six points.
   Centré entre les voisins, il ne peut plus se cogner du tout. */
.topbar__title, .topbar__menu {
  flex: 1 1 0; min-width: 0;
  font-family: var(--font-marque); font-size: 2.1rem; font-weight: 700;
  white-space: nowrap; text-align: center; line-height: 1.1;
  overflow: hidden; text-overflow: ellipsis;
  border: 0; background: none; color: inherit; padding: 0;
}
/* Le titre ne se touche pas ; le menu, si. */
.topbar__title { pointer-events: none; }
.topbar__menu { cursor: pointer; }
/* Sous 390 points — la référence de l'application — les écrans d'une soirée
   chargent assez la barre pour que le nom s'y tronque. Il rapetisse plutôt
   que de se couper : « Toque Ch… » ne dit plus rien.
   Les trois paliers ne montent pas du même pas, et c'est mesuré et non estimé.
   L'écran le plus serré est la fiche d'une soirée à 320 points, où la flèche
   de retour, le nom et l'étiquette du compte à rebours se partagent la barre :
   le palier du bas n'y gagne presque rien quand celui du haut prend un sixième.
   Relevé sur treize écrans et cinq largeurs — au moins douze points de marge
   partout. Les tailles précédentes, 2,4 / 1,95 / 1,6, coupaient le nom à 390
   comme à 320 : elles avaient été posées sans ce relevé-là. */
@media (max-width: 389px) { .topbar__title, .topbar__menu { font-size: 1.65rem; } }

/* La porte est la barre la plus chargée de l'application : elle porte le logo,
   le nom ET deux boutons, là où les autres écrans n'ont qu'une flèche ou une
   étiquette. Il lui faut donc environ cinq cent vingt points pour tout montrer,
   et « Toque Chef » s'y coupait bien avant les 389 du palier commun.

   Deux renoncements, dans l'ordre où ils coûtent le moins.

   D'abord le logo de la barre. C'est le seul écran où l'on peut s'en passer
   sans rien perdre : la marque est juste en dessous, en grand, au milieu de la
   page. Ailleurs elle ne quitte jamais le coin, parce qu'elle y dit chez qui
   l'on est — ici, elle le dit deux fois.

   Ensuite seulement la taille du nom, et par deux paliers. Un nom coupé ne dit
   plus rien ; un nom un peu plus petit se lit encore. */
@media (max-width: 540px) { .topbar--porte .topbar__mark { display: none; } }
@media (max-width: 450px) {
  .topbar--porte .topbar__title { font-size: 1.75rem; }
  /* Sous 450 px, le nom a deja rétréci mais les deux boutons, eux, gardaient
     leur pleine largeur : sur un iPhone 12 « Toque Chef » réclamait 142 px et
     n'en recevait que 133, donc il se coupait. Les boutons rendent le terrain
     en largeur seulement — le rembourrage latéral et l'écart de la barre —,
     jamais en hauteur ni en corps : un libellé illisible ou une cible plus
     petite coûteraient plus cher que ce qu'on gagne. */
  .topbar--porte { gap: 8px; }
  .topbar--porte .btn-barre { padding-left: 12px; padding-right: 12px; }
}
/* 400 et non 380. Les boutons resserrés suffisent à faire tenir le nom au corps
   supérieur sur un iPhone 12 — mais au pixel près, sans un point de marge. Or
   la largeur d'un texte dépend de la police réellement obtenue et du réglage de
   taille du système, deux choses que la feuille de style ne commande pas : une
   mise en page juste à zéro près est une mise en page qui casse chez quelqu'un.
   Sous 400 px le nom prend donc le corps inférieur, avec vingt-quatre points de
   marge. Plus petit se lit ; coupé ne se lit pas. */
@media (max-width: 400px) { .topbar--porte .topbar__title { font-size: 1.5rem; } }
@media (max-width: 339px) { .topbar__title, .topbar__menu { font-size: 1.22rem; } }
/* L'espaceur poussait ce qui suit vers la droite du temps où le nom était
   rigide. Il avale maintenant le vide que le nom réclame pour se centrer, et
   il n'a plus rien à pousser : le nom élastique le fait pour lui. */
.topbar__spacer { margin-left: 0; }
/* Ce que la barre porte à droite — un compte, un total — cède la place avant
   le nom, et s'abrège plutôt que de pousser la porte de sortie hors de l'écran. */
.topbar > :not(.topbar__back):not(.topbar__mark):not(.topbar__title):not(.topbar__menu):not(.topbar__spacer):not(.topbar__out):not(.btn-barre) {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* La flèche de retour se pose à gauche du logo, qui ne bouge jamais. Sur les
   écrans étroits le libellé s'efface avant la flèche — c'est la flèche qui
   sert, le mot ne fait que rassurer. */
.topbar__back {
  display: inline-flex; align-items: center; gap: 1px; flex: none;
  margin: -6px 0 -6px -8px; padding: 6px 8px 6px 4px;
  border-radius: 999px;
  color: var(--ink-soft); text-decoration: none;
  font-size: .78rem; font-weight: 700;
}
.topbar__back svg { width: 22px; height: 22px; }
.topbar__back:active { background: var(--bg-soft); }
@media (max-width: 359px) { .topbar__back span { display: none; } }

/* La porte de sortie. Rouge, parce qu'elle ferme quelque chose. */
.topbar__out {
  display: inline-flex; flex: none;
  margin: -6px -6px -6px 0; padding: 6px;
  border-radius: 999px; color: var(--tomato);
}
.topbar__out svg { width: 23px; height: 23px; }
.topbar__out:active { background: var(--tomato-soft); }

.page-head { padding: 14px 0 10px; }
.page-head p { margin: 4px 0 0; color: var(--ink-soft); font-size: .9rem; }

/* Un écran public ouvre plus bas de ton : le titre s'y fait plus petit que
   l'enseigne, parce qu'il s'adresse à quelqu'un qui n'est pas encore entré et
   qu'une enseigne de 1,55 rem au-dessus d'un texte de vente crie.

   Titre et sous-titre tiennent dans le même enfant, et c'est le point : ils ne
   sont pas deux blocs mais une phrase coupée en deux tailles. Séparés, il
   fallait tolérer un écart de quatre points pour la seule paire qui n'en est
   pas une. */
.page-head--sobre { padding: 6px 0 0; }
.page-head--sobre h1 { font-size: 1.35rem; }
.page-head--sobre p { font-size: .85rem; }

/* --- Navigation basse ----------------------------------------------------
   Une seule barre dans toute l'application : les étapes d'un événement, dans
   l'ordre où on les vit. Elle ne se transforme jamais — seule l'étape allumée
   change, et un point vert marque ce qui est derrière soi. */

.tabbar {
  position: fixed; left: 50%; bottom: 0; z-index: 40;
  transform: translateX(-50%);
  width: 100%; max-width: 560px;
  display: flex;
  padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.tabbar a {
  position: relative;
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 0; padding: 6px 1px; border-radius: var(--radius-sm);
  font-size: .67rem; font-weight: 700; letter-spacing: -.01em;
  color: var(--ink-faint); text-decoration: none;
}
.tabbar a svg { width: 21px; height: 21px; }
.tabbar a span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tabbar a[aria-current] { color: var(--tomato-deep); background: var(--tomato-soft); }
.tabbar a.is-past { color: var(--basil-deep); }
.tabbar a.is-past::after {
  content: ''; position: absolute; top: 4px; right: calc(50% - 15px);
  width: 6px; height: 6px; border-radius: 50%; background: var(--basil);
}

/* Titre de la barre du haut : c'est lui qui ouvre le menu. Un seul menu dans
   toute l'application, et il n'a pas besoin d'un bouton à lui. */
.topbar__menu {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 4px; margin: -4px 0 -4px -4px;
  border: 0; border-radius: 999px; background: transparent;
  font: inherit; font-family: var(--font-display); font-size: 1.15rem; font-weight: 600;
  color: inherit; cursor: pointer;
}
.topbar__menu::after { content: '▾'; font-size: .7rem; color: var(--ink-faint); }
.topbar__menu:active { background: var(--bg-soft); }

/* --- Cartes -------------------------------------------------------------- */

.card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px;
  margin-bottom: 10px;
}
.card--flat { box-shadow: none; border: 1px solid var(--line); }
/* Le bandeau de visite : le superviseur regarde chez quelqu'un d'autre, et
   cela doit se voir sans lire. Franc, collant en haut du contenu, avec la
   sortie dedans — chercher le retour ailleurs serait une faute. */
/* --- Les drapeaux de la carte ---------------------------------------------
   Six langues, six drapeaux, et rien d'autre : un nom de langue écrit dans une
   langue qu'on ne lit pas ne sert à personne, alors que le drapeau se reconnaît
   sans savoir lire. Le nom vit quand même dans title et aria-label, pour qui
   n'y voit pas.

   Assez gros pour un pouce — 40 points de côté, la cible minimale d'iOS — et
   posés au calme, centrés, séparés du reste. Ce n'est pas une action qu'on
   cherche, c'est une action qu'on trouve quand on en a besoin. */
.drapeaux {
  display: flex; justify-content: center; flex-wrap: wrap; gap: 4px;
  margin: 22px 0 6px; padding-top: 14px;
  border-top: 1px solid var(--line);
}
.drapeau {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: var(--radius-sm);
  font-size: 1.35rem; line-height: 1; text-decoration: none;
  opacity: .5; transition: opacity .12s ease, background .12s ease;
}
.drapeau:hover, .drapeau:focus-visible { opacity: 1; background: var(--bg-soft); }
/* Celle qu'on lit se distingue par sa netteté, pas par une bordure : un cadre
   de plus sur un écran qui en porte déjà beaucoup se lirait comme un bouton. */
.drapeau--ici { opacity: 1; background: var(--bg-soft); }

/* --- Le comparatif des formules ------------------------------------------
   Trois colonnes que le chef a demandées. Sur 390 points elles ne tiennent pas
   côte à côte en restant lisibles : elles défilent horizontalement, chacune
   large de 68 % de la colonne, ce qui laisse voir le bord de la suivante — un
   défilement qu'on ne devine pas est un défilement qu'on ne fait pas.

   Le conteneur défile, jamais le corps de la page. */
.colonnes {
  display: flex; gap: 10px; overflow-x: auto; padding: 2px 0 8px;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
}
.colonne {
  flex: 0 0 68%; scroll-snap-align: start;
  display: flex; flex-direction: column;
  padding: 14px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line);
}
.colonne__nom {
  font-family: var(--font-display); font-size: 1.1rem; font-weight: 700;
  color: var(--ink);
}
.colonne__prix {
  margin-top: 4px; font-size: 1.5rem; font-weight: 800; color: var(--tomato-deep);
  font-variant-numeric: tabular-nums;
}
.colonne__prix i {
  display: block; font-style: normal; font-size: .72rem; font-weight: 500;
  color: var(--ink-faint); letter-spacing: .02em;
}
.colonne__an {
  margin-top: 6px; padding: 4px 8px; border-radius: 999px;
  background: var(--vert-soft, var(--bg-soft)); color: var(--ink-soft);
  font-size: .72rem; font-weight: 700; align-self: flex-start;
}
.colonne__accroche {
  margin: 10px 0 0; font-size: .8rem; line-height: 1.4; color: var(--ink-soft);
}
.colonne__liste {
  margin: 12px 0 14px; padding: 0; list-style: none; flex: 1 1 auto;
  font-size: .8rem; line-height: 1.5; color: var(--ink);
}
.colonne__liste li { padding-left: 18px; position: relative; }
.colonne__liste li::before {
  content: '·'; position: absolute; left: 4px; font-weight: 800;
  color: var(--tomato);
}
/* Ce que la formule n'ouvre PAS se lit d'un coup d'œil : c'est la moitié de
   ce qu'on vient comparer. */
.colonne__non { color: var(--ink-faint); text-decoration: line-through; }
.colonne__non::before { content: '·'; color: var(--ink-faint) !important; }

/* Le bouton d'offre, à gauche de la porte du chef. Il se lit comme un mot, pas
   comme un bouton plein : sur la porte d'entrée, ce qui doit sauter aux yeux
   est le champ du code, pas la vente. */
.topbar__pro {
  flex: none; padding: 5px 10px; border-radius: 999px;
  background: var(--bg-soft); color: var(--tomato-deep);
  font-size: .68rem; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; text-decoration: none; white-space: nowrap;
}

/* Les deux portes de l'écran d'entrée, côte à côte et de deux teintes.
   Le plein est pour celui qui ne nous connaît pas — c'est à lui qu'on vend ;
   le vert est pour le chef, qui vient tous les jours et ne cherche pas. */
/* Deux boutons qu'on vise au pouce sur la porte, et non deux étiquettes : ils
   étaient assez petits pour qu'on les manque. */
.btn-barre {
  flex: none; padding: 10px 18px; border-radius: 999px;
  font-size: .88rem; font-weight: 700; text-decoration: none; white-space: nowrap;
  line-height: 1.15;
}
/* « S'abonner » porte le plein, et il vient en dernier : c'est le geste que la
   porte propose, et un bouton se pose à droite quand il conclut. « Connexion »
   le précède en sobre — le chef qui entre tous les jours trouve sa porte les
   yeux fermés, il n'a pas besoin qu'on la lui désigne. Une seule teinte pleine,
   dans tous les cas : deux pastilles côte à côte se disputent l'œil. */
.btn-barre--chef { background: var(--surface-2); color: var(--ink-soft);
                   box-shadow: inset 0 0 0 1px var(--line); }
.btn-barre--pro  { background: var(--tomato-deep); color: #fff; }
.btn-barre:active { filter: brightness(.94); }

/* Le voile de l'hôte quand le service n'est plus payé.

   Il couvre tout, y compris la barre du haut et la barre d'onglets : un voile
   qu'on contourne par le bas n'est pas un voile. Pas de bouton pour le fermer
   — c'est un mur, pas un avertissement. */
.voile {
  position: fixed; inset: 0; z-index: 999;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; background: rgba(28, 22, 17, .88);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.voile__boite {
  width: 100%; max-width: 340px; padding: 22px;
  border-radius: var(--radius); background: var(--surface);
  text-align: center; box-shadow: 0 18px 50px rgba(0, 0, 0, .35);
}
.voile__boite h2 {
  margin: 0 0 10px; font-family: var(--font-display);
  font-size: 1.25rem; font-weight: 700; color: var(--ink);
}
.voile__boite p {
  margin: 0 0 16px; font-size: .9rem; line-height: 1.5; color: var(--ink-soft);
}

.visite { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 14px 0; padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--tomato-soft); color: var(--tomato-deep);
  font-size: .84rem; font-weight: 650; }
.visite span { flex: 1 1 auto; min-width: 0; white-space: normal; }
.visite .btn { flex: none; background: var(--surface); }
/* Une décision, pas une information : elle porte deux boutons et doit tenir
   sur deux lignes plutôt que de rogner la phrase qui l'explique. */
.visite--decision { align-items: flex-start; }
.visite--decision form { flex: none; margin: 0; }
.visite--decision .btn:not(.btn--ghost) { background: var(--tomato); color: #fff; }

/* Un trait quand on change de sujet, et seulement là. Deux cartes qui parlent
   de la même chose se suivent ; deux sujets différents se séparent. Le trait
   respire plus haut que bas, parce qu'un intertitre le suit toujours.

   Sa couleur n'est pas celle des bordures de champs : posé sur le fond crème
   et non sur une carte blanche, un --line disparaît — mesuré, il ne se voyait
   pas sur une capture.

   Deux points d'épaisseur, à la demande du chef : il veut que la structure se
   voie sans qu'on la cherche. */
.regle { border: 0; border-top: 2px solid var(--trait);
  margin: 22px 0 12px; }


/* L'intertitre d'un sujet. Capitales et interlettrage : à cette taille-là,
   c'est ce qui distingue un titre d'un simple gras, et c'est ce qui rend une
   page « structurée et nette » plutôt que seulement remplie.

   À ne pas confondre avec .aisle, qui coiffe un rayon repliable de la liste de
   courses : celui-là s'ouvre et se ferme, il porte un chevron, et son rôle
   n'est pas le même. */
.titre { display: flex; align-items: baseline; gap: 8px;
  margin: 0 0 10px; font-size: .78rem; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink); }
.titre .tag { margin-left: auto; letter-spacing: 0; text-transform: none; }
/* Ce qu'on fait de la liste tient dans le titre qui la nomme : « Voir tous »
   et le « + » y prennent la place du compteur, qui n'apprenait rien — savoir
   qu'on voit 3 soirées sur 14 ne dit pas quoi faire de la quatorzième. */
.titre__g { display: flex; align-items: center; gap: 7px; margin-left: auto; }
.btn-titre {
  display: inline-flex; align-items: center; justify-content: center;
  height: 28px; padding: 0 11px; border-radius: 999px;
  background: var(--bg-soft); color: var(--ink-soft);
  font-size: .72rem; font-weight: 700; letter-spacing: 0; text-transform: none;
  text-decoration: none; white-space: nowrap;
}
/* Le seul orange de l'application : ce qui crée quelque chose. Carré arrondi
   et non pastille, pour qu'il ne se lise pas comme un jumeau du bouton d'à
   côté — l'un mène à une liste, l'autre fabrique une soirée. */
.btn-titre--plus {
  width: 28px; padding: 0; border-radius: 9px;
  background: var(--tomato-deep); color: #fff; font-size: 1rem; line-height: 1;
}
.card__head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.card__head h2, .card__head h3 { margin: 0; }
.card__head .spacer { margin-left: auto; }

.stack > * + * { margin-top: 12px; }

/* Une ligne de recette : le repère, l'ingrédient, la quantité, la corbeille.
   Tout tient sur une ligne — le select héritait d'un width:100% qui, dans une
   ligne flexible, réclamait toute la largeur et rejetait la quantité en
   dessous. Sept ingrédients y gagnaient trois cent soixante pixels.
   Chaque pixel repris aux boutons revient ensuite au nom de l'ingrédient, qui
   est le seul à en manquer. */
#rows > * + * { margin-top: 6px; }
.rrow { display: flex; align-items: center; gap: 5px; }
.rrow select { flex: 1 1 0; width: auto; min-width: 0; padding-right: 6px; }
.rrow__pin { flex: none; width: 30px; padding: 0; }
.rrow input[type=number] { flex: none; width: 56px; text-align: right; padding: 4px 6px; }
.rrow__u { flex: none; width: 14px; font-size: .7rem; color: var(--ink-faint); }
.rrow__x { flex: none; width: 32px; padding: 0; }
.row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.row--between { justify-content: space-between; }
.grow { flex: 1 1 auto; min-width: 0; }
.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); }
.small { font-size: .85rem; }
.tiny  { font-size: .76rem; }
.center { text-align: center; }
.nowrap { white-space: nowrap; }

/* --- Boutons ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 20px; min-height: 44px;
  border: 0; border-radius: 999px;
  font: inherit; font-weight: 600; font-size: .95rem;
  color: #fff; background: var(--tomato-deep);
  cursor: pointer; text-decoration: none;
  transition: transform .12s ease, filter .12s ease;
}
.btn:active { transform: scale(.97); }
.btn:hover { filter: brightness(1.06); }
.btn--ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--line); }
.btn--soft  { background: var(--tomato-soft); color: var(--tomato-deep); }
.btn--green { background: var(--basil-deep); }
/* Ce qui ne se répare pas : la couleur le dit avant qu'on ait lu le libellé. */
.btn--danger { color: var(--tomato-deep); border-color: var(--tomato-soft); }
.btn--sm { padding: 7px 14px; min-height: 36px; font-size: .85rem; }
/* Meme raison que pour .info, et meme methode. Trente-six pixels est une
   decision de dessin — .btn en fait quarante-quatre, la petite variante est
   plus discrete a dessein — mais la cible, elle, n'a pas a etre discrete.
   L'extension est verticale seulement : deux petits boutons cote a cote
   restent frequents, et etendre horizontalement les ferait se recouvrir. */
.btn--sm { position: relative; }
.btn--sm::after {
  content: ''; position: absolute;
  left: 0; right: 0; top: 50%; height: 44px; transform: translateY(-50%);
}
.btn--block { display: flex; width: 100%; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }

/* --- Formulaires --------------------------------------------------------- */

label { display: block; font-size: .78rem; font-weight: 600; color: var(--ink-soft); margin-bottom: 3px; }

input[type=text], input[type=number], input[type=date], input[type=time],
input[type=email], input[type=password], input[type=tel],
input[type=datetime-local], select, textarea {
  width: 100%; padding: 8px 12px; min-height: 40px;
  font-family: inherit; font-size: 16px; line-height: 1.3; color: var(--ink);
  background: var(--surface-2);
  border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  appearance: none;
}
textarea { min-height: 68px; resize: vertical; }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--tomato); background: var(--surface);
  box-shadow: 0 0 0 3px var(--tomato-soft);
}
.field { margin-bottom: 8px; }
/* 140 px, pas 150 : dans une carte d'iPhone SE il reste 311 px utiles, et
   deux colonnes de 150 avec leur gouttière en demandent 314. Dix pixels de
   trop faisaient basculer toute la fiche sur une seule colonne. */
.fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0 14px; }

.switch { display: flex; align-items: center; gap: 12px; padding: 10px 0; cursor: pointer; }
.switch input { position: absolute; opacity: 0; pointer-events: none; }
.switch__track {
  flex: none; width: 48px; height: 28px; border-radius: 999px;
  background: var(--line); position: relative; transition: background .18s ease;
}
.switch__track::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.2);
  transition: transform .18s ease;
}
.switch input:checked + .switch__track { background: var(--basil); }
.switch input:checked + .switch__track::after { transform: translateX(20px); }
.switch__label { font-size: .92rem; font-weight: 600; color: var(--ink); margin: 0; }

/* --- Bulle d'information ------------------------------------------------- */

.info {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: none; margin-left: 6px;
  border-radius: 50%; border: 0;
  background: var(--basil-soft); color: var(--basil-deep);
  font: 600 12px/1 var(--font); cursor: pointer; vertical-align: middle;
}
.info:hover { background: var(--basil); color: #fff; }
/* Vingt pixels a l'oeil, quarante-quatre sous le doigt. Le rond reste petit
   parce qu'il est secondaire — il ne doit pas peser autant que ce qu'il
   explique — mais un doigt ne vise pas vingt pixels, il en rate la moitie.
   La zone s'etend donc par-dessous, sans deplacer quoi que ce soit : un
   pseudo-element absolu ne participe pas a la mise en page.

   Elle est posee en taille absolue et non en debordement negatif, parce qu'un
   enfant absolu se cale sur la boite de REMBOURRAGE de son parent, bordure
   exclue : un inset de -12px sur un bouton borde de 1,5px rendait 42 pixels
   la ou l'on en voulait 44. Quarante-quatre pixels demandes, quarante-quatre
   obtenus, quelle que soit la bordure. */
.info { position: relative; }
.info::after {
  content: ''; position: absolute;
  top: 50%; left: 50%; width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.info-panel {
  margin: 8px 0 4px; padding: 12px 14px;
  background: var(--basil-soft); border-radius: var(--radius-sm);
  font-size: .84rem; line-height: 1.5; color: var(--ink);
}
.info-panel strong { color: var(--basil-deep); }
.info-panel[hidden] { display: none; }

/* --- Étiquettes ---------------------------------------------------------- */

.tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 11px; border-radius: 999px;
  font-size: .74rem; font-weight: 700; letter-spacing: .02em;
  background: var(--bg-soft); color: var(--ink-soft);
}
.tag--tomate { background: var(--tomato-soft); color: var(--tomato-deep); }
.tag--creme  { background: var(--crust-soft);  color: #8A6A32; }
.tag--green  { background: var(--basil-soft);  color: var(--basil-deep); }
.tag--warn   { background: #FBEBD2; color: #8A5A1E; }

/* --- Galerie de pizzas --------------------------------------------------- */

.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 14px; }

.pizza-card {
  position: relative; display: block; width: 100%; padding: 0;
  background: var(--surface); border: 2.5px solid transparent;
  border-radius: var(--radius); box-shadow: var(--shadow);
  overflow: hidden; text-align: left; cursor: pointer;
  font: inherit; color: inherit;
  transition: transform .14s ease, border-color .14s ease;
}
.pizza-card:active { transform: scale(.98); }
.pizza-card[aria-pressed="true"] { border-color: var(--basil); }
.pizza-card__img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: var(--bg-soft); }
.pizza-card__body { padding: 11px 13px 13px; }
.pizza-card__name { font-family: var(--font-display); font-size: 1.02rem; font-weight: 600; }
.pizza-card__meta { margin-top: 3px; font-size: .76rem; color: var(--ink-faint); }
.pizza-card__check {
  position: absolute; top: 10px; right: 10px;
  width: 30px; height: 30px; border-radius: 50%;
  background: rgba(255,255,255,.86); backdrop-filter: blur(6px);
  display: grid; place-items: center;
  color: var(--ink-faint); box-shadow: 0 2px 8px rgba(0,0,0,.14);
}
.pizza-card[aria-pressed="true"] .pizza-card__check { background: var(--basil-deep); color: #fff; }
.pizza-card__votes {
  position: absolute; top: 10px; left: 10px;
  padding: 3px 9px; border-radius: 999px;
  background: rgba(255,255,255,.88); backdrop-filter: blur(6px);
  font-size: .74rem; font-weight: 700; color: var(--ink);
}

/* --- Pizza annotée ------------------------------------------------------- */

.annotated { position: relative; margin: 0 auto; max-width: 520px; }
.annotated__stage { position: relative; }
/* Le conteneur est vide jusqu'a ce qu'annotated.js y pose la photo : la page
   sautait donc au moment ou elle arrive. On lui reserve une boite tant qu'il
   est vide — et seulement tant qu'il l'est. Des que le script a rempli la
   scene, :empty cesse de correspondre et la photo reprend sa hauteur reelle,
   quelle que soit ses proportions. Imposer un rapport a la photo elle-meme
   serait faux : les reperes sont poses en pourcentage de l'image, et la
   recadrer les deplacerait tous. */
.annotated:empty { aspect-ratio: 4 / 3; background: var(--bg-soft); border-radius: var(--radius); }
.annotated img { display: block; width: 100%; border-radius: var(--radius); }
.annotated__svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
/* Le trait, le point et son halo se règlent par pizza : c'est la photo qui
   décide, et annotated.js pose les trois variables sur le conteneur. Les
   valeurs de repli sont celles d'origine — une pizza dessinée sans réglage
   garde l'allure qu'elle avait. */
.annotated__svg line {
  stroke: var(--repere, var(--tomato-deep));
  stroke-width: var(--repere-trait, 1.5px);
  opacity: .75;
}
.annotated__svg circle { fill: var(--repere, var(--tomato-deep)); }
.annotated__labels { position: absolute; inset: 0; pointer-events: none; }
.annotated__label {
  position: absolute; white-space: nowrap;
  padding: 4px 10px; border-radius: 999px;
  background: var(--surface); color: var(--ink);
  font-size: .76rem; font-weight: 600;
  box-shadow: var(--shadow);
  transform: translateY(-50%);
}
.annotated__label small { color: var(--ink-faint); font-weight: 500; }
.annotated__dot {
  position: absolute; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border-radius: 50%; background: var(--repere, var(--tomato-deep));
  /* Le halo vire au sombre quand le trait est clair : un point blanc cerné de
     blanc disparaît, et le blanc se choisit justement sur les photos claires. */
  box-shadow: 0 0 0 2.5px var(--repere-halo, rgba(255,255,255,.85));
}

/* Une étiquette que le chef a traînée est centrée sur son point, et non
   accrochée à un bord de la photo : c'est sous le doigt qu'elle se pose. */
.annotated__label.is-posee { transform: translate(-50%, -50%); }

/* Sur l'écran du chef, la photo se touche : on y pose un repère, et on tire
   ceux qui y sont. Le curseur le dit, et « cursor: pointer » a un second rôle —
   Safari iOS ne délivre un geste à un élément ordinaire que s'il le porte. */
#pin-stage { cursor: crosshair; }
#pin-stage .annotated__labels { pointer-events: none; }
#pin-stage .annotated__dot {
  pointer-events: auto; cursor: grab; touch-action: none;
  /* Neuf pixels ne s'attrapent pas au doigt : la cible en fait trente. */
  padding: 10px; margin: -15px 0 0 -15px; background-clip: content-box;
}
/* Le nom se tire comme le point. Il faut le rendre saisissable un à un : la
   couche qui les porte reste transparente au doigt, sans quoi on ne pourrait
   plus poser de repère au travers. */
#pin-stage .annotated__label {
  pointer-events: auto; cursor: grab; touch-action: none;
}
/* Sauf pendant qu'on pose : le doigt vise alors la photo, et un nom posé
   par-dessus ne doit pas s'interposer. */
#pin-stage.is-posant .annotated__label { pointer-events: none; cursor: crosshair; }
#pin-stage.is-tirant { cursor: grabbing; }
#pin-stage.is-tirant .annotated__dot,
#pin-stage.is-tirant .annotated__label { cursor: grabbing; }
.annotated__label.is-after { background: var(--basil-deep); color: #fff; }
.annotated__label.is-after small { color: rgba(255,255,255,.75); }

/* Une étape qu'on enchaîne quand on peut, dans le fil du jour J. Discrète :
   c'est une nuance de l'heure affichée, pas une alerte. */
.fil__asap {
  display: inline-block; margin-left: 6px; padding: 1px 7px;
  border-radius: 999px; background: var(--bg-soft); color: var(--ink-faint);
  font-size: .66rem; font-weight: 600; white-space: nowrap; vertical-align: middle;
}

/* Le prix d'avant, quand un code promo est appliqué. Barré et effacé : c'est
   le nouveau prix qu'on doit lire, l'ancien n'est là que pour situer. */
.colonne__prix s, .colonne__an s {
  color: var(--ink-faint); font-weight: 500; text-decoration-thickness: 1px;
}

/* --- Le déroulé d'une pâte ------------------------------------------------ */
/* Une étape sur une ligne : son nom, sa durée, un chevron. Elle en occupait
   quatre, et treize étapes faisaient deux mille sept cents points dont on n'en
   voyait que trois en ouvrant l'écran. Ce qu'on garde dehors est ce qu'on
   revient changer — le reste se règle une fois, à l'écriture de la recette. */

.etape { padding: 6px 0; border-bottom: 1px solid var(--line); }
.etape:last-child { border-bottom: 0; padding-bottom: 2px; }
.etape:first-child { padding-top: 2px; }
.etape__h { display: flex; align-items: center; gap: 6px; }
.etape__h input[type=text] { flex: 1 1 auto; min-width: 0; }

/* La durée, seul chiffre resté sur la ligne. 58 points suffisent : une durée
   d'étape va de 5 à 1440 minutes, quatre caractères, là où les pesées en
   demandaient 76 pour un « 100 » qui se coupait. */
/* Le nom : une ligne de texte qui ouvre le tiroir, pas un champ. Il se coupe
   avec des points de suspension au lieu de se trancher net, et le champ qui le
   modifie prend toute la largeur une fois le tiroir ouvert. */
.etape__n {
  flex: 1 1 auto; min-width: 0; padding: 8px 2px; border: 0; background: none;
  font: inherit; font-size: .93rem; color: var(--ink); text-align: left; cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etape__n[data-vide] { color: var(--ink-faint); font-style: italic; }
.etape__nl {
  display: block; margin: 0 0 8px;
  font-size: .72rem; font-weight: 600; color: var(--ink-soft);
}
.etape__nl input { margin-top: 3px; }

/* Deux classes et non une : la règle générale des champs les met à 100 %, et
   `.etape__min` seule perdait contre elle — la ligne partait alors hors écran.
   70 points, et six de rembourrage au lieu de douze : « 1440 » est le maximum
   qu'accepte le champ, et il doit s'y lire en entier. Mesuré sur le champ,
   scrollWidth contre clientWidth, comme pour les pesées — 68 coupait d'un
   point. */
.etape__h .etape__min {
  flex: none; width: 70px; padding-left: 6px; padding-right: 6px;
  text-align: right; font-variant-numeric: tabular-nums;
}
.etape__u { flex: none; font-size: .72rem; color: var(--ink-faint); }
/* Quand la durée n'est pas un chiffre, le mot prend sa place à droite plutôt
   que de laisser un trou : « aussitôt », « la soirée ». */
.etape__u--dit { width: 62px; text-align: right; font-style: italic; }
.etape__more {
  flex: none; width: 26px; height: 26px; padding: 0; border: 0;
  border-radius: 50%; background: var(--bg-soft); color: var(--ink-soft);
  font-size: .8rem; line-height: 1; cursor: pointer;
  transition: transform .18s ease;
}
.etape__more[aria-expanded="true"] { transform: rotate(180deg); }
.etape__x2 { margin: 8px 0 4px 4px; padding-left: 10px; border-left: 2px solid var(--line); }
.etape__x2[hidden] { display: none; }
.etape__rm { width: 100%; margin-top: 8px; }
/* Deux façons de déplacer une étape : la poignée qu'on tire, ou qu'on touche
   pour saisir puis reposer. Les flèches d'un cran sont parties — le glisser
   les rendait redondantes. Le clavier passe par la poignée, qui est un
   bouton : Entrée saisit, Entrée dépose. */
.etape__grip {
  flex: none; width: 26px; height: 32px; padding: 0;
  border: 0; background: none; cursor: grab;
  color: var(--ink-faint); font-size: 1rem; line-height: 1;
  /* Le geste doit rester au script : sans cela le navigateur défile la page
     dès que le doigt bouge, et la ligne ne suit jamais. */
  touch-action: none;
}
.etape__grip[aria-pressed] { color: var(--tomato-deep); }
.etape.is-held { background: var(--tomato-soft); border-radius: var(--radius-sm); }
.etape.is-drag { opacity: .65; }
.etape.is-drag .etape__grip { cursor: grabbing; }
.etape__b { display: flex; align-items: center; gap: 7px; }
.etape__b select { flex: 1 1 auto; min-width: 0; }
.etape__d { margin: 8px 0 0; font-size: .74rem; line-height: 1.35; color: var(--ink-soft); }

/* Ce qu'on pèse à l'étape. Replié, c'est une ligne de résumé qui se lit sans
   rien ouvrir ; déplié, six champs en deux colonnes. Les champs restent dans
   la page même repliés : un formulaire n'envoie que ce qu'il porte, et une
   colonne trouée décalerait toutes les étapes d'un cran. */
.etape__p { margin-top: 7px; }
.etape__pb {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 5px 10px; border: 0; border-radius: var(--radius-sm);
  background: var(--bg-soft); color: var(--ink-soft);
  font: inherit; font-size: .74rem; text-align: left; cursor: pointer;
}
.etape__pb span:first-child {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.etape__pb[aria-expanded="true"] span:last-child { transform: rotate(180deg); }
.etape__pb:disabled { cursor: default; }
.etape__pl {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; margin-top: 8px;
}
.etape__pl label {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-size: .72rem; font-weight: 600; color: var(--ink-soft);
}
.etape__pl label > span:first-child {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
/* 76 et non 58 : « 100 » se coupait, et son dernier zéro passait pour un C.
   Mesuré sur le champ lui-même — scrollWidth contre clientWidth —, et non sur
   un canevas où « system-ui » se résout à une autre fonte : le canevas donnait
   30 points de texte là où le champ en demande 45. 72 suffirait à 320, 360 et
   390 points ; 76 laisse la marge d'une police un peu plus large. */
.etape__pl input { flex: none; width: 76px; text-align: right; }
.etape__pu { flex: none; color: var(--ink-faint); }
@media (max-width: 359px) { .etape__pl { grid-template-columns: 1fr; } }
/* Ce que Vito et les autres recommandent vit derrière le « i » de l'étape,
   comme partout ailleurs dans les recettes (P14). Un conseil n'est pas une
   consigne : un écart n'est pas un défaut (P17). */
.etape .info-panel { margin-top: 6px; }
/* Celles dont la soirée décide : on les montre, on ne les chiffre pas. */
.etape--imposee .etape__b select[name="etape_mode[]"] { color: var(--ink-faint); }
/* Le « × » a quitté la ligne du nom pour le tiroir : à côté du chevron, il se
   touchait par erreur, et une étape retirée d'un doigt ne se retrouve pas. */

/* --- Le trait des repères ------------------------------------------------ */
/* Cinq couleurs et trois épaisseurs, sur une ligne sous la photo. Des
   pastilles : une couleur se choisit à l'œil, et le mot « Bleu » écrit en noir
   n'apprend rien. Tout tient en 260 points, donc sur le plus étroit des
   téléphones. */

.repere__t { display: block; font-size: .78rem; font-weight: 600; color: var(--ink-soft); }
.repere { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 5px; }
.repere__lot { display: flex; align-items: center; gap: 8px; }
.repere__c, .repere__e { position: relative; display: block; margin: 0; cursor: pointer; }
.repere__c input, .repere__e input {
  position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0;
  cursor: pointer;
}
.repere__c span {
  display: block; width: 28px; height: 28px; border-radius: 50%;
  background: var(--c); box-shadow: inset 0 0 0 1px rgba(59,50,43,.22);
}
.repere__c input:checked + span {
  box-shadow: inset 0 0 0 1px rgba(59,50,43,.22), 0 0 0 2px var(--bg), 0 0 0 4px var(--ink);
}
.repere__e span {
  display: grid; place-items: center; width: 36px; height: 28px;
  border-radius: 9px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line);
}
.repere__e span::before {
  content: ''; display: block; width: 18px; height: var(--e);
  border-radius: 2px; background: var(--ink-soft);
}
.repere__e input:checked + span { box-shadow: inset 0 0 0 2px var(--ink); }
.repere__c input:focus-visible + span, .repere__e input:focus-visible + span {
  outline: 2px solid var(--tomato-deep); outline-offset: 3px;
}

/* --- Panneau glissant ---------------------------------------------------- */

.sheet { position: fixed; inset: 0; z-index: 60; display: none; }
.sheet.is-open { display: block; }
.sheet__backdrop { position: absolute; inset: 0; background: rgba(45, 30, 22, .5); }
.sheet__panel {
  position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  width: 100%; max-width: 560px; max-height: 92vh; overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--bg);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 8px 16px calc(18px + env(safe-area-inset-bottom));
  box-shadow: var(--shadow-lg);
  animation: sheet-up .22s ease both;
}
@keyframes sheet-up { from { transform: translate(-50%, 12%); opacity: .5 } to { transform: translate(-50%, 0); opacity: 1 } }
.sheet__grip { width: 42px; height: 4px; border-radius: 999px; background: var(--line); margin: 6px auto 14px; }
/* La croix, en haut à droite de chaque tiroir. Le clic à côté ferme toujours ;
   celle-ci est pour la main qui ne peut pas viser le bord de l'écran. */
.sheet__x {
  position: absolute; top: 10px; right: 12px; z-index: 2;
  width: 34px; height: 34px; padding: 0; border: 0; border-radius: 999px;
  background: var(--bg-soft); color: var(--ink-soft);
  display: grid; place-items: center; cursor: pointer;
}
.sheet__x svg { width: 16px; height: 16px; }
.sheet__x:active { background: var(--line); }
/* Enregistrer et Supprimer sur la même ligne : ce sont les deux issues, elles
   se lisent ensemble. Le poids visuel les sépare mieux qu'un empilement. */
.sheet__actions--duo { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; align-items: stretch; }
.sheet__actions--duo form { display: contents; }

/* Le nom dans les six langues : un drapeau, un champ, six fois. */
.noms6 { display: grid; gap: 6px; }
.noms6 > div { display: flex; align-items: center; gap: 8px; }
.noms6 > div > span { flex: none; width: 26px; text-align: center; font-size: 1.1rem; line-height: 1; }
.noms6 input { flex: 1 1 auto; min-width: 0; }
.sheet__actions {
  position: sticky; bottom: -18px; margin-top: 16px; padding: 12px 0 4px;
  background: linear-gradient(to top, var(--bg) 72%, transparent);
}

/* --- Liste de montage ---------------------------------------------------- */

.assembly { list-style: none; margin: 0; padding: 0; }
.assembly li {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; margin-bottom: 5px;
  background: var(--surface-2); border-radius: var(--radius-sm);
  border-left: 4px solid var(--crust);
}
.assembly li:last-child { border-left-color: var(--tomato); }
.assembly__after li { border-left-color: var(--basil); background: var(--basil-soft); }
.assembly__qty { margin-left: auto; font-size: .8rem; font-weight: 700; color: var(--ink-soft); }

/* --- Timeline du jour J -------------------------------------------------- */

.timeline { position: relative; padding-left: 30px; }
.timeline::before {
  content: ''; position: absolute; left: 10px; top: 8px; bottom: 8px;
  width: 2px; background: var(--line); border-radius: 2px;
}
.tl-step { position: relative; margin-bottom: 12px; }
.tl-step::before {
  content: ''; position: absolute; left: -25px; top: 18px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--surface); border: 2.5px solid var(--line);
}
.tl-step[data-status="done"]::before    { background: var(--basil); border-color: var(--basil); }
.tl-step[data-status="running"]::before { background: var(--tomato-deep); border-color: var(--tomato-soft);
  box-shadow: 0 0 0 4px var(--tomato-soft); }
.tl-step__card { background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow); padding: 14px 16px; }
.tl-step[data-status="running"] .tl-step__card { box-shadow: var(--shadow-lg); border: 2px solid var(--tomato-soft); }
.tl-step[data-status="done"] .tl-step__card { background: var(--surface-2); box-shadow: none; }
.tl-step__time { font-size: .78rem; font-weight: 700; color: var(--ink-faint); letter-spacing: .02em; }
.tl-step__title { font-family: var(--font-display); font-size: 1.05rem; font-weight: 600; margin: 2px 0 4px; }
.tl-step__detail { font-size: .85rem; color: var(--ink-soft); }

.countdown {
  position: sticky; top: 58px; z-index: 20;
  display: flex; align-items: center; gap: 14px;
  padding: 14px 18px; margin: 0 0 16px;
  background: var(--tomato-deep); color: #fff;
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.countdown__clock { font-family: var(--font-display); font-size: 2rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.countdown__label { font-size: .8rem; opacity: .88; }
.countdown--done { background: var(--basil-deep); }

/* --- Tableaux ------------------------------------------------------------ */

/* --- Inventaire ----------------------------------------------------------
   Trente-six références à relever debout devant un placard. Une ligne par
   référence : ce qu'on touche à droite, ce qu'on lit en dessous. */

.inv__r {
  display: flex; align-items: center; gap: 10px;
  padding: 5px 0; border-bottom: 1px solid var(--line);
}
.inv__r:last-child { border-bottom: 0; }
.inv__k { flex: 1 1 auto; min-width: 0; font-size: .88rem; line-height: 1.3; }
/* Trente-six noms en rouge feraient une liste qui crie. Ils restent à l'encre :
   la ligne entière est de toute façon la cible. */
.inv__k a { font-weight: 600; text-decoration: none; color: var(--ink); }
.inv__m {
  margin-top: 1px; font-size: .69rem; line-height: 1.35;
  color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
/* La vignette d'une référence. Quarante-quatre points : assez pour reconnaître
   un emballage d'un coup d'œil, assez peu pour que trente-six lignes tiennent
   encore dans un écran. Sans photo, l'élément n'existe pas et la ligne ne garde
   aucun trou — un cadre vide se lirait comme un défaut. */
.inv__img {
  flex: none; width: 44px; height: 44px; border-radius: var(--radius-sm);
  object-fit: cover; background: var(--surface-2);
  box-shadow: inset 0 0 0 1px var(--line);
}

/* Le prix cible, à gauche de la quantité et à sa taille : ce sont les deux
   nombres de la ligne, et on les lit ensemble — « je vise 7,50 le kilo, j'en ai
   tant ». Le chiffre tabulaire aligne la colonne d'une ligne à l'autre. */
.inv__p {
  flex: none; min-width: 62px; text-align: right;
  font-size: .95rem; font-weight: 600; color: var(--ink-soft);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.inv__p-u { font-size: .72rem; color: var(--ink-faint); font-weight: 500; }
/* Un composé n'a pas de prix visé : le sien se déduit de sa recette. */
.inv__p-calc { font-size: .69rem; font-weight: 500; color: var(--ink-faint); }

.inv__q { flex: none; display: flex; align-items: center; gap: 5px; }
/* Quatre-vingts points, et pas soixante-six : un relevé se compte en grammes,
   et vingt-cinq kilos de farine s'écrivent 25000. Le champ en coupait le
   dernier chiffre — on tapait juste, on lisait faux, et rien ne le disait. Le
   chiffre tabulaire fige la largeur d'un chiffre : la colonne ne danse plus
   d'une ligne à l'autre pendant qu'on saisit. */
.inv__q input { width: 80px; text-align: right; min-height: 36px; padding: 4px 6px;
                font-variant-numeric: tabular-nums; }
.inv__q span { width: 16px; font-size: .69rem; color: var(--ink-faint); }

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 -4px; }
table { width: 100%; border-collapse: collapse; font-size: .88rem; }
th, td { padding: 6px 8px; text-align: left; border-bottom: 1px solid var(--line); }
th { font-size: .74rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-faint); font-weight: 700; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Un tableau sur un téléphone : il défile dans sa propre boîte plutôt que de
   pousser la page entière de côté. La première colonne prend ce qui reste, les
   trois autres ne se coupent pas. */
.tableau { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tableau table { font-size: .82rem; }
.tableau th, .tableau td { padding: 7px 6px; }
.tableau td:first-child { width: 99%; min-width: 0; }
.tableau td:first-child a {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 650; color: var(--ink); text-decoration: none;
}
.tableau td:not(:first-child), .tableau th:not(:first-child) { white-space: nowrap; }
.tableau .tag { font-size: .66rem; padding: 3px 8px; }
/* Un compte fermé se lit encore, mais il ne réclame plus le regard. */
.tableau tr.est-parti td:first-child a { color: var(--ink-faint); }
tbody tr:last-child td { border-bottom: 0; }
tr.total td { font-weight: 700; border-top: 2px solid var(--line); }

/* --- Chiffres clés ------------------------------------------------------- */

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(126px, 1fr)); gap: 9px; }
.stat {
  padding: 11px 13px; border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow);
}
.stat__value { font-family: var(--font-display); font-size: 1.45rem; font-weight: 700; line-height: 1.05; }
.stat__label { margin-top: 2px; font-size: .74rem; line-height: 1.25; color: var(--ink-faint); font-weight: 600; }
.stat--green .stat__value { color: var(--basil-deep); }
.stat--red   .stat__value { color: var(--tomato-deep); }

/* Barres horizontales, sans dépendance graphique.
   Une seule série, donc une seule teinte : c'est la longueur qui porte
   l'information, pas la couleur. Colorer chaque barre différemment ferait
   croire à des catégories distinctes. Extrémité arrondie côté donnée
   uniquement, base ancrée à zéro. */
.bars { display: grid; gap: 10px; }
.bar { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center; }
.bar__label { font-size: .85rem; font-weight: 600; }
.bar__value { font-size: .85rem; font-variant-numeric: tabular-nums; color: var(--ink-soft); }
.bar__track { grid-column: 1 / -1; height: 10px; border-radius: 3px; background: var(--bg-soft); overflow: hidden; }
.bar__fill  { height: 100%; border-radius: 0 4px 4px 0; background: var(--tomato-deep); min-width: 3px; }

/* --- Messages ------------------------------------------------------------ */

.note {
  padding: 13px 16px; border-radius: var(--radius-sm);
  font-size: .87rem; line-height: 1.5;
  background: var(--basil-soft); color: var(--ink);
  border-left: 4px solid var(--basil);
}
.note--warn { background: #FBEBD2; border-left-color: #E0A54C; }
.note--error { background: var(--tomato-soft); border-left-color: var(--tomato-deep); }
.note + .note { margin-top: 8px; }

/* L'état vide prenait 252 points pour une phrase de deux lignes : quarante-quatre
   de marge en haut, autant en bas, et une icône de cinquante-quatre. C'est le
   bloc le plus gros de l'accueil d'un hôte, et il n'y dit rien qu'on ne sache
   déjà. Il se replie, et l'écran cesse de déborder. */
.empty { padding: 22px 20px; text-align: center; color: var(--ink-faint); }
.empty svg { width: 38px; height: 38px; opacity: .35; margin-bottom: 6px; }
.empty p { margin: 0; }

.toast {
  position: fixed; left: 50%; bottom: 84px; z-index: 90;
  transform: translateX(-50%);
  padding: 12px 20px; border-radius: 999px;
  background: var(--ink); color: var(--bg);
  font-size: .88rem; font-weight: 600;
  box-shadow: var(--shadow-lg);
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.toast.is-visible { opacity: 1; }

/* --- Code d'accès -------------------------------------------------------- */

.code-input {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 1.6rem; font-weight: 700; letter-spacing: .35em;
  text-align: center; text-transform: uppercase;
  padding: 16px 12px;
}
.code-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px; border-radius: 999px;
  background: var(--bg-soft);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 1.02rem; font-weight: 700; letter-spacing: .16em;
}

/* --- Compteur de service ------------------------------------------------- */

.service-item {
  display: flex; align-items: center; gap: 14px;
  padding: 12px; margin-bottom: 10px;
  background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow);
}
.service-item.is-complete { opacity: .5; }
.service-item__img { width: 68px; height: 68px; border-radius: var(--radius-sm); object-fit: cover; flex: none; }
.service-item__count { font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; }
.service-item__btn {
  flex: none; width: 52px; height: 52px; border-radius: 50%;
  border: 0; background: var(--basil-deep); color: #fff;
  font-size: 1.5rem; cursor: pointer;
}
.service-item__btn:disabled { background: var(--line); color: var(--ink-faint); }

/* --- Tuiles de pizza ------------------------------------------------------
   Une règle unique pour les trois rôles : l'image ouvre, le bouton agit.
   Le bouton est un rond posé sur l'image, toujours au même endroit. */

.tiles { display: grid; gap: 9px; }
.tiles--2 { grid-template-columns: repeat(2, 1fr); }
.tiles--3 { grid-template-columns: repeat(3, 1fr); }

.tile {
  position: relative; background: var(--surface);
  border-radius: var(--radius-sm); box-shadow: var(--shadow); overflow: hidden;
}
.tile__im { position: relative; display: block; width: 100%; padding: 0; border: 0;
  background: none; cursor: pointer; }
.tile__im img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  background: var(--bg-soft); }
.tile__cap { display: flex; align-items: center; gap: 6px; padding: 5px 9px 7px; }
.tile__name { flex: 1 1 auto; min-width: 0; font-weight: 600; font-size: .8rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tiles--2 .tile__name { font-family: var(--font-display); font-size: .92rem; }
/* À trois colonnes il reste soixante-sept pixels pour un nom : « Pollo e
   Peperoni » n'y tient pas, et une ellipse ne dit plus de quelle pizza il
   s'agit. Le nom prend donc deux lignes, le compte reste calé sur la première. */
.tiles--3 .tile__cap { align-items: flex-start; }
.tiles--3 .tile__name, .tile__cap--stack .tile__name {
  white-space: normal; line-height: 1.2;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  /* « Reblochonata » ne tient pas sur une ligne de tuile. Coupé par la
     césure il donne « Reblo-chonata » ; laissé au navigateur, « Reblochona-ta ». */
  hyphens: auto;
}
.tile__cap--stack { display: block; }
/* Nom et prix centrés sous la photo : la vignette est un objet symétrique, et
   un texte calé à gauche sous une image centrée penche toujours. */
.tile__cap--centre { text-align: center; }
.tile__cap--centre .tile__name { white-space: normal; }
/* Sur un petit téléphone, une vignette de trois colonnes fait soixante-quinze
   points utiles et « 1,76 € (−2,00) » en demande autant. La remise passe à la
   ligne plutôt que de se faire couper : deux lignes se lisent, une ligne
   tronquée ne dit plus le chiffre. */
.tile__cap--centre .tile__num { white-space: normal; }
/* Ce qu'on déduit si l'invité fournit la garniture, collé au revient dont il
   se retranche. */
.tile__remise { margin-left: 3px; color: var(--basil-deep); font-weight: 700; }
.tile__num {
  display: block; font-size: .72rem; line-height: 1.45; white-space: nowrap;
  color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
/* Le prix de vente est le seul chiffre que l'on cherche du regard, et le seul
   que le client verra jamais. Il tient sa propre ligne sous le revient : à
   trois colonnes, les deux côte à côte ne tenaient pas et c'était lui qu'on
   coupait. */
.tile__sale {
  display: block; color: var(--ink); font-weight: 700; font-size: .95rem;
  line-height: 1.2; font-variant-numeric: tabular-nums;
}
.tile__count { flex: none; font-size: .84rem; font-weight: 700; color: var(--ink-soft);
  font-variant-numeric: tabular-nums; }
.tile.is-done { opacity: .5; }
.tile__bar { position: absolute; left: 0; bottom: 0; height: 3px; background: var(--basil); }
.tile__votes {
  position: absolute; left: 6px; top: 6px; padding: 2px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  backdrop-filter: blur(6px);
  font-size: .7rem; font-weight: 700; color: var(--ink);
}

/* Le bouton posé sur l'image. Assez gros pour un pouce gras de farine. */
.tile__act {
  position: absolute; right: 6px; top: 6px;
  width: 44px; height: 44px; border-radius: 50%; border: 0;
  display: grid; place-items: center; cursor: pointer;
  background: var(--basil-deep); color: #fff; font-size: 1.15rem;
  box-shadow: 0 2px 6px rgba(0,0,0,.22);
}
.tile__act:active { transform: scale(.93); }
.tile__act:disabled { background: var(--line); color: var(--ink-faint); }
.tile__act--sm { width: 32px; height: 32px; right: 5px; top: 5px; font-size: .9rem;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  color: var(--ink-faint); box-shadow: 0 1px 4px rgba(0,0,0,.18); }
.tile__act--on { background: var(--tomato-deep); color: #fff; }

/* --- Choisir un fichier ---------------------------------------------------
   Le champ natif est illisible sur téléphone : on le cache derrière un
   bouton, qui reste un vrai label et garde donc le clavier et le lecteur
   d'écran de son côté. */

.filebtn { position: relative; overflow: hidden; cursor: pointer; }
.filebtn input[type=file] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
}
.filebtn:focus-within { box-shadow: 0 0 0 3px var(--tomato-soft); }

/* --- Liste de pizzas avec pas-à-pas (hôte) --------------------------------
   Le seul écran qui abandonne les grandes images : les bornes, les pizzas et
   les invités ne tiennent pas ensemble autrement. La règle ne change pas —
   la vignette ouvre, le pas-à-pas agit. */

.plist { display: block; }
.pline { display: flex; align-items: center; gap: 10px; padding: 6px 0;
  border-bottom: 1px solid var(--line); }
.pline:last-child { border-bottom: 0; }
.pline__im { width: 44px; height: 44px; flex: none; padding: 0; border: 0;
  border-radius: 12px; overflow: hidden; background: none; cursor: pointer; }
.pline__im img { display: block; width: 100%; height: 100%; object-fit: cover; }
.pline__k { flex: 1 1 auto; min-width: 0; }
.pline__k strong { display: block; font-size: .88rem; font-weight: 650;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pline__k span { display: block; font-size: .72rem; color: var(--ink-faint); }

.stepper { display: flex; align-items: center; flex: none;
  background: var(--bg-soft); border-radius: 999px; height: 38px; }
.stepper button {
  width: 38px; height: 38px; display: grid; place-items: center;
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 1.1rem; font-weight: 700; color: var(--tomato-deep);
}
.stepper button:active { transform: scale(.9); }
.stepper input {
  width: 34px; min-height: 0; padding: 0; text-align: center;
  border: 0; background: none; border-radius: 0;
  font: inherit; font-size: .9rem; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--ink); appearance: textfield; -moz-appearance: textfield;
}
.stepper input::-webkit-outer-spin-button,
.stepper input::-webkit-inner-spin-button { appearance: none; margin: 0; }
.stepper input:focus { outline: none; box-shadow: none; }
.stepper.is-zero input { color: var(--ink-faint); font-weight: 600; }

/* --- Qui a répondu, et combien de ses envies sont retenues ---------------- */

.who { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px 8px; }
.who span { font-size: .75rem; color: var(--ink-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.who b { color: var(--ink); font-variant-numeric: tabular-nums; }
.who .is-none, .who .is-none b { color: var(--tomato-deep); }

/* --- Cases cochables (« Quelle base ? ») ---------------------------------- */

.pick-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pick-chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 38px; padding: 0 15px; border-radius: 999px;
  border: 1.5px solid var(--line); background: var(--surface);
  font: inherit; font-size: .85rem; font-weight: 650; color: var(--ink-faint);
  cursor: pointer;
}
.pick-chip[aria-pressed="true"] {
  background: var(--tomato-soft); border-color: var(--tomato-soft); color: var(--tomato-deep);
}
.pick-chip[aria-pressed="true"]::before { content: '✓'; font-size: .8rem; }

/* --- Bascule à deux ou trois volets ---------------------------------------
   Pour un choix qui ne change pas d'écran : pour moi / pour le client. */

/* Un volet — ou un bouton — posé juste sous la barre s'y collait : il lui faut
   le même dégagement qu'à n'importe quel premier bloc de la colonne. */
.shell > .seg:first-child,
.shell > .btn:first-child,
.shell > .note:first-child { margin-top: 14px; }
.seg { display: flex; gap: 3px; padding: 3px; margin-bottom: 12px;
  background: var(--bg-soft); border-radius: 999px; }
.seg a {
  flex: 1; text-align: center; min-height: 36px; line-height: 36px;
  border-radius: 999px; text-decoration: none;
  font-size: .85rem; font-weight: 650; color: var(--ink-faint);
  /* Un libellé qui passe à la ligne fait grandir la bascule et casse sa forme
     de pilule. Il se tronque avant de se plier. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Cinq onglets ne tiennent pas sur une pilule de 320 points : « Formules » y
   perdait ses deux dernières lettres. Ils passent alors sur deux rangs plutôt
   que de se tronquer — un onglet coupé ne dit plus où il mène, et c'est tout
   ce qu'on lui demande. La pilule devient un pavé arrondi, ce qui se voit et
   ne gêne pas : elle reste une bascule. */
.seg--large { flex-wrap: wrap; border-radius: var(--radius); }
.seg--large a { flex: 1 1 30%; }
@media (min-width: 430px) {
  .seg--large { flex-wrap: nowrap; border-radius: 999px; }
  .seg--large a { flex: 1; }
}
.seg a[aria-current] {
  background: var(--surface); color: var(--tomato-deep);
  box-shadow: 0 1px 3px rgba(88,64,44,.14);
}

/* --- Filtres en pastilles -------------------------------------------------
   Quand les choix sont trop nombreux pour une bascule et qu'on accepte de les
   faire défiler : six états de compte ne tiennent pas côte à côte sur 320
   points, et les tasser les rendrait illisibles. */

.chips { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 2px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.chips::-webkit-scrollbar { display: none; }
.chip { flex: 0 0 auto; padding: 6px 12px; min-height: 32px; line-height: 20px;
  border-radius: 999px; background: var(--surface); border: 1px solid var(--line);
  color: var(--ink-faint); font-size: .8rem; font-weight: 600; text-decoration: none; }
.chip--on { background: var(--tomato-soft); border-color: var(--tomato-soft);
  color: var(--tomato-deep); }

/* --- Liste de courses, par rayon ------------------------------------------ */

.rayon { background: var(--surface); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 4px 14px; margin-bottom: 14px; }

/* Le bandeau d'un rayon prend la couleur du rayon, et déborde le rembourrage
   de la carte pour aller d'un bord à l'autre : une bande de couleur qui
   s'arrête à quatorze points des bords se lit comme un encadré, pas comme un
   intitulé de rayon. */
.rayon--primeur      { --r-bg: var(--rayon-primeur);      --r-ink: var(--rayon-primeur-i); }
.rayon--cremerie     { --r-bg: var(--rayon-cremerie);     --r-ink: var(--rayon-cremerie-i); }
.rayon--charcuterie  { --r-bg: var(--rayon-charcuterie);  --r-ink: var(--rayon-charcuterie-i); }
.rayon--poissonnerie { --r-bg: var(--rayon-poissonnerie); --r-ink: var(--rayon-poissonnerie-i); }
.rayon--epicerie     { --r-bg: var(--rayon-epicerie);     --r-ink: var(--rayon-epicerie-i); }
.rayon--divers       { --r-bg: var(--rayon-divers);       --r-ink: var(--rayon-divers-i); }
.rayon[class*="rayon--"] > summary.aisle {
  margin: -4px -14px 0; padding: 11px 14px 10px;
  background: var(--r-bg); color: var(--r-ink);
  border-radius: var(--radius) var(--radius) 0 0;
}
/* Replié, le bandeau EST la carte : ses quatre coins s'arrondissent. */
.rayon[class*="rayon--"]:not([open]) > summary.aisle {
  margin-bottom: -4px; border-radius: var(--radius);
}
.rayon[class*="rayon--"] > summary.aisle::after { color: inherit; opacity: .55; }
/* Le compte se pose sur la couleur : un fond crème y ferait une pastille
   collée, un blanc translucide s'accorde à n'importe laquelle des cinq. */
.rayon[class*="rayon--"] > summary.aisle .tag {
  background: rgba(255, 255, 255, .55); color: inherit;
}
/* Le total d'un rayon prend l'encre de sa couleur : le gris de --ink-faint se
   délavait sur le bleu comme sur le vert. */
.rayon[class*="rayon--"] > summary.aisle .aisle__n { color: inherit; opacity: .72; }

/* La liste de l'hôte n'a pas de replis : ses rayons sont des intitulés, pas
   des volets. Le bandeau est le même, sans le chevron. */
.rayon[class*="rayon--"] > .aisle {
  margin: -4px -14px 0; padding: 11px 14px 10px;
  background: var(--r-bg); color: var(--r-ink);
  border-radius: var(--radius) var(--radius) 0 0;
}
.rayon[class*="rayon--"] > .aisle .tag { background: rgba(255, 255, 255, .55); color: inherit; }
.aisle { display: flex; align-items: center; gap: 8px;
  padding: 10px 0 8px; cursor: pointer; list-style: none;
  font-size: .88rem; font-weight: 700; color: var(--ink); }
.aisle::-webkit-details-marker { display: none; }
/* Le chevron n'annonce que ce qui s'ouvre : sur un simple intertitre — les
   groupes de l'historique — il promettrait un repli qui n'existe pas. */
summary.aisle::after { content: '▾'; color: var(--ink-faint); font-weight: 400; }
.rayon[open] > summary.aisle::after { content: '▴'; }
.aisle__n { margin-left: auto; font-size: .78rem; font-weight: 600; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; }

.buyline { display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 6px 0; border: 0; border-bottom: 1px solid var(--line); background: none;
  font: inherit; color: inherit; text-align: left; cursor: pointer; }
.buyline:last-child { border-bottom: 0; }
.buyline__k { flex: 1 1 auto; min-width: 0; }
.buyline__k strong { display: block; font-size: .86rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.buyline__k span { display: block; font-size: .72rem; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; }
.buyline__v { flex: none; font-size: .88rem; font-weight: 700;
  font-variant-numeric: tabular-nums; }
.buyline.is-covered { opacity: .45; }

/* --- Déroulé : l'instant présent, puis le fil ----------------------------- */

.now {
  background: var(--tomato-deep); color: #fff;
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 12px;
}
.now--done { background: var(--basil-deep); }
.now__clock { font-family: var(--font-display); font-size: 2rem; font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1; }
.now__title { font-family: var(--font-display); font-size: 1.1rem; font-weight: 650; margin-top: 6px; }
.now__detail { font-size: .8rem; opacity: .88; margin-top: 2px; }
.now__btn {
  display: inline-flex; align-items: center; height: 36px; padding: 0 16px; margin-top: 11px;
  border: 0; border-radius: 999px; background: color-mix(in srgb, #fff 94%, transparent);
  color: var(--tomato-deep); font: inherit; font-size: .84rem; font-weight: 700; cursor: pointer;
}
.now--done .now__btn { color: var(--basil-deep); }

.fil { position: relative; padding-left: 22px; }
.fil::before { content: ''; position: absolute; left: 6px; top: 8px; bottom: 8px;
  width: 2px; background: var(--line); border-radius: 2px; }
.fil__day { display: flex; align-items: center; gap: 9px; margin: 9px 0 5px;
  font-family: ui-monospace, Menlo, monospace; font-size: .66rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint); }
.fil__day::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.fil__day:first-child { margin-top: 0; }
.fil__step { position: relative; }
.fil__step::before {
  content: ''; position: absolute; left: -20px; top: 12px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--surface); border: 2.5px solid var(--line);
}
.fil__step[data-status="done"]::before { background: var(--basil); border-color: var(--basil); }
.fil__step.is-now::before { background: var(--tomato-deep); border-color: var(--tomato-soft);
  box-shadow: 0 0 0 4px var(--tomato-soft); }
.fil__btn {
  display: flex; align-items: baseline; gap: 9px; width: 100%;
  padding: 5px 0; border: 0; background: none; cursor: pointer;
  font: inherit; color: inherit; text-align: left;
}
.fil__time { flex: none; width: 40px; font-family: ui-monospace, Menlo, monospace;
  font-size: .72rem; color: var(--ink-faint); }
.fil__label { flex: 1 1 auto; min-width: 0; font-size: .86rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fil__step[data-status="done"] .fil__label { color: var(--ink-faint); font-weight: 500; }
.fil__step.is-now .fil__label { color: var(--tomato-deep); font-weight: 700; }

/* --- Recette d'une étape, en gestes numérotés ----------------------------- */

.recipe { list-style: none; margin: 0; padding: 0; counter-reset: geste; }
.recipe li {
  position: relative; padding: 6px 0 6px 26px; counter-increment: geste;
  font-size: .87rem; color: var(--ink-soft); line-height: 1.45;
}
.recipe li::before {
  content: counter(geste); position: absolute; left: 0; top: 7px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--tomato-soft); color: var(--tomato-deep);
  font-size: .68rem; font-weight: 700; display: grid; place-items: center;
}

/* --- Repli en une ligne --------------------------------------------------- */

.foldline {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 14px; margin-bottom: 10px;
  border: 0; border-radius: var(--radius-sm); background: var(--surface-2);
  font: inherit; font-size: .87rem; font-weight: 650; color: var(--ink);
  text-align: left; cursor: pointer; text-decoration: none;
}
.foldline::after { content: '▾'; margin-left: auto; color: var(--ink-faint); font-weight: 400; }
.foldline--link::after { content: '›'; }
.foldline .tag { margin-left: auto; }
.foldline .tag + ::after { margin-left: 8px; }

/* --- Trois bornes : minimum, recommandé, maximum -------------------------- */

/* L'accueil de l'hôte est le seul écran qui doive tenir en entier : on le
   regarde d'un coup ou pas du tout, et il porte un bouton d'envoi qu'il ne faut
   pas aller chercher. Ses cartes se resserrent donc de quelques pixels, ce que
   nul autre écran n'a besoin de faire. */
.shell--serre .card { padding: 10px 14px; margin-bottom: 6px; }
.shell--serre details.fold { margin-bottom: 5px; }
.shell--serre .pline { padding: 4px 0; }

/* Les trois bornes de l'hôte. Serrées, parce que son accueil doit tenir sans
   défiler : c'est un écran qu'on regarde en entier ou pas du tout. */
.bounds { display: flex; gap: 0; text-align: center; }
.bounds > div { flex: 1; padding: 2px; border-radius: 12px; }
.bounds__k { font-size: .72rem; color: var(--ink-faint); }
.bounds__v { font-weight: 700; font-variant-numeric: tabular-nums; }
.bounds__reco { background: var(--basil-soft); }
.bounds__reco .bounds__k, .bounds__reco .bounds__v { color: var(--basil-deep); }

/* --- Divers -------------------------------------------------------------- */

.hr { height: 1px; background: var(--line); border: 0; margin: 14px 0; }
details.fold { border-radius: var(--radius-sm); background: var(--surface-2); padding: 2px 12px; margin-bottom: 7px; }
details.fold > summary { padding: 9px 0; cursor: pointer; font-weight: 600; font-size: .9rem; list-style: none; }
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary::after { content: '▾'; float: right; color: var(--ink-faint); transition: transform .15s; }
details.fold[open] > summary::after { transform: rotate(180deg); }

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

@media print {
  .topbar, .tabbar, .btn, .info { display: none !important; }
  body { background: #fff; }
  .card { box-shadow: none; border: 1px solid #ddd; }
}

/* --- Règlements et conversation ------------------------------------------ */

/* Le suivi : une soirée par ligne, son état, ce qu'elle a rapporté. */
.payline {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 0; border-bottom: 1px solid var(--line);
  color: inherit; text-decoration: none;
}
.payline:last-child { border-bottom: 0; }
.payline__k { flex: 1 1 auto; min-width: 0; }
.payline__k b { display: block; font-weight: 650; }
.payline__k i {
  display: block; font-style: normal; font-size: .74rem; color: var(--ink-faint);
}
.payline__v {
  flex: none; font-weight: 700; font-variant-numeric: tabular-nums;
}
.tag--link { background: #E5EDF6; color: #2C5480; }

/* La pastille des messages non lus. Elle vit à trois endroits — ici, sur la
   barre du bas, et sur l'icône installée — mais c'est le même chiffre. */
.pastille {
  flex: none; min-width: 19px; height: 19px; padding: 0 5px;
  border-radius: 999px; background: var(--tomato-deep); color: #fff;
  font-size: .66rem; font-weight: 700; line-height: 19px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.tabbar a { position: relative; }
.tabbar .pastille { position: absolute; top: 2px; left: 50%; margin-left: 4px; }

/* Le fil. Ce que l'un écrit s'aligne à droite chez lui, à gauche chez
   l'autre : le gabarit est le même des deux côtés, seul le côté change. */
.fil-thread {
  display: flex; flex-direction: column; gap: 8px; margin: 16px 0;
}
.fil-msg {
  align-self: flex-start; max-width: 82%;
  padding: 9px 13px; border-radius: 18px; border-bottom-left-radius: 6px;
  background: var(--surface); box-shadow: var(--shadow);
  font-size: .92rem; line-height: 1.4;
}
.fil-msg.is-mine {
  align-self: flex-end; background: var(--tomato-deep); color: #fff;
  border-bottom-left-radius: 18px; border-bottom-right-radius: 6px;
}
.fil-msg em {
  display: block; font-style: normal; font-size: .68rem; opacity: .7;
  margin-top: 4px; font-variant-numeric: tabular-nums;
}
.fil-msg.is-mine em { text-align: right; }

/* Un message qui porte autre chose que des mots : un paiement, une facture. */
.fil-card {
  align-self: flex-start; max-width: 90%;
  display: flex; align-items: center; gap: 11px;
  padding: 11px 13px; border-radius: 18px; border-bottom-left-radius: 6px;
  background: var(--surface); box-shadow: var(--shadow);
}
.fil-card.is-mine {
  align-self: flex-end;
  border-bottom-left-radius: 18px; border-bottom-right-radius: 6px;
}
.fil-card__k { flex: 1 1 auto; min-width: 0; }
.fil-card__k b { display: block; font-weight: 700; }
.fil-card__k i {
  display: block; font-style: normal; font-size: .72rem; color: var(--ink-faint);
}

/* Le champ d'écriture. 16 px au minimum : en dessous, Safari zoome à la mise
   au point et l'on se retrouve avec un écran de travers. */
.fil-write { display: flex; gap: 7px; align-items: center; }
.fil-write__in {
  flex: 1 1 auto; min-width: 0; height: 44px; padding: 0 14px;
  font: inherit; font-size: 16px;
  background: var(--surface-2); border: 1.5px solid var(--line);
  border-radius: 999px; color: var(--ink);
}
.fil-write__in:focus {
  outline: none; border-color: var(--tomato); background: var(--surface);
}
.fil-write__go {
  flex: none; width: 44px; height: 44px; border-radius: 50%;
  background: var(--basil-deep); color: #fff; border: 0;
  font-size: 1.05rem; cursor: pointer;
}

/* --- L'accueil du chef -----------------------------------------------------
   Trois évènements, un module, quatre chiffres. Tout ce qui compte tient
   au-dessus de la ligne de flottaison, et le reste a sa page. */

/* Un évènement en une ligne : son nom, ce qu'il reste avant lui, et ce qu'il
   attend. Le compte à rebours rougit quand la soirée est dans la journée. */
.evline {
  display: block; width: 100%; padding: 8px 0;
  border-bottom: 1px solid var(--line);
  text-decoration: none; color: inherit;
}
.evline:last-child { border-bottom: 0; }
/* Une soirée hors de l'historique de la formule : elle est là, elle ne s'ouvre
   plus. Grisée et non cachée — ce qui disparaît fait croire à une perte de
   données, ce qui est fermé à clef fait acheter. */
.evline--ferme { color: var(--ink-faint); cursor: default; }
.evline--ferme b { font-weight: 600; }
.evline__h { display: flex; align-items: baseline; gap: 8px; }
.evline__h b {
  flex: 1 1 auto; min-width: 0; font-size: .95rem; font-weight: 650;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.evline__t {
  flex: none; font-variant-numeric: tabular-nums;
  font-size: .9rem; font-weight: 700; color: var(--tomato-deep);
}
.evline__t--loin { color: var(--ink-faint); font-weight: 650; }
.evline__s { display: block; font-size: .76rem; color: var(--ink-faint); margin-top: 1px; }

/* Un module : une carte qu'on touche, qui dit ce qu'elle porte et ce qui y
   attend. La pastille remplace le chevron — s'il y a quelque chose à lire,
   c'est plus important que de savoir qu'on peut cliquer. */
.mod {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: left; text-decoration: none; color: inherit;
}
.mod__i {
  flex: none; width: 40px; height: 40px; border-radius: 12px;
  display: grid; place-items: center;
  background: var(--basil-soft); color: var(--basil-deep);
}
.mod__i svg { width: 21px; height: 21px; }
.mod__k { flex: 1 1 auto; min-width: 0; }
.mod__k b { display: block; font-size: .95rem; font-weight: 650; }
.mod__k i { display: block; font-style: normal; font-size: .76rem; color: var(--ink-faint); }
.mod__c { flex: none; color: var(--ink-faint); font-size: 1rem; }
/* Le module passé sous les chiffres : un filet l'en sépare, comme une ligne de
   liste se sépare de la suivante. On ouvre cet écran pour voir ce que la
   saison a rapporté ; on va relancer un hôte une fois qu'on l'a vu. */
.mod--sous { margin-top: 10px; padding-top: 11px; border-top: 1px solid var(--line); }

/* Deux rectangles sur l'accueil : les soirées et leurs gestes d'un côté,
   l'argent et ses chiffres de l'autre. Ce qui vivait dessous entre dedans, et
   ce qui entre doit cesser de porter son propre fond blanc — une tuile blanche
   sur une carte blanche ne se détache plus, c'est le trait qui la dessine. */
.bloc > .mod:not(.mod--sous) { padding-bottom: 12px; margin-bottom: 12px;
  border-bottom: 1px solid var(--line); }
.bloc .seg { background: var(--surface-2); }
.bloc .kpi { background: var(--surface-2); box-shadow: none; border: 1px solid var(--line); }

/* Les chiffres clés, deux par deux. */
.kpis { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.kpi {
  padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--surface); box-shadow: var(--shadow);
}
.kpi b {
  display: block; font-family: var(--font-display); font-size: 1.2rem;
  font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums;
}
.kpi i {
  display: block; font-style: normal; font-size: .7rem;
  color: var(--ink-faint); font-weight: 650; margin-top: 2px;
}
/* La marge nette est le seul chiffre qui dise ce qui reste : elle se
   distingue des trois autres, qui ne sont que le chemin pour y arriver. */
.kpi--vert b { color: var(--basil-deep); }

/* Deux chiffres seuls sur leur ligne : on les centre, sinon ils flottent à
   gauche d'un bloc trois fois plus large qu'eux. */
.kpis--centre .kpi { text-align: center; }

/* Ajouter une référence tenait une ligne pleine largeur pour un geste qu'on
   fait trois fois par an. Il devient un carré au bout des deux chiffres, qui
   se partagent ce qui reste — et la ligne rendue vaut plus que le bouton. */
.kpis--plus { display: flex; }
.kpis--plus .kpi { flex: 1 1 0; min-width: 0; }
/* Le stock suit le pas commun — dix points — et garde ses quatorze là où ils
   ont un sens : entre deux rayons, qui sont des sections et non des blocs. */
.kpi__plus {
  flex: none; width: 58px; border-radius: var(--radius-sm);
  background: var(--tomato-deep); color: #fff;
  display: grid; place-items: center; font-size: 1.4rem; line-height: 1;
  text-decoration: none; box-shadow: var(--shadow);
}

/* Le compte d'un rayon replié se colle à droite, juste avant le chevron :
   c'est ce qui dit s'il vaut la peine d'être ouvert. */
.aisle .tag { margin-left: auto; }

/* --- Les onglets de l'hôte ------------------------------------------------- */

/* Le code à partager, en grand : c'est la seule chose à faire sur cet écran
   tant que personne n'a répondu. */
.code-chip--lg { font-size: 1.5rem; letter-spacing: .22em; padding: 10px 16px; }

/* Appeler le chef. Un soir de soirée on appelle, on n'écrit pas : le bouton
   passe donc avant la conversation, et il a la taille d'un pouce. */
.tel {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px; margin: 14px 0 4px;
  background: var(--basil-soft); border-radius: var(--radius);
  color: var(--basil-deep); text-decoration: none;
}
.tel svg { flex: none; width: 24px; height: 24px; }
.tel span { font-size: .95rem; font-weight: 650; }
.tel i {
  display: block; font-style: normal; font-size: .82rem; font-weight: 600;
  opacity: .78; font-variant-numeric: tabular-nums;
}

/* Un invité et ses envies, en une ligne. */
.guestline {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 0; border-bottom: 1px solid var(--line);
}
.guestline:last-child { border-bottom: 0; }
.guestline__k { flex: 1 1 auto; min-width: 0; }
.guestline__k b { display: block; font-size: .92rem; font-weight: 650; }
.guestline__k i {
  display: block; font-style: normal; font-size: .74rem; color: var(--ink-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* La barre d'écriture se colle au bas de l'écran, juste au-dessus des onglets.
   Sans cela, un fil de vingt messages la fait défiler hors de vue et il faut
   remonter tout le fil pour répondre. Le fil, lui, se réserve la place qu'elle
   occupe. */
.fil-write--fixe {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(63px + env(safe-area-inset-bottom));
  z-index: 35; width: 100%; max-width: 560px;
  padding: 8px 16px;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: blur(12px);
}
.shell--chat { padding-bottom: calc(140px + env(safe-area-inset-bottom)); }

/* --- La fiche d'une pizza -------------------------------------------------- */

/* Le nom, la photo, les repères : les trois choses qu'on retouche en regardant
   l'image, donc sur une seule ligne juste sous elle. Le nom prend la place qui
   reste — les deux boutons ont une largeur, pas lui. */
.trio { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.trio__nom {
  flex: 1 1 auto; min-width: 0; height: 40px; padding: 0 12px;
  font: inherit; font-size: 16px; font-weight: 650;
  background: var(--surface); border: 1.5px solid var(--line);
  border-radius: var(--radius-sm); color: var(--ink);
}
.trio__nom:focus { outline: none; border-color: var(--tomato); }
.trio .btn { flex: none; }
.trio .btn svg { width: 16px; height: 16px; margin-right: 4px; vertical-align: -3px; }

/* --- Ordre de montage d'une pizza ------------------------------------------
   Trois façons de déplacer une ligne, et la même largeur pour toutes : la
   poignée qu'on tire ou qu'on touche, et les deux flèches d'un cran. Les
   flèches sont le seul chemin qui marche au clavier. */

.rrow__grip {
  flex: none; width: 26px; height: 34px; padding: 0;
  border: 0; background: none; cursor: grab;
  color: var(--ink-faint); font-size: 1rem; line-height: 1;
  /* Le geste doit rester au script : sans cela le navigateur défile la page
     dès que le doigt bouge, et la ligne ne suit jamais. */
  touch-action: none;
}
.rrow__grip[aria-pressed] { color: var(--tomato-deep); }
.rrow__mv { flex: none; display: flex; flex-direction: column; gap: 1px; }
.rrow__mv button {
  width: 22px; height: 16px; padding: 0;
  border: 0; border-radius: 5px; background: var(--bg-soft);
  color: var(--ink-soft); font-size: .5rem; line-height: 1; cursor: pointer;
}
.rrow__mv button:disabled { opacity: .3; cursor: default; }
.rrow__mv button:active:not(:disabled) { background: var(--tomato-soft); color: var(--tomato-deep); }

/* La ligne saisie, et celle qu'on tire. La première attend qu'on la repose,
   la seconde suit le doigt. */
.rrow.is-held { background: var(--tomato-soft); border-radius: var(--radius-sm); }
.rrow.is-drag { opacity: .65; }
.rrow.is-drag .rrow__grip { cursor: grabbing; }

/* --- La consigne de l'invité -----------------------------------------------
   Tant que le compte des envies n'y est pas, c'est une attente et non un
   acquis : cela se voit à la couleur avant de se lire. */
.note--sm { padding: 9px 12px; font-size: .82rem; }
.note--sm b { display: block; font-weight: 650; }
.note--sm span { display: block; margin-top: 2px; opacity: .8; font-variant-numeric: tabular-nums; }
.note--attente { background: var(--crust-soft); border-left-color: var(--crust); }

/* L'accueil d'un invité qui arrive par un lien : le nom de la soirée avant
   tout, puisque c'est la seule chose qu'il reconnaît. */
.bienvenue { text-align: center; padding: 26px 0 18px; }
.bienvenue__marque { width: 76px; height: 76px; display: block; margin: 0 auto 12px; }
.bienvenue h1 { font-size: 1.5rem; }
.bienvenue p { margin: 4px 0 0; color: var(--ink-faint); font-size: .88rem; }

/* Le bandeau d'une soirée. La barre du haut ne porte plus son nom : c'est ici
   qu'on lit dans laquelle on se trouve, et un nom long y tient. */
.soiree { padding: 12px 0 10px; }
.soiree b {
  display: block; font-family: var(--font-display);
  font-size: 1.2rem; font-weight: 600; line-height: 1.2;
}
.soiree i { display: block; font-style: normal; font-size: .78rem; color: var(--ink-faint); margin-top: 2px; }

/* --- La recette d'un pâton -------------------------------------------------
   Des grammes à saisir, le pourcentage du boulanger en regard, et le poids du
   pâton en bas — qui n'est pas un champ mais leur somme. */

.recette__l {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 0; border-bottom: 1px solid var(--line);
}
.recette__l:last-child { border-bottom: 0; }
.recette__k { flex: 1 1 auto; min-width: 0; }
.recette__k b { display: block; font-size: .9rem; font-weight: 650; }
.recette__k i {
  display: block; font-style: normal; font-size: .72rem;
  color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
/* Quatre-vingt-seize points : à soixante-quatorze, la ligne coupait ce que
   l'application venait elle-même d'y écrire — « 124.9 » se lisait « 124. » sur
   la pâte, « 0.00 » se lisait « 0.0 » sur les formules. Un champ qui ment sur
   sa propre valeur est pire qu'un champ vide : on le croit. Mesuré à 320 comme
   à 390, valeurs rendues et valeurs au maximum déclaré. */
.recette__l input[type=number] { flex: none; width: 96px; text-align: right;
                                 font-variant-numeric: tabular-nums; }
/* L'unité suit un champ de largeur fixe : c'est lui qui aligne la colonne,
   pas elle. Elle se contente donc de sa place — sinon « sans limite » tombe
   à la verticale, une lettre par ligne. */
.recette__u {
  flex: none; min-width: 12px; max-width: 62%; text-align: right;
  font-size: .74rem; color: var(--ink-faint);
}
.recette__v { flex: none; font-size: .76rem; color: var(--ink-faint); font-style: italic; }

/* La levure ne se saisit pas, le pâton non plus : les deux lignes se
   distinguent de celles qu'on remplit. */
.recette__l--inerte { opacity: .72; }
.recette__l--somme { border-top: 2px solid var(--line); padding-top: 10px; }
.recette__l--somme b {
  font-family: var(--font-display); font-size: 1.15rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Le thermomètre du déroulé. On le règle debout dans la cuisine, une main
   occupée : il vit sur la carte du compte à rebours, pas au fond d'une feuille
   qu'il faut ouvrir. */
.therm { flex: none; display: flex; align-items: center; gap: 2px; }
.therm button {
  width: 34px; height: 32px; padding: 0;
  border: 0; border-radius: 999px;
  background: rgba(255, 255, 255, .2); color: #fff;
  font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.therm button:active { background: rgba(255, 255, 255, .34); }
.therm b {
  min-width: 58px; text-align: center;
  font-size: .92rem; font-weight: 700; color: #fff;
  font-variant-numeric: tabular-nums;
}

/* --- La porte d'entrée -----------------------------------------------------
   Presque tous ceux qui arrivent ici ont un code en main : c'est à eux que
   l'écran s'adresse, et le champ du code est le seul de la page. */

/* Un écran qui n'a qu'une chose à faire centre cette chose. La barre du haut
   fait 59 points ; on retire aussi les marges de la colonne pour que le milieu
   du bloc tombe au milieu de ce qui reste, et non de la page entière. */
/* C'est le champ qu'on centre, pas le bloc. Centrer l'ensemble — marque, titre,
   carte — poussait la saisie dans le tiers bas de l'écran, puisque la marque
   pèse cent soixante points au-dessus d'elle. Trois rangées, donc : la carte
   occupe celle du milieu et tombe pile au centre, la marque se pose au bas de
   celle du haut, et la dernière ne fait qu'équilibrer. */
.shell--porte {
  /* La hauteur de sa barre, doublée : la porte s'en offre deux. */
  min-height: calc(100vh - var(--barre) - env(safe-area-inset-bottom));
  display: grid;
  /* Une colonne, dite explicitement. Sans elle, la grille en créait une par
     enfant : chaque bloc posé en rangée 2 s'en allait dans SA colonne, et
     l'écran le plus vu de l'application affichait sa carte sur 220 points de
     large avec le lien de confidentialité collé à côté. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: 1fr auto 1fr;
  padding-bottom: calc(16px + env(safe-area-inset-bottom));
}
.shell--porte > * { grid-column: 1; grid-row: 2; }
.shell--porte > .porte { grid-row: 1; align-self: end; }
/* min-height: 0 n'est pas un détail : un élément de grille refuse par défaut de
   rétrécir sous sa taille naturelle. Sans lui, un logo plus haut que sa rangée
   la déborde des deux côtés et paraît collé au bandeau ET à la carte — ce qui
   ressemble à un défaut de centrage alors que c'est un défaut de place. */
.shell--porte > .porte__marque { grid-row: 1; align-self: center; min-height: 0; }
/* Plus rien ne précède la carte : le logo et le nom sont remontés dans la
   barre, et le milieu de l'écran ne porte que le champ du code. */
.shell--porte > .card { margin-top: 0; }
.shell--porte > .note { grid-row: 1; align-self: start; }
/* Ce qui vient après la carte tombe dans la troisième rangée : deux blocs dans
   la même cellule se superposeraient. */
.shell--porte > .porte__pied { grid-row: 3; align-self: start; }

/* Sur un écran court — un iPhone SE, un clavier ouvert — les trois rangées se
   marcheraient dessus. On reprend le fil normal : mieux vaut défiler que
   superposer. */
@media (max-height: 700px) {
  .shell--porte { display: block; min-height: 0; padding-top: 18px; }
  .shell--porte > .porte { }
}

.porte { text-align: center; padding: 0 0 6px; }
/* Le logo d'accueil : dans la rangée du haut de la grille, centré dans l'espace
   qui sépare la barre de la carte. Ni collé à l'une ni à l'autre. */
.porte__marque { display: grid; place-items: center; min-height: 0; }
/* Deux plafonds, et chacun sert à quelque chose. Celui en unités de largeur le
   retient sur un téléphone étroit ; celui en hauteur le fait tenir dans sa
   rangée sur un écran court, au lieu de la déborder. Sans le second, le logo
   pousse la carte du code vers le bas et ne se centre plus dans rien. */
.porte__marque img {
  width: min(252px, 60vw); height: auto;
  max-height: 100%; object-fit: contain;
  display: block;
}
/* Le nom en plein milieu de la porte : c'est l'autre endroit — le seul autre —
   où la marque s'écrit. Le reste de la page garde la pile de lecture. */
.porte h1 { font-family: var(--font-marque); font-weight: 700;
            font-size: 2.1rem; margin-top: 10px; letter-spacing: -.015em; }

/* Le mot de la barre, quand la marque est déjà en grand dans la page.

   Il était centré sur la barre elle-même, et non entre ses voisins, parce que
   le logo à gauche et la porte à droite n'ont pas la même largeur. Depuis que
   la porte d'entrée porte aussi « Abonnement PRO », un mot centré tombe
   dessus : il reprend sa place dans le fil, et l'espaceur le pousse à gauche
   du reste. Un peu moins joli qu'un centrage parfait, et lisible. */
.topbar__mot {
  font-family: ui-monospace, Menlo, monospace; font-size: .66rem;
  letter-spacing: .22em; font-weight: 700; color: var(--ink-faint);
  white-space: nowrap;
}
/* Sur la porte, le mot prend toute la place que les deux boutons lui laissent
   et se centre dedans : il n'y a plus de logo à sa gauche, et le centrer sur
   la barre entière l'aurait fait glisser sous « S'abonner ». */
/* « Bienvenue » occupe toute la place que les deux boutons lui laissent, et se
   centre dedans. L'espaceur disparaît : sa marge automatique avalait le vide
   avant que le mot puisse grandir, et le mot restait collé à gauche. */
.topbar--porte .topbar__spacer { display: none; }
.topbar--porte .topbar__mot {
  /* Base zéro : le mot prend TOUTE la place laissée, et son centrage porte
     alors sur cette place et non sur sa propre largeur. */
  flex: 1 1 0; text-align: center;
  /* Le serif, et pas la fonte de la marque : « Bienvenue » n'est pas la
     marque, et --font-marque lui est réservée. La grotesque est aussi bien
     plus large — mesurée, elle coupait le mot de soixante-trois points sur un
     téléphone de trois cent vingt. */
  font-family: var(--font-display); font-size: 2.4rem; line-height: 1.05;
  letter-spacing: .01em; font-weight: 600; color: var(--ink-soft);
  text-transform: none;
}

/* La porte d'entrée s'offre une barre deux fois plus haute. Elle ne porte plus
   la marque — le logo est en grand au milieu de la page — mais le mot qui
   accueille, et il prend toute la hauteur qu'elle lui donne. C'est le premier
   écran qu'on voit du site : il peut se permettre de respirer. */
/* 118 points, soit exactement le double des 59 ordinaires. La hauteur se pose
   plutôt que de se déduire d'un remplissage : le logo y grandit sans que la
   barre bouge, et la colonne d'en dessous peut compter dessus. */
/* La porte avait sa barre doublée, du temps où « Bienvenue » s'y écrivait en
   grand. Le mot est parti, la marque a repris sa place : la hauteur redevient
   celle de tous les autres écrans. */
.topbar--porte { min-height: var(--barre); }

/* La porte du chef : discrète, mais pas cachée. */
.topbar__in {
  display: inline-flex; flex: none;
  margin: -6px -6px -6px 0; padding: 6px;
  border-radius: 999px; color: var(--tomato-deep);
}
.topbar__in svg { width: 23px; height: 23px; }
.topbar__in:active { background: var(--tomato-soft); }

/* Une fois et demie la taille d'une légende ordinaire : sur la porte, cette
   ligne n'est pas une étiquette de champ mais la seule phrase de l'écran. */
.lbl-centre {
  display: block; text-align: center; font-size: 1.23rem;
  font-weight: 650; color: var(--ink-soft); line-height: 1.25;
}

/* Le champ du code : le seul de l'écran, donc le plus grand. On le tape à deux
   pouces, souvent en tenant un plat de l'autre main. Le chevron le prolonge
   plutôt que de s'aligner dessous. */
.saisie { display: flex; gap: 7px; margin-top: 14px; }
.saisie__code {
  flex: 1 1 auto; min-width: 0; height: 64px; padding: 0 12px;
  background: var(--surface-2); border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  /* Ce qu'on tape s'écrit à la taille de « CODE », et au même espacement : le
     mot s'efface à la première frappe, et rien ne doit changer de gabarit à ce
     moment-là — un texte qui rapetisse sous le doigt donne l'impression d'avoir
     tapé à côté.
     Un code tiré fait huit signes et tient largement. Un code choisi peut aller
     jusqu'à seize : le champ défile alors, ce qui est le comportement normal
     d'une saisie et non une casse de mise en page. */
  font: inherit; font-size: 2.9rem; font-weight: 700; letter-spacing: .1em;
  text-align: center; color: var(--ink); text-transform: uppercase;
  /* L'espacement des lettres s'ajoute AUSSI derrière la dernière, et un texte
     centré s'en trouve poussé d'un demi-cran vers la gauche. Le retrait le
     rattrape. C'est la seule correction horizontale nécessaire.
     Rien pour la verticale : un navigateur centre tout seul la ligne d'un
     champ de saisie, et il le fait bien. Une hauteur de ligne fixée ici le lui
     interdisait — voir le texte d'invite juste dessous, qui est plus gros que
     le champ et se retrouvait plaqué en haut. */
  text-indent: .1em;
  line-height: normal;
}
/* « CODE » s'écrit à la mesure du champ : c'est le seul mot de l'écran et la
   seule chose qu'on y attend. Il ne grandit que le texte d'invite — ce qu'on
   tape garde sa taille, sinon un code de seize signes sortirait du cadre. */
/* Le champ n'a plus de texte d'invite visible : un espace, seulement, pour que
   :placeholder-shown réponde. */
.saisie__code::placeholder { color: transparent; }

/* « CODE », posé par-dessus le champ et centré par la grille — donc centré
   exactement, dans les deux sens, quelle que soit sa taille. C'est tout
   l'intérêt de le sortir du texte d'invite : celui-ci se dessine sur la ligne
   de base du champ et ne peut pas être plus grand que lui sans déborder. */
.saisie__champ { position: relative; flex: 1 1 auto; min-width: 0; display: block; }
.saisie__champ .saisie__code { width: 100%; }
.saisie__mot {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 2.9rem; font-weight: 700; letter-spacing: .1em;
  color: var(--ink-faint); pointer-events: none;
  /* Le retrait rattrape l'espacement ajouté derrière la dernière lettre, qui
     pousserait le mot d'un demi-cran vers la gauche. */
  text-indent: .1em;
}
/* Le mot s'efface dès qu'on touche le champ, et pas seulement à la première
   frappe : on tape sur « CODE », le mot part, le curseur reste. Attendre la
   première lettre laissait un instant où l'on écrivait derrière le mot.
   Sans script : c'est le champ lui-même qui dit s'il a le doigt et s'il est
   vide. */
.saisie__champ .saisie__code:focus + .saisie__mot,
.saisie__champ .saisie__code:not(:placeholder-shown) + .saisie__mot { display: none; }
.saisie__code:focus { outline: none; border-color: var(--tomato); background: var(--surface); }
.saisie__go {
  flex: none; width: 70px; height: 64px; padding: 0;
  border: 0; border-radius: var(--radius-sm);
  background: var(--tomato-deep); color: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.saisie__go svg {
  display: block; width: 16px; height: 33px; fill: none; stroke: currentColor;
  stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round;
}

/* --- Le pas vertical d'un écran ---------------------------------------------
   Dix points entre deux blocs, partout. Ils étaient à quatre, sept, huit,
   treize, quinze et seize selon la page — six valeurs pour un même geste,
   chacune posée à la main sur un bloc. L'œil compte les écarts avant de lire
   les mots, et six écarts font une page qui flotte.

   En fin de feuille, et c'est voulu : ces règles ont la force d'une classe,
   comme celles qu'elles corrigent, et c'est l'ordre qui tranche. Écrites plus
   haut, `.titre` et `.seg` les auraient recouvertes.

   La règle d'un changement de sujet garde les siens : vingt-deux au-dessus,
   douze en dessous. C'est ce qui la fait lire comme une coupure et non comme
   un bloc de plus. */
/* Le pas traverse ce qui n'a pas de classe. Un <form> nu enveloppe la fiche
   d'une pizza, ou la maison de l'hôte tout entière : l'œil ne le voit pas, et
   le pas ne doit pas s'arrêter à lui. Sans cette seconde ligne, chaque écran
   bâti sur un formulaire réinventait ses marges bloc par bloc — six points,
   puis sept, puis huit, au gré du jour où on les avait posées. */
.shell > * + *,
.shell > form:not([class]) > * + * { margin-top: 10px; }
.shell > .regle,
.shell > form:not([class]) > .regle { margin-top: 22px; margin-bottom: 12px; }
.shell > .regle + *,
.shell > form:not([class]) > .regle + * { margin-top: 12px; }
/* Les marges basses posées à la main s'annulent : deux marges qui se suivent
   fusionnent, et la plus grande gagnerait — le pas ci-dessus n'aurait alors
   d'effet que là où il est déjà respecté. */
.shell > *:not(.regle),
.shell > form:not([class]) > *:not(.regle) { margin-bottom: 0; }
/* Deux rayons se séparent de quatorze points et non de dix : ce sont des
   sections, pas deux blocs d'un même sujet. Au stock ils vivent dans un
   formulaire et gardent leur propre marge ; sur la liste de courses ils sont
   enfants de la colonne, et le pas commun les aurait recollés. */
.shell > .rayon + .rayon,
.shell > form:not([class]) > .rayon + .rayon { margin-top: 14px; }
/* Une carte peut avoir une dernière ligne hors cadre — le bouton qui supprime
   une formule, par exemple. Six points en négatif la recollent : ce n'est pas
   un bloc de plus, c'est le bas de celui du dessus. Écrit ici plutôt qu'en
   style d'attribut, parce que le pas passe après et l'aurait recouvert. */
.shell > .colle,
.shell > form:not([class]) > .colle { margin-top: -6px; }

/* Le bouton qui enregistre un relevé de stock.

   Trente-six références demandent plusieurs écrans de défilement. Le bouton
   attendait tout en bas : on corrigeait une quantité en haut de la liste, on
   changeait d'onglet, et la correction partait avec. Il reste donc à vue,
   posé juste au-dessus de la barre du bas.

   Il se colle par le bas de la colonne et non de l'écran : la colonne est
   centrée et bornée à 560 points, un `position: fixed` l'aurait étalé sur toute
   la largeur d'une tablette, loin de la liste qu'il valide. */
.inv__valider {
  position: sticky;
  bottom: calc(var(--barre) + env(safe-area-inset-bottom) - 4px);
  z-index: 5;
  margin: 14px -16px 0;
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--line);
}
.inv__valider .btn { margin: 0; }

/* La photo d'un ingrédient, dans sa fiche. */
.ing-photo { display: flex; align-items: center; gap: 10px; margin: 10px 0 4px; }
.ing-photo__vue {
  flex: none; width: 56px; height: 56px; border-radius: var(--radius-sm);
  object-fit: cover; box-shadow: inset 0 0 0 1px var(--line);
}

/* Un écran qui n'a rien à montrer, et le geste qui le remplit.

   Différent de `.empty`, qui n'est qu'une ligne grise au fil d'une liste : ici
   c'est tout l'écran qui est vide, et le message doit tomber au milieu de la
   hauteur avec le bouton sous lui. Un constat sans issue laisserait le chef
   chercher où l'on ajoute. */
.vide-centre {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; text-align: center;
  min-height: 46vh; padding: 20px 24px;
  color: var(--ink-faint);
}
.vide-centre svg { width: 54px; height: 54px; opacity: .3; }
.vide-centre__mot { margin: 0; font-size: 1.05rem; font-weight: 650; color: var(--ink-soft); }
.vide-centre__aide { margin: 0; max-width: 30ch; font-size: .85rem; line-height: 1.45; }
.vide-centre .btn { margin-top: 6px; }

/* ===========================================================================
   L'abonnement, vu de dehors.

   Empilées et non en colonnes : trois colonnes sur 390 points obligeaient à
   défiler de côté pour comparer, ce qui est le contraire de comparer.

   Et compact, parce que ce qui ne tient pas dans l'écran ne se compare pas non
   plus. Trois leviers plutôt qu'un rétrécissement général : chaque carte ne
   liste que ce qu'elle AJOUTE à la précédente, son bouton n'apparaît qu'une
   fois choisie, et le bandeau porte le nom, la pastille et les deux prix sur
   une seule ligne.
   ======================================================================== */

.promo-haut {
  display: flex; gap: 8px; align-items: center;
  margin: 0 0 12px; padding-bottom: 11px; border-bottom: 2px solid var(--trait);
}
.promo-haut input {
  flex: 1 1 auto; min-width: 0; min-height: 42px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); font: inherit; font-size: .86rem; color: var(--ink);
  text-transform: uppercase; letter-spacing: .1em;
}
.promo-haut button {
  flex: none; min-height: 42px; padding: 0 16px; border: 0;
  border-radius: var(--radius-sm); background: var(--tomato-deep); color: #fff;
  font: inherit; font-size: .82rem; font-weight: 700; cursor: pointer;
}
.promo-haut__pose { flex: 1 1 auto; min-width: 0; font-size: .82rem; color: var(--ink-soft); }
.promo-haut__pose b { color: var(--ink); }
.promo-haut__pose i { display: block; font-style: normal; font-size: .74rem; color: var(--ink-faint); }

.offres { display: flex; flex-direction: column; gap: 9px; margin-top: 4px; }

.offre {
  position: relative; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); box-shadow: var(--shadow);
  padding: 0 0 11px;
}
/* Tout ce qui n'est ni la zone ni le bouton se décale du bord ; le bandeau, lui,
   va d'un bord à l'autre. */
.offre > *:not(.haut):not(.zone):not(.choix) { margin-left: 13px; margin-right: 13px; }

/* La carte entière se choisit : une radio invisible, un libellé qui la couvre.
   On ne vise pas un petit bouton, on tape la carte. */
.offre .choix { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; pointer-events: none; }
.offre .zone { position: absolute; inset: 0; border-radius: var(--radius-sm); cursor: pointer; z-index: 2; }
.offre > *:not(.zone):not(.choix):not(.go-offre) { position: relative; z-index: 1; pointer-events: none; }
.offre > .go-offre { position: relative; z-index: 3; }

/* Le bouton n'apparaît qu'une fois la carte choisie. Quatre boutons offerts
   ensemble demandent quatre fois « lequel ? » ; un seul, après le choix, ne
   demande plus que « on y va ? ». Et trois boutons en moins, c'est trois
   hauteurs de moins à faire défiler. */
.offre .go-offre { display: none; }
.offre:has(.choix:checked) .go-offre { display: block; }
.offre:has(.choix:checked) { border-color: var(--tomato-deep); box-shadow: 0 0 0 1px var(--tomato-deep), var(--shadow); }
.offre:has(.choix:focus-visible) { outline: 2px solid var(--tomato-deep); outline-offset: 2px; }

.offre .haut {
  display: flex; align-items: center; gap: 7px;
  padding: 10px 13px; margin: 0 0 9px;
  background: linear-gradient(168deg, #4A342A 0%, #6B4436 100%);
}
.offre .nom { font-size: 1rem; font-weight: 800; letter-spacing: -.02em; color: #fff; }
.offre .eti {
  font-size: .62rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; background: var(--crust); color: #4A342A;
}
.offre .eti--libre { background: var(--basil-soft); color: var(--basil-deep); }

/* Le rythme prend la place du taux de Gestineo : le mois en grand, l'année
   dessous avec ce qu'elle fait gagner. */
.offre .tarif {
  margin-left: auto; text-align: right; white-space: nowrap; line-height: 1.15; flex: none;
  font-variant-numeric: tabular-nums;
}
.offre .tarif b { display: inline; font-size: 1.15rem; font-weight: 800; letter-spacing: -.03em; color: var(--crust); }
.offre .tarif s { display: block; font-size: .62rem; color: #C9B6A6; }
.offre .tarif i { display: inline; font-style: normal; font-size: .62rem; color: #C9B6A6; margin-left: 5px; }
.offre .tarif u { display: block; text-decoration: none; margin-top: 2px; font-size: .68rem; font-weight: 650; color: #E4D5C6; }
.offre .tarif em { font-style: normal; font-weight: 800; color: var(--basil); }

/* La carte gratuite ne concourt pas : bandeau clair, pas de dégradé sombre. */
.offre--libre .haut--libre { background: var(--basil-soft); }
.offre--libre .nom { color: var(--basil-deep); }
.offre--libre .tarif b { color: var(--basil-deep); }

.offre--conseille { border-color: var(--crust); }

/* « En plus de X » : la carte ne dit que son écart. Le filet à mi-largeur
   sépare sans peser une ligne entière. */
.offre .en-plus {
  margin: 8px 0 5px; font-size: .7rem; font-weight: 700; color: var(--ink-faint);
  position: relative; padding-bottom: 6px;
}
.offre .en-plus::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 46%; height: 1px; background: var(--line);
}

.offre ul { list-style: none; margin: 5px 0 10px; padding: 0; }
.offre li {
  display: flex; align-items: flex-start; gap: 7px;
  padding: 2px 0; font-size: .8rem; line-height: 1.38; color: var(--ink-soft);
}
.offre li::before {
  content: "✓"; flex: none; font-weight: 800; color: var(--basil-deep); font-size: .78rem; line-height: 1.5;
}
.offre li span { flex: 1 1 auto; min-width: 0; }
.offre li span b { color: var(--ink); font-weight: 700; }

.go-offre {
  display: block; width: calc(100% - 26px); margin: 0 13px; padding: 11px;
  border: 0; border-radius: var(--radius-sm);
  background: var(--tomato-deep); color: #fff;
  font: inherit; font-size: .86rem; font-weight: 700; text-align: center; cursor: pointer;
}
.go-offre--doux { background: var(--basil-soft); color: var(--basil-deep); }
.go-offre:active { filter: brightness(.94); }

/* Le code d'invitation, écrit comme un code se lit. */
.saisie-code {
  text-transform: uppercase; letter-spacing: .14em;
  font-family: ui-monospace, Menlo, monospace;
}

/* La mention de TVA, en pied de la page des formules. Discrète mais pas
   minuscule : c'est la première question d'un professionnel devant un tarif. */
.mention-ttc {
  margin: 12px 0 0; padding: 9px 12px;
  border-radius: var(--radius-sm); background: var(--surface-2);
  font-size: .74rem; line-height: 1.45; color: var(--ink-faint); text-align: center;
}
.mention-ttc b { color: var(--ink-soft); }
