/* =============================================================================
   LW MENU — FEUILLE DE COMPOSANTS
   -----------------------------------------------------------------------------
   Le contrat de jetons vit dans app/assets/tailwind/application.css et ne se
   rouvre pas (AD-24). Cette feuille-ci porte les regles du produit, et elle ne
   contient AUCUNE valeur en dur : une hexadecimale, une ombre, une bordure, un
   rayon ou une duree ecrits ici seraient un bug au meme titre qu'une requete
   N+1 (UX-DR2). Tout passe par un jeton, nomme par son role.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Texte de substitution des champs — UX-DR111, interdit dur.
   -----------------------------------------------------------------------------
   Le couple `texte-4` sur `surface-creuse` vaut 4,28:1 en regime sombre et
   4,40:1 en clair : sous AA dans les deux. Et il n'est PAS exempte — WCAG 1.4.3
   n'exempte que les composants INACTIFS, or un texte de substitution vit dans un
   champ ACTIF. C'est `texte-3` qu'on pose (6,91:1 / 6,25:1 sur creuse).

   Sans cette regle, le navigateur applique son propre gris et le contrat n'est
   tenu par rien : « Karine, dans le bus, a une main, lisait "Votre nom" et
   "0694 00 00 00" sous AA ».
   -------------------------------------------------------------------------- */
input::placeholder,
textarea::placeholder {
  color: var(--color-texte-3);
  opacity: 1; /* Firefox eclaircit le texte de substitution par defaut, ce qui
                 abaisserait un rapport de contraste deja mesure. */
}

/* -----------------------------------------------------------------------------
   Largeur de la colonne de contenu — UX-DR113.
   -----------------------------------------------------------------------------
   « A partir de 768 px, la colonne de contenu SE CENTRE ET SE BORNE ; elle ne
   s'etale pas. Aucune barre laterale, aucun tableau, aucune vue bureau. »

   ⚠️ Le contrat de jetons ne porte AUCUNE largeur de colonne de contenu — il
   n'a que `--spacing-largeur-colonne-quantite` et `-reserve`, qui sont des
   colonnes de tableau de quantites. Et le contrat NE SE ROUVRE PAS ici
   (AD-24) : une garde de la story 1.1 verifie que la feuille versee est
   identique a la source. La valeur vit donc dans cette feuille de composants.

   La valeur n'est pas inventee : c'est le point de rupture nomme du dossier
   (« 480 - 767 px »), donc la borne du palier au-dela duquel la colonne cesse
   de grandir. Candidate a entrer au contrat en v1.2.
   -------------------------------------------------------------------------- */
:root {
  --largeur-lecture: 480px;
}

/* ⚠️ Nommee `colonne-lecture` et NON `max-w-lecture` : une classe qui imite la
   forme d'un utilitaire Tailwind laisserait croire qu'elle vient du contrat de
   jetons. Elle n'en vient pas — elle vit ici, et c'est visible. */
.colonne-lecture {
  max-width: var(--largeur-lecture);
}

/* -----------------------------------------------------------------------------
   Deux mesures prescrites par DESIGN.md, que le contrat de jetons ne nomme pas.
   -----------------------------------------------------------------------------
   UX-DR2 : « une hexadecimale, une ombre, UNE BORDURE, un rayon ou une duree
   dans un partial ERB est un bug au meme titre qu'une requete N+1. »

   Ces deux valeurs viennent de DESIGN.md § Composants :
     - « Libelle ... marge basse 6 px » et « Aide sous le champ ... marge haute
       6 px ». L'echelle d'espacement du contrat va de 2 px a 4 px puis 8 px :
       AUCUN jeton ne vaut 6. La mesure est donc nommee ici.
     - « bord bas 3 px {colors.accent-actif} qui lui donne son relief physique ».
       La couleur est un jeton ; l'epaisseur n'en a pas.

   Elles vivent dans cette feuille de composants et non dans le contrat, parce
   que le contrat NE SE ROUVRE PAS (AD-24) — une garde de la story 1.1 verifie
   que la feuille versee est identique a la source. Candidates a y entrer en v1.2.
   -------------------------------------------------------------------------- */
:root {
  --marge-libelle: 6px;
  --epaisseur-relief-bouton: 3px;
}

.mb-libelle { margin-bottom: var(--marge-libelle); }
.mt-libelle { margin-top: var(--marge-libelle); }

/* ⚠️ `gap-libelle` ET `pt-libelle` ETAIENT DES CLASSES FANTOMES.
   `--marge-libelle` vit ici, pas dans le contrat de jetons : Tailwind n'en tire
   donc AUCUN utilitaire. `gap-libelle` etait ecrit depuis la story 2.3 dans une
   dizaine de vues et ne produisait rien — les listes n'avaient aucun ecart, et
   personne ne l'a vu parce qu'une classe absente ne leve pas.
   Releve en revue de la story 2.7, sur `pt-libelle` qui venait d'y etre ajoute. */
.gap-libelle { gap: var(--marge-libelle); }
.pt-libelle { padding-top: var(--marge-libelle); }

.border-b-accent {
  border-bottom: var(--epaisseur-relief-bouton) solid var(--color-accent-actif);
}

/* Le meme relief, eteint — DESIGN.md § Bouton principal : « Eteint — fond
   surface-eteinte, texte texte-3, BORD BAS filet ». L'epaisseur ne change pas :
   c'est la couleur qui dit l'etat, pas la geometrie. Un bouton qui maigrit en
   s'eteignant deplacerait ce qui l'entoure. */
.border-b-eteint {
  border-bottom: var(--epaisseur-relief-bouton) solid var(--color-filet);
}

/* -----------------------------------------------------------------------------
   L'emplacement a remplir mais laisse vide — UX-DR37, story 2.5.
   -----------------------------------------------------------------------------
   Le jeton `--trait-style-emplacement` EXISTE au contrat (§ addenda). Mais un
   jeton de STYLE DE TRAIT n'appartient a aucun namespace Tailwind : il ne
   genere pas d'utilitaire tout seul, contrairement a une couleur ou a un
   espacement. Sans cette classe, la vignette vide aurait porte `border-dashed`
   — c'est-a-dire une valeur en dur hors du contrat, ce qu'`UX-DR2` refuse.

   ⚠️ ELLE NE VIT PAS DANS LA FEUILLE DE JETONS, et c'est une contrainte de
   garde : `tokens_contract_test` verifie que le versement est IDENTIQUE a la
   source. Le contrat ne se rouvre pas ici (AD-24).

   ⚠️ ELLE NE REUTILISE JAMAIS `--etat-reglement-style-attente` : celui-la dit
   « l'argent n'est pas rentre », et le confondre brouillerait le signal le plus
   economique du produit.
   -------------------------------------------------------------------------- */
.border-emplacement {
  border-style: var(--trait-style-emplacement);
}

/* -----------------------------------------------------------------------------
   Les cibles de saut — UX-DR100, complement de la regle [D-03] du contrat.
   -----------------------------------------------------------------------------
   Le contrat pose `scroll-margin` sur tout element focalisable, mais son
   selecteur exclut `[tabindex="-1"]` — a raison : ce sont les elements qu'on ne
   TABULE pas. Sauf qu'une cible de lien d'evitement porte precisement
   `tabindex="-1"`, et qu'elle est focalisee par programme au saut.

   Sans cette regle, « Aller a votre commande et au total » amene le
   recapitulatif a la limite du viewport, c'est-a-dire SOUS la barre de pouce
   collante — le focus non masque de WCAG 2.4.11 tombe exactement la ou on
   croyait l'avoir tenu.

   ⚠️ Le contrat NE SE ROUVRE PAS (AD-24) : la regle vit donc ici, comme la
   largeur de colonne.
   -------------------------------------------------------------------------- */
[tabindex="-1"][id] {
  scroll-margin-top:    var(--spacing-desengagement-collant);
  scroll-margin-bottom: var(--spacing-desengagement-collant);
}

/* -----------------------------------------------------------------------------
   Le degagement sous une PILE collante — majeur de la revue du 29/08.
   -----------------------------------------------------------------------------
   Le jeton du contrat vaut 112px, et son budget est ecrit : une barre de 44,
   une rangee de 56, les filets et l'ecart. C'etait vrai d'UNE barre.

   La liste du jour en empile desormais QUATRE : rangee de journee (44) + ruban
   d'ecart (4) + rangee d'onglets (44) + barre de filtres (44), plus leurs
   espacements — et un cinquieme etage, le bandeau de filtre actif, quand un
   filtre est pose. La pile depasse 190px, et jusqu'a 250px filtree : une carte
   focalisee au clavier atterrissait EN PARTIE SOUS ELLE. C'est le defaut
   [D-03] que le jeton existe pour empecher (WCAG 2.4.11, focus non masque).

   ⚠️ LE CONTRAT NE SE ROUVRE PAS (`AD-24`) : la valeur vit ici, nommee, comme
   les trois valeurs du papier et la largeur de colonne. Elle ne REMPLACE pas le
   jeton — elle ne s'applique qu'aux cibles qui suivent une pile, et le reste du
   produit garde les 112px du contrat.

   ⚠️ UN EXCES DE DEGAGEMENT EST BENIN — la cible apparait un peu plus bas —,
   un DEFICIT casse le critere. La valeur couvre donc la pile la plus haute,
   filtre actif compris.
   -------------------------------------------------------------------------- */
:root { --desengagement-pile: 256px; }

.pile-collante ~ * [tabindex="-1"][id],
.pile-collante ~ [tabindex="-1"][id] {
  scroll-margin-top: var(--desengagement-pile);
}

/* -----------------------------------------------------------------------------
   Le squelette de chargement du frame — UX-DR59, UX-DR109, story 2.14.
   -----------------------------------------------------------------------------
   Il n'y a qu'UN seul echange asynchrone sur la liste du jour : le remplacement
   du `turbo-frame#vue_du_jour` au changement d'onglet — et desormais de filtre.
   Turbo pose lui-meme `aria-busy="true"` sur le frame pendant ce chargement :
   la bascule est donc entierement en CSS, sans une ligne de JavaScript
   (UX-DR115), et sans le moindre controleur Stimulus sur cet ecran.

   ⚠️ RIEN NE BOUGE. Aucun `@keyframes`, aucune pulsation, aucun fileur : le
   depot n'en contient aucun, et le bloc « mouvement reduit » du contrat de
   jetons ramene les durees a 1 ms sans remettre aucune `transform` a `none`.
   Son commentaire promet « on neutralise tout deplacement » ; tant qu'aucun
   deplacement n'existe, il dit vrai. Faire pulser ce squelette le rendrait
   faux, et le corriger demanderait de rouvrir un contrat verse a l'octet
   (AD-24). UX-DR109 demande de toute facon l'inverse : « aucun contenu ne
   bouge, ne clignote ou ne defile tout seul ».

   ⚠️ AUCUNE VALEUR EN DUR : la surface, le rayon et l'ecart sont des jetons.
   -------------------------------------------------------------------------- */
.squelette { display: none; }

.squelette-rangee {
  background-color: var(--color-surface-creuse);
  border-radius:    var(--radius-md);
}

turbo-frame[aria-busy="true"] .squelette   { display: flex; }
turbo-frame[aria-busy="true"] .vue-en-cours { display: none; }

/* -----------------------------------------------------------------------------
   LA PISTE DE GLISSEMENT — UX-DR19 a UX-DR23, UX-DR103, contrat § 4. Story 4.2.
   -----------------------------------------------------------------------------
   « Hauteur {spacing.cible-action}, largeur pleine de la carte, course minimale
   {spacing.course-glissement}. Le pouce pousse un curseur d'accent de gauche a
   droite. » Les deux jetons EXISTENT au contrat — 72px et 132px — et le
   commentaire de `--spacing-cible-action` nomme deja la piste : « ET hauteur de
   la piste de glissement. Le geste le plus repete. »

   ⚠️ CE QUI VIT ICI EST CE QUE TAILWIND NE SAIT PAS DIRE. La hauteur, le fond,
   le filet, le rayon et la famille de texte sont des utilitaires portes par le
   balisage, comme partout dans ce depot ; seuls le REMPLISSAGE en surimpression
   et la course minimale demandent une regle. Une classe de plus serait une
   classe a maintenir.

   ⚠️⚠️ LA COURSE EST VISIBLE PENDANT QU'ELLE SE FAIT — c'est ce qui separe la
   piste de l'appui long : « on voit ou on en est, on peut revenir ». Sa largeur
   est portee par `--course`, posee par le controleur Stimulus a l'execution :
   une largeur en `style="width:…"` SERVIE serait refusee par la garde du
   plancher, qui refuse toute dimension fixe en ligne.

   ⚠️ AUCUNE TRANSITION, AUCUNE ANIMATION. Le bloc « mouvement reduit » du
   contrat de jetons ramene les durees a 1 ms sans remettre aucune `transform` a
   `none` ; une garde d'`impression_test` tient la condition, et le retour
   elastique se fait en remettant `--course` a zero, pas en animant.

   ⚠️ AUCUNE VALEUR EN DUR : la course, le voile d'accent et le voile de succes
   sont des jetons du contrat, nommes par leur role.
   -------------------------------------------------------------------------- */
.piste-glissement {
  --course: 0%;
  position: relative;
  overflow: hidden;
  min-width: var(--spacing-course-glissement);
  /* ⚠️⚠️ SANS CETTE LIGNE, LE GESTE EST ALEATOIRE SUR L'APPAREIL MEME QUE LA
     STORY NOMME — revue adverse du 06/09/2026, majeur M2.

     Le geste nominal est un glissement HORIZONTAL au doigt, telephone en main.
     Sans `touch-action`, le navigateur peut revendiquer ce geste pour son
     propre defilement et emettre `pointercancel` EN PLEINE COURSE : la piste
     retombe en retour elastique alors que la personne glissait vraiment.
     Safari iOS le fait sur l'overscroll horizontal, Chrome Android selon sa
     detection de pan.

     `pan-y` cede le defilement VERTICAL au navigateur — la colonne de commandes
     defile normalement — et garde l'horizontal pour la piste. C'est le
     decoupage exact du geste, pas une desactivation : `none` prendrait aussi le
     defilement vertical, sur un ecran qui en a besoin. */
  touch-action: pan-y;
}

/* ⚠️ IL EST DECORATIF ET IL PORTE `aria-hidden` : la course NE S'ANNONCE PAS.
   « Elle change des dizaines de fois par seconde et noierait la lecture » —
   seuls l'armement, la validation et l'echec sont annonces. */
.piste-remplissage {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--course);
  background-color: var(--color-accent-voile);
}

/* L'etat ARME — second temps de l'appui, `aria-pressed="true"`. Le voile passe
   au succes : la couleur CONFIRME, le libelle reecrit dit tout. */
.piste-glissement[aria-pressed="true"] .piste-remplissage {
  width: 100%;
  background-color: var(--color-succes-voile);
}

/* Le libelle passe DEVANT le remplissage. Tous deux sont positionnes ; celui-ci
   vient apres dans le flux, donc au-dessus, sans qu'aucun `z-index` soit du. */
.piste-libelle {
  position: relative;
}

/* -----------------------------------------------------------------------------
   LA BARRE DE POUCE DE LA LISTE DU JOUR — UX-DR39, UX-DR104. Story 4.2.
   -----------------------------------------------------------------------------
   `EXPERIENCE.md` § « **La remise au sac** | barre de pouce » : « La remise au sac | barre de pouce de la liste du jour,
   au moment de la preparation ». Ce n'est pas une quatrieme entree d'onglet —
   `UX-DR9` tient la barre a trois — c'est une action dans la barre de pouce.

   ⚠️ ELLE COLLE AU-DESSUS DE LA BARRE D'ONGLETS, JAMAIS PAR-DESSUS.
   `shared/_barre_onglets` est `fixed inset-x-0 bottom-0` et haute de
   `{spacing.cible-option}` ; une barre collee a `bottom: 0` se serait posee
   dessus, c'est-a-dire sur la navigation de toute la surface. Le decalage vaut
   donc exactement la hauteur de cette barre-la, et il se lit sur le meme jeton :
   deux mesures qui doivent rester egales ne s'ecrivent pas deux fois.

   ⚠️ TAILWIND N'EN TIRE AUCUN UTILITAIRE UTILISABLE ICI (`bottom-*` ne compose
   pas avec la position collante sans que la valeur soit ecrite quelque part) :
   la regle vit dans cette feuille, comme la largeur de colonne et le degagement
   sous pile. Aucune valeur en dur — c'est le jeton, nomme par son role.
   -------------------------------------------------------------------------- */
.barre-de-pouce-du-jour {
  position: sticky;
  bottom: var(--spacing-cible-option);
}

/* -----------------------------------------------------------------------------
   LE REGIME PAPIER — FR-062, UX-DR114, arbitrage A1 du 29/08/2026.
   -----------------------------------------------------------------------------
   « Impression / PDF est une SORTIE A PART ENTIERE, pas une capture : la liste,
   les quantites ou la tournee selon la vue courante, NOIR SUR BLANC, montants
   en monospace tabulaire, creneaux rendus par LIBELLE ET FORME, jamais par
   couleur seule. »

   ⚠️⚠️ POURQUOI CES REGLES VIVENT ICI, ET NULLE PART AILLEURS. Le contrat de
   jetons (app/assets/tailwind/application.css) est verse A L'OCTET PRES depuis
   la source UX et une garde compare les deux fichiers : un seul caractere
   ajoute la fait rougir, et AD-24 ferme le contrat. Un fichier `.css` NEUF, lui,
   ne serait lu par aucune des deux feuilles que `classes_ecrites_test` connait :
   toute classe qu'il declarerait serait reputee FANTOME. Cette feuille-ci est
   donc le seul emplacement possible — et c'est le bon : le chargement est
   global (`stylesheet_link_tag :app` sur les deux layouts, aucun chargement
   conditionnel, aucune vue n'ecrit `content_for :head`), et un `@media print`
   se borne tout seul.

   ⚠️⚠️ « NOIR SUR BLANC » DEMANDE DU TRAVAIL, ET C'EST LE PIEGE DE CET ECRAN.
   Le regime par defaut est SOMBRE (`color-scheme: dark`). A l'impression, un
   navigateur supprime les APLATS de fond par defaut mais GARDE LA COULEUR DU
   TEXTE — or plusieurs encres d'etat sont des encres SUR APLAT, donc CLAIRES.
   Sans ce bloc, on obtient du texte clair sur du blanc : illisible, et aucune
   garde du depot ne rend un media `print` pour le voir.

   ⚠️⚠️ ET LE CRENEAU DE CYCLE PERD SA SILHOUETTE, LUI SEUL. `--etat-cycle-filet`
   vaut 0px en regime sombre — arbitrage A-03 du 26/08, la SEULE entorse admise
   au contrat : la pastille de cycle n'a aucun filet, sa forme ne tient que par
   son aplat. Les creneaux 2, 3 et 4 gardent la leur (bord plein, bord gauche
   epais, bord pointille). Le regime papier est le TROISIEME cas qu'A-03 n'a pas
   traite : on rend donc le filet du creneau 1 visible ICI, en surchargeant la
   PROPRIETE `box-shadow` — SANS jamais redefinir le jeton, que le contrat
   verrouille.

   ⚠️ LES TROIS VALEURS CI-DESSOUS SONT NOMMEES ICI PARCE QUE LE CONTRAT N'A PAS
   DE REGIME PAPIER : ses deux palettes sont des regimes d'ECRAN. Meme precedent
   que `--largeur-lecture` et `--marge-libelle` — la mesure vit dans la feuille
   de composants, elle est visible, et elle est candidate a entrer au contrat.
   -------------------------------------------------------------------------- */
:root {
  --encre-papier: #000000;
  --fond-papier:  #ffffff;
  --filet-papier: 1px;
}

@media print {
  /* L'encre et le fond, d'abord — avant toute silhouette. */
  html, body {
    background-color: var(--fond-papier) !important;
    color:            var(--encre-papier) !important;
  }

  body * {
    color:            var(--encre-papier) !important;
    background-color: transparent !important;
  }

  /* Les quatre silhouettes de creneau, rendues au trait. La FORME dit la
     famille, le LIBELLE dit la valeur : aucun des deux n'est seul, et la
     couleur ne porte plus rien sur du papier. */
  .et-cycle {
    box-shadow: inset 0 0 0 var(--filet-papier) var(--encre-papier) !important;
  }
  .et-preparation,
  .et-reglement,
  .et-vide       { border-color: var(--encre-papier) !important; }
  .et-livraison  { border-left-color: var(--encre-papier) !important; }

  /* Rien ne colle a une feuille de papier, et rien n'y clignote. */
  .sticky { position: static !important; }

  /* Le retour a l'ecran est une cible : il n'a rien a faire sur la feuille. */
  .retour-ecran { display: none !important; }

  /* ⚠️⚠️ ET `.sticky` NE COUVRE PAS `position: fixed` — majeur de la revue du
     29/08, constate par execution. La barre d'onglets du gabarit
     (`shared/_barre_onglets`) est `fixed`, pas `sticky` : la regle ci-dessus ne
     la voyait pas, et un element fixe se REPETE SUR CHAQUE PAGE en media
     pagine. « Le jour · Les menus · La cuisine » se serait imprime en bas de
     chaque A4, par-dessus le contenu.

     `.hors-papier` dit la seule chose qui compte ici : cet element est une
     cible d'ECRAN, il n'existe pas sur la feuille. Il se pose sur le balisage,
     jamais devine par la feuille — on ne peut pas selectionner une propriete
     en CSS, et une liste de selecteurs devinee vieillit mal. */
  .hors-papier { display: none !important; }

  /* Le squelette non plus — il n'existe que le temps d'un chargement. */
  .squelette { display: none !important; }
}

/* -----------------------------------------------------------------------------
   LA BASCULE DE REGIME — story 5.8, D12, `UX-DR17` ; `tournee/_bascule_de_regime`.
   -----------------------------------------------------------------------------
   Deux segments en toutes lettres, chacun avec son glyphe ; le segment COURANT
   est INVERSE (`surface-inverse` / `sur-inverse`, 16,34:1 / 18,27:1 — inscrit au
   recapitulatif du contrat v1.2).

   ⚠️ L'ETAT PORTE LE STYLE : le segment courant se lit sur `aria-pressed`, et
   aucune classe ne se permute en JS — le meme attribut dit l'etat au lecteur
   d'ecran et a l'oeil, ils ne peuvent pas diverger. « Enfonce » veut dire
   ardoise (A3 (a)).

   ⚠️ `bascule-regime__*`, JAMAIS `segment-*` : ce prefixe est le vocabulaire du
   ruban d'ecart.

   ⚠️ AUCUNE `transition` SUR LES COULEURS : un fondu de theme n'est pas dans le
   contrat, et la bascule doit etre instantanee.
   -------------------------------------------------------------------------- */
.bascule-regime { padding: var(--spacing-xs); gap: var(--spacing-xs); }

.bascule-regime[aria-pressed="false"] .bascule-regime__plein-jour,
.bascule-regime[aria-pressed="true"] .bascule-regime__ardoise {
  background-color: var(--color-surface-inverse);
  color: var(--color-sur-inverse);
}

/* -----------------------------------------------------------------------------
   LE LIBELLE D'UN CRENEAU PEUT PASSER A LA LIGNE — story 5.8, `AC-12`.
   -----------------------------------------------------------------------------
   ⚠️⚠️ MESURE, PAS SUPPOSE : la tournee peuplee, a 320 px et au zoom texte de
   200 %, debordait de 98 px a l'horizontale (« Reglement : impaye »). Deux
   causes, qu'aucun banc n'avait jamais exercees sur cette surface :
     1. « Famille&nbsp;:&nbsp;valeur » ne laissait AUCUNE coupure — corrige dans
        `shared/_creneaux_d_etat` (l'espace APRES les deux-points redevient une
        espace ordinaire ; celle d'AVANT reste insecable, c'est la typographie) ;
     2. le libelle est un ELEMENT DE FLEX : sa largeur minimale est celle de son
        plus long mot (`min-width: auto`), et `overflow-wrap: break-word` du
        contrat (`.et`, §17) ne peut rien contre elle. `min-width: 0` lui rend
        son effet : le mot qui ne tient pas passe a la ligne au lieu de sortir de
        l'ecran.
   ⚠️ RIEN N'EST ROGNE : `overflow` reste `visible`, aucune hauteur n'est posee,
   et le creneau grandit avec ses lignes (`--etat-hauteur` est un MIN-HEIGHT).
   C'est la garde du contrat — « le creneau ne tronque jamais » — qui avait
   raison ; il lui manquait de pouvoir s'appliquer.
   -------------------------------------------------------------------------- */
.et > span { min-width: 0; }
