/* ============================================================
   THE NAUGHTY GOLFER — components.css
   ============================================================ */

/* ------------------------------------------------------------
   BOUTONS
   Règle : un bouton nomme toujours l'action qui va se produire.
   Jamais d'icône seule pour une action importante.
   ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--touch-min);
  padding: 0 var(--s-5);
  border-radius: var(--r-md);
  font-weight: var(--w-black);
  font-size: var(--t-base);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  transition: transform var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease);
}

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

.btn--block { width: 100%; }
.btn--xl    { min-height: var(--touch-xl); font-size: var(--t-lg); }

/* TOUS les boutons sont bâtis pareil : un aplat, un contour, un texte.
   Ce qui les distingue est l'intensité de l'aplat, jamais sa présence.

   Le vert principal garde son aplat saturé : c'est lui qui doit
   attraper le pouce. Il lui manquait seulement le contour — il était
   le seul bouton de l'app sans, ce qui le faisait ressembler à une
   autre espèce plutôt qu'au sommet d'une même famille. */
.btn--primary {
  background: var(--action);
  color: var(--action-ink);
  border: 2px solid var(--action-deep);
}

/* SUR UN FOND SOMBRE, LE CONTOUR S'INVERSE.

   Le contour du bouton est un vert plus sombre que son aplat : sur du
   craie, il le détache très bien. Sur la carte de compétition ou le
   panneau d'une partie en cours, tous deux vert-noir, l'aplat ne
   rendait plus que 2.77 de contraste avec son fond — sous le seuil de
   3 exigé pour qu'un élément d'interface se distingue — et son
   contour sombre n'aidait pas, il se fondait aussi.

   Un liseré clair rétablit la limite. Il ne s'applique QUE sur ces
   deux surfaces : ailleurs, le contour sombre reste le bon choix. */
.homecard--compet .btn--primary,
.livegame .btn--primary {
  border-color: color-mix(in srgb, var(--action) 45%, #FFFFFF);
}

.btn--pickup {
  background: var(--pickup);
  color: var(--pickup-ink);
  border: 2px solid var(--pickup-line);
}

.btn--ghost {
  background: var(--paper-raised);
  color: var(--ink);
  border: var(--border-strong);
}

/* Chemin alternatif : revenir, saisir autrement, changer de méthode.
   Même famille que le bouton principal, aplat dilué au lieu de saturé.
   Il ne concurrence pas le vert plein — il ne fait pas avancer, il
   dévie — mais il reste une action, donc il reste vert. */
.btn--alt {
  background: var(--alt-soft);
  color: var(--alt);
  border: 2px solid var(--alt-line);
}

.btn--alt:active { background: color-mix(in srgb, var(--alt-line) 16%, var(--alt-soft)); }

.btn--quiet {
  background: var(--paper-sunk);
  color: var(--ink);
  border: 2px solid var(--rule);
}

/* Même traitement que --alt : aplat dilué, contour, texte coloré.
   Le fond transparent d'avant faisait de ce bouton le seul de l'app
   sans aplat — il ne ressemblait à aucun autre. */
.btn--danger {
  background: var(--danger-soft);
  color: var(--danger);
  border: 2px solid var(--danger);
}

.btn--danger:active { background: color-mix(in srgb, var(--danger) 14%, var(--danger-soft)); }

/* Un bouton désactivé doit avoir l'air en attente, pas en panne.
   Un gris franc à la place d'un vert donne l'impression d'un autre
   bouton ; on garde donc la teinte, très diluée.

   Le contour reste, simplement neutralisé : le faire disparaître
   changerait la forme du bouton entre ses deux états, et donnerait
   l'impression qu'un autre élément a pris sa place. */
.btn[disabled] {
  background: var(--disabled);
  color: var(--disabled-ink);
  border-color: var(--disabled-ink);
  pointer-events: none;
}

/* Le libellé reste lisible : un bouton désactivé doit se lire pour
   qu'on comprenne CE QU'IL FERA une fois actif. Le référentiel
   n'impose rien ici, mais un texte fantôme en plein soleil laisse le
   parent devant un bouton dont il ignore la fonction. */
.btn--primary[disabled] {
  background: color-mix(in srgb, var(--action) 28%, var(--paper-sunk));
  color: color-mix(in srgb, var(--action-ink) 80%, var(--paper-sunk));
}

.btn--pickup[disabled] {
  background: color-mix(in srgb, var(--pickup) 40%, var(--paper-sunk));
  color: color-mix(in srgb, var(--pickup-ink) 45%, var(--paper-sunk));
}

.stepper[disabled] {
  background: var(--disabled);
  border-color: transparent;
  color: var(--disabled-ink);
  opacity: 1;
}

/* Les gros −/+ du compteur. Carrés, atteignables au pouce.

   64 px et non 76 : voir le calcul dans .player. Ces douze pixels
   par carte, multipliés par deux joueurs, sont une partie de ce qui
   permet de les voir tous les deux sur un iPhone 13.

   64 reste très au-dessus de --touch-min, la cible tactile minimale
   de 56 px. Ce sont toujours les plus gros boutons de
   l'application — et de loin les plus utilisés : quatre-vingts appuis
   dans une partie de dix-huit trous. */
.stepper {
  width: 64px;
  height: 64px;
  flex: 0 0 auto;
  border-radius: var(--r-md);
  background: var(--count);
  border: none;
  color: var(--count-ink);
  font-weight: var(--w-black);
  font-size: var(--t-2xl);
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--dur-fast) var(--ease);
}

.stepper:active { transform: scale(0.92); }
.stepper[disabled] { pointer-events: none; }

/* ------------------------------------------------------------
   DRAPEAU DE TYPE DE PARTIE
   ------------------------------------------------------------ */

/* Étiquette COMPÉTITION. Le noir d'encre employé ici était à 148°,
   hors de la famille verte : le même défaut que les onglets. */
.flag {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--s-2);
  border-radius: var(--r-sm);
  background: var(--action-deep);
  color: #FFFFFF;
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.notice {
  background: var(--pickup-bg);
  border: 1.5px solid var(--pickup-line);
  border-radius: var(--r-lg);
  padding: var(--s-4);
}

/* ------------------------------------------------------------
   ACTION DESTRUCTIVE DISCRÈTE
   Un lien, pas un bouton : abandonner une partie ne doit jamais
   être aussi facile à toucher que la reprendre.
   ------------------------------------------------------------ */

.linkbtn {
  display: block;
  width: 100%;
  margin-top: var(--s-3);
  padding: var(--s-2);
  min-height: 44px;
  font-size: var(--t-sm);
  color: var(--ink-soft);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.linkbtn:active { color: var(--danger); }

/* Variante destructive : ce lien jette un travail qui ne se
   récupère qu'en refaisant la photo. Un lien gris au milieu d'une
   page se clique par curiosité — celui-ci doit se voir avant, pas
   se regretter après. La couleur prévient, la boîte confirme. */
.linkbtn--danger {
  color: var(--danger);
  font-weight: var(--w-semi);
}

/* ------------------------------------------------------------
   REPÈRES DE DÉPART
   La couleur EST l'information : c'est ainsi qu'on les désigne sur
   un parcours (« il part des oranges »). Le libellé reste accessible
   aux lecteurs d'écran.
   ------------------------------------------------------------ */

.tees {
  display: flex;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin-top: var(--s-2);
}

.tee {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
  border: 2px solid var(--rule);
  background: var(--paper-raised);
  color: var(--ink-faint);
  font-weight: var(--w-black);
  font-size: var(--t-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--dur-fast) var(--ease);
}

.tee:active { transform: scale(0.92); }

.tee--on {
  background: var(--tee-color);
  color: var(--tee-ink);
  border-color: var(--ink);
}

/* Version compacte, affichée à côté du nom pendant le scoring. */
.tee--sm {
  width: 30px;
  height: 30px;
  font-size: var(--t-xs);
  border-width: 1.5px;
}

/* Version point, dans la colonne des noms de la carte de score.
   Aucune lettre : à cette taille elle est illisible, et la couleur
   porte déjà l'information — c'est la règle du sélecteur de repères.
   inline-block et non flex : en display:flex l'élément est de niveau
   bloc et passe sous le prénom. */
.tee--dot {
  display: inline-block;
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
  border-width: 2px;
  border-radius: var(--r-pill);
  transition: none;
}

.tee--dot:active { transform: none; }

.player-row {
  padding-bottom: var(--s-3);
  border-bottom: var(--border);
}

.player-row:last-child { border-bottom: none; padding-bottom: 0; }

/* ------------------------------------------------------------
   CHAMP AVEC LIBELLÉ
   ------------------------------------------------------------ */

.field {
  display: block;
}

.field__label {
  display: block;
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: var(--s-2);
}

/* ------------------------------------------------------------
   BANDEAU DU TROU EN COURS
   ------------------------------------------------------------ */

/* La barre du trou respire au-dessus : sans cet écart, le badge
   COMPÉTITION se retrouvait collé aux flèches de navigation, deux
   éléments qui n'ont rien à voir l'un avec l'autre.

   flex-wrap est une SÉCURITÉ, pas une intention : « Trou 18 » avec
   ses deux badges et les deux flèches demande 341 px, et un iPhone SE
   n'en offre que 288. Plutôt que d'écraser le contenu, la ligne passe
   à deux niveaux — les flèches descendent à droite. */
.hole-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
  margin-top: var(--s-4);
}

.hole-bar > .row {
  gap: var(--s-2);
  min-width: 0;
}

.hole-bar__nav { margin-left: auto; }

/* Le titre reste l'élément dominant de la ligne — Archivo Black, en
   encre pleine — mais à 20 px et non 36. À sa taille d'origine, il
   poussait les deux badges et les flèches hors de l'écran sur tout
   téléphone plus étroit qu'un grand format. */
.hole-bar__no {
  font-weight: var(--w-black);
  font-size: var(--t-lg);
  white-space: nowrap;
  letter-spacing: var(--track-tight);
}

/* Archivo comme tout l'en-tête, pas la monospace de la carte.

   La monospace existe pour que les colonnes de chiffres s'alignent
   dans le tableau de score. Dans un badge isolé, elle n'aligne rien
   et se contente de jurer à côté du reste. La variante tabulaire
   garde des chiffres de largeur égale, ce qui évite que le badge
   change de taille entre « Par 3 » et « Par 5 ». */
/* Même taille que les chiffres du tableau, et sans gras : ce sont
   deux informations de référence, pas des titres. Elles renseignent
   le trou, elles ne l'annoncent pas — c'est le rôle de « Trou 3 ».

   Largeur commune calée sur la plus longue, « Index 11 » à deux
   chiffres : deux pastilles voisines de tailles différentes accrochent
   l'œil sur leur différence plutôt que sur leur contenu. */
.hole-bar__par,
.hole-bar__hcp {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 62px;
  min-height: 34px;
  font-weight: var(--w-regular);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-xs);
  color: var(--ink-soft);
  padding: 0 var(--s-3);
  border: var(--border);
  border-radius: var(--r-pill);
  background: var(--paper-raised);
}

.hole-bar__nav { display: flex; gap: var(--s-2); }

/* 44 px comme Retour et Comprendre : ces flèches changent de trou,
   c'est fréquent mais ce n'est pas l'action principale de l'écran —
   le compteur l'est. À 56 px elles pesaient autant que lui. */
.hole-nav {
  width: 40px;
  height: 40px;
  border-radius: var(--r-md);
  border: var(--border);
  background: var(--paper-raised);
  font-size: var(--t-lg);
  display: flex;
  align-items: center;
  justify-content: center;
}

.hole-nav[disabled] { opacity: 0.3; pointer-events: none; }

/* ------------------------------------------------------------
   LIGNE JOUEUR — le cœur de l'écran de scoring
   Trois états : en saisie / validé / ramassé.
   Chaque joueur est indépendant des autres.
   ------------------------------------------------------------ */

/* DEUX JOUEURS À L'ÉCRAN, C'EST LA CONTRAINTE QUI FIXE CES VALEURS.

   Objectif mesuré : sur un iPhone 13 dans Safari, la zone qui défile
   offre 425 px. Deux cartes plus leur écart doivent donc tenir en
   425 — soit 206 px par carte. Elles en faisaient 248.

   Décomposition de la carte d'origine, mesurée :
       rembourrage      2 x 16
       nom du joueur        22
       compteur - 0 +       76   (+ 16 d'écart)
       consigne             20   (+  8 d'écart)
       Valider / Ramassé    56   (+ 16 d'écart)
       ————————————————   ————
       total               248

   Ce qui est rogné, et ce qui ne l'est pas :
     - le rembourrage passe de 16 à 12, les écarts de 16 à 12 ;
     - les boutons − et + descendent de 76 à 64 px ;
     - la consigne disparaît des cartes SUIVANTES, jamais de la
       première.

   Ce qui ne bouge pas : Valider et Ramassé restent à 56 px, la cible
   tactile minimale de l'application. On compte des coups en marchant,
   parfois avec des gants — descendre en dessous ferait rater des
   appuis, et un appui raté sur Valider coûte plus cher que deux
   joueurs visibles. */
.player {
  background: var(--paper-raised);
  border: var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-3);
  box-shadow: var(--shadow-raised);
}

/* La consigne est la même pour tous les joueurs. Une fois suffit. */
.player__hint {
  text-align: center;
  font-size: var(--t-sm);
  margin-top: var(--s-1);
}

.player ~ .player .player__hint { display: none; }

.player + .player { margin-top: var(--s-3); }

/* Trou verrouillé : un trou antérieur n'est pas validé. Contour
   pointillé et fond en retrait — c'est un état d'attente, pas une
   erreur, donc ni rouge ni alarme. */
.player--locked {
  background: var(--paper);
  border: 2px dashed var(--rule);
  box-shadow: none;
  text-align: center;
}

.player__name {
  font-weight: var(--w-black);
  font-size: var(--t-lg);
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
}

/* --- État : en saisie --- */

.player__counter {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: var(--s-3);
}

.player__strokes {
  font-weight: var(--w-black);
  font-size: var(--t-score);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  flex: 1;
  text-align: center;
}

.player__actions {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.player__actions .btn { flex: 1; }

/* --- État : validé (ligne compactée, score + MODIFIER visibles) --- */

.player--done {
  background: var(--action-soft);
  border-color: var(--action);
}

.player--pickedup {
  background: var(--pickup-bg);
  border-color: var(--pickup-line);
}

.player__done-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}

.player__done-score {
  font-weight: var(--w-black);
  font-size: var(--t-xl);
  font-variant-numeric: tabular-nums;
}

.player__tag {
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--pickup-ink);
}

/* ------------------------------------------------------------
   NOTATION GOLF — élément signature
   Rond = sous le par. Carré = au-dessus. Convention des vraies
   cartes ; c'est aussi ce qui apprend la lecture au parent.
   ------------------------------------------------------------ */

.mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.1em;
  height: 2.1em;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  line-height: 1;

  /* Couleur de l'anneau de séparation des marques doubles. Elle doit
     valoir le fond de la cellule, sinon le double cercle se détache
     sur un halo blanc au-dessus du trou en cours. */
  --mark-halo: var(--paper-raised);
}

/* Birdie et mieux : cercle rouge. Eagle : double cercle. */
.mark--under {
  color: var(--under-par);
  border: 2px solid var(--under-par);
  border-radius: var(--r-pill);
}

.mark--under-2 {
  color: var(--under-par);
  border: 2px solid var(--under-par);
  border-radius: var(--r-pill);
  box-shadow: 0 0 0 2px var(--mark-halo), 0 0 0 4px var(--under-par);
}

/* Albatros : trois cercles. Le score le plus rare du golf — un 2 sur
   un par 5, un ace sur un par 4 — et la carte le dit en ajoutant un
   anneau, pas en changeant de forme. */
.mark--under-3 {
  color: var(--under-par);
  border: 2px solid var(--under-par);
  border-radius: var(--r-pill);
  box-shadow:
    0 0 0 2px var(--mark-halo), 0 0 0 4px var(--under-par),
    0 0 0 6px var(--mark-halo), 0 0 0 8px var(--under-par);
}

/* Bogey et pire : carré encre. Double bogey : double carré. */
.mark--over {
  color: var(--over-par);
  border: 2px solid var(--over-par);
  border-radius: 2px;
}

.mark--over-2 {
  color: var(--over-par);
  border: 2px solid var(--over-par);
  border-radius: 2px;
  box-shadow: 0 0 0 2px var(--mark-halo), 0 0 0 4px var(--over-par);
}

/* Triple bogey ou pire : trois carrés. Même logique que les cercles,
   dans l'autre sens. */
.mark--over-3 {
  color: var(--over-par);
  border: 2px solid var(--over-par);
  border-radius: 2px;
  box-shadow:
    0 0 0 2px var(--mark-halo), 0 0 0 4px var(--over-par),
    0 0 0 6px var(--mark-halo), 0 0 0 8px var(--over-par);
}

/* Par : rien. C'est la référence, elle ne se signale pas. */
.mark--par { color: var(--ink); }

.mark--pickup {
  color: var(--pickup-ink);
  border: 2px dashed var(--pickup-line);
  border-radius: 2px;
}

.mark--empty { color: var(--ink-faint); }

/* ------------------------------------------------------------
   CARTE DE SCORE
   ------------------------------------------------------------ */

.card-wrap {
  overflow-x: auto;
  border: var(--border-strong);
  border-radius: var(--r-md);
  background: var(--paper-raised);
}

.card {
  font-size: var(--t-sm);
  min-width: max-content;
}

.card th,
.card td {
  border: 1px solid var(--rule);
  padding: var(--s-2);
  text-align: center;
  white-space: nowrap;
}

.card thead th {
  background: var(--paper-sunk);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

/* Colonne des noms : figée au scroll horizontal. */
.card th[scope="row"] {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--paper-raised);
  text-align: left;
  font-weight: var(--w-semi);
  border-right: var(--border-strong);
  min-width: 88px;
}

.card .col-total {
  background: var(--paper-sunk);
  font-weight: 500;
}

.card .cell-current { background: color-mix(in srgb, var(--brand) 22%, transparent); }

/* ------------------------------------------------------------
   AIDE AUX PARENTS
   La raison d'être du produit : expliquer sans quitter l'écran.
   ------------------------------------------------------------ */

/* Même forme et même hauteur que le bouton Retour, en face duquel il
   se trouve. Deux boutons de tailles et de formes différentes aux
   deux bouts d'une même ligne se lisent comme deux éléments sans
   rapport. */
.help-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 44px;
  padding: 0 var(--s-3);
  border-radius: var(--r-md);
  border: var(--border);
  background: var(--paper-raised);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink);
}

.help-btn__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--r-pill);
  background: var(--action-deep);
  color: #FFFFFF;
  font-weight: var(--w-black);
  font-size: var(--t-xs);
}

.sheet-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(20, 38, 28, 0.45);
  z-index: 50;
}

/* Sur grand écran, la feuille reste dans la colonne : posée sur
   toute la largeur de la fenêtre, elle sortait du téléphone qu'on
   regarde et cassait l'illusion. */
.sheet {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 480px;
  bottom: 0;
  z-index: 51;
  background: var(--paper-raised);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: var(--shadow-sheet);
  padding: var(--s-5) var(--s-4) calc(var(--s-5) + env(safe-area-inset-bottom));
  max-height: 82dvh;
  overflow-y: auto;
  animation: sheet-in var(--dur-base) var(--ease);
}

/* LE BOUTON DE FERMETURE RESPIRE.

   Il touchait littéralement l'élément au-dessus — écart mesuré à
   zéro. J'ai d'abord espacé TOUS les enfants de la feuille, avant de
   voir que l'écran de comptage en a trois autres, où titre, texte et
   champs se seraient retrouvés à vingt-quatre pixels les uns des
   autres. Une règle globale posée pour un cas particulier casse les
   cas qu'on n'a pas regardés.

   La marge ne porte donc que sur le dernier bouton de la feuille,
   quel que soit son contenu au-dessus. */
.sheet > .btn:last-child { margin-top: var(--s-5); }

/* L'animation doit conserver le centrage horizontal : sans le
   translateX, la feuille sautait à gauche le temps de l'apparition. */
@keyframes sheet-in {
  from { transform: translate(-50%, 12px); opacity: 0; }
  to   { transform: translate(-50%, 0);    opacity: 1; }
}

.sheet__grip {
  width: 40px;
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--rule);
  margin: 0 auto var(--s-4);
}

.sheet h3 { margin-bottom: var(--s-2); }
.sheet p  { margin-bottom: var(--s-3); color: var(--ink-soft); }
.sheet p:last-of-type { margin-bottom: var(--s-5); }

/* ------------------------------------------------------------
   LOGO
   ------------------------------------------------------------ */

.brandmark {
  display: block;
  width: 176px;
  max-width: 52%;
  height: auto;
}

/* Repli texte, aux couleurs du logo, si l'image ne charge pas. */
.wordmark {
  font-weight: var(--w-black);
  font-size: var(--t-2xl);
  letter-spacing: var(--track-tight);
  line-height: 1;
}

.wordmark__a { color: var(--ink); }
.wordmark__b { color: var(--brand); }

/* ------------------------------------------------------------
   SIGNATURE DE MARQUE
   Mention d'éditeur, pas une publicité. Aucun lien tant que la
   boutique n'existe pas : on ne promet rien qu'on ne peut tenir.
   ------------------------------------------------------------ */

.signature {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-4) 0 var(--s-2);
  text-align: center;
}

.signature__text {
  font-size: var(--t-xs);
  color: var(--ink-faint);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.signature__brand {
  font-weight: var(--w-black);
  color: var(--ink-soft);
}

.signature__motto {
  display: block;
  margin-top: var(--s-1);
  font-size: var(--t-xs);
  color: var(--ink-faint);
  letter-spacing: var(--track-wide);
  text-transform: none;
  font-style: italic;
}

/* ------------------------------------------------------------
   ÉTATS VIDES
   Un écran vide est une invitation à agir, pas une excuse.
   ------------------------------------------------------------ */

.empty {
  text-align: center;
  padding: var(--s-7) var(--s-4);
}

.empty h2 { margin-bottom: var(--s-2); }
.empty p  { color: var(--ink-soft); margin-bottom: var(--s-5); }


/* ------------------------------------------------------------
   ACCUEIL
   ------------------------------------------------------------ */

.greeting { padding: var(--s-5) 0 var(--s-2); }

.greeting h1 {
  font-size: var(--t-2xl);
  margin-bottom: var(--s-3);
}

.greeting__lead {
  color: var(--ink-soft);
  font-size: var(--t-lg);
  line-height: 1.4;
}

/* Variante centrée de l'accueil.

   Trois lignes courtes le supportent, et la page respire. Le
   centrage s'arrête là : les paragraphes des cartes en dessous
   restent alignés à gauche. Un texte de quatre lignes centré
   oblige l'œil à retrouver le début de chaque ligne — inutile sur
   un écran de bureau, pénible au soleil sur un parcours.

   La largeur est bornée pour que les lignes se coupent où elles
   doivent : centré et pleine largeur, un texte produit une ligne
   longue suivie d'un mot isolé. */
.greeting--center {
  text-align: center;
}

/* LE « BONJOUR » EST VERT.

   Trois verts de la palette ont été rendus et mesurés sur le fond
   craie, à la taille réelle du titre :

     --brand      #97C02E   contraste 1.90   le vert du mot « caddy »
     --aide-par   #6BA13C   contraste 2.77
     --action     #606D3C   contraste 5.01
     --action-deep #4F631D  contraste 5.99

   Les deux premiers sont hors jeu : sous 3, un texte devient un
   lavis dès qu'il y a du soleil, et cette application se lit dehors
   à midi. Le vert du logo était le candidat naturel — il ne tient
   pas sur ce fond-là.

   --action-deep, donc : même teinte que le logo à 77°, simplement
   assez sombre pour rester lisible. La règle ne porte que sur la
   variante centrée : l'écran de fin de partie utilise le même bloc
   et garde son titre en encre. */
.greeting--center h1 { color: var(--action-deep); }

/* PLUS D'AIR SOUS « BONJOUR ».

   Douze pixels séparaient un titre de 36 px de sa question. À cette
   échelle, douze pixels ne se lisent pas comme un intervalle mais
   comme un accident : les deux lignes se touchaient presque, alors
   que ce sont deux choses différentes — une salutation, puis une
   question.

   Vingt-quatre, soit la hauteur d'une ligne du titre. La règle ne
   porte que sur la variante centrée : l'écran de fin de partie
   utilise le même bloc avec un titre plus court, où l'intervalle
   d'origine convient. */
/* 16 px, et non 24. C'ÉTAIT LE DERNIER OBSTACLE.

   Mesuré avec la vraie police et les encoches de l'iPhone 13 en app
   installée : l'accueil débordait de 22 px. Vingt-deux pixels, c'est
   le pire des cas — trop peu pour qu'un pouce sente qu'il y a
   quelque chose à faire glisser, assez pour couper le bas des deux
   boutons. C'est exactement le défaut corrigé ce matin, revenu par
   une autre porte.

   Huit pixels viennent d'ici, huit du bloc en dessous, et l'écart
   entre les deux blocs fournit les six derniers. Le titre garde de
   l'air : seize pixels sous un titre de quarante restent un
   intervalle franc, pas un accident. */
.greeting--center h1 { margin-bottom: var(--s-4); }
.greeting--center .greeting__lead {
  max-width: 34ch;
  margin-left: auto;
  margin-right: auto;
}
.greeting--center .greeting__lead + .greeting__lead {
  margin-top: var(--s-3);
}

.lead {
  color: var(--ink-soft);
  font-size: var(--t-lg);
  line-height: 1.4;
}

/* ------------------------------------------------------------
   PHOTO DE LA CARTE
   ------------------------------------------------------------ */

.shot {
  display: block;
  width: 100%;
  border-radius: var(--r-lg);
  border: var(--border);
  background: var(--paper-raised);
}

/* LA ZONE EST UN BOUTON, ELLE DOIT DONC SE COMPORTER COMME TEL.

   Le cadre en pointillés a toujours ressemblé à une zone d'accueil —
   c'est ce qui a fait cliquer dessus quelqu'un qui découvrait l'app.
   Il en est un maintenant, et il en porte les marques : cible
   tactile, retour au doigt, contour de focus.

   L'appel tient en deux lignes, verbe d'abord. « Aucune photo pour le
   moment » décrivait un état ; « Ajouter la photo de la carte » dit
   quoi faire. Un cadre vide n'a pas besoin qu'on lui dise qu'il est
   vide, ça se voit. */
.shot--empty {
  aspect-ratio: 3 / 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  border-style: dashed;
  border-color: var(--alt-line);
  color: var(--alt);
  background: var(--alt-soft);
  cursor: pointer;
  text-align: center;
  padding: var(--s-4);
  transition: background var(--dur-fast) var(--ease);
}

.shot--empty:active { background: var(--paper-sunk); }

.shot__marque { display: flex; }
.shot__marque svg { width: 40px; height: 40px; display: block; }

.shot__appel {
  font-weight: var(--w-semi);
  font-size: var(--t-base);
  color: var(--alt);
}

.shot__sous {
  font-size: var(--t-sm);
  color: var(--ink-soft);
}

/* Une photo posée ne dit pas d'elle-même qu'on peut la remplacer.
   L'étiquette le dit, en bas à droite, sans masquer la carte. */
.shot--rempli {
  position: relative;
  padding: 0;
  overflow: hidden;
  cursor: pointer;
}

.shot--rempli img {
  display: block;
  width: 100%;
}

.shot__reprendre {
  position: absolute;
  right: var(--s-2);
  bottom: var(--s-2);
  padding: var(--s-1) var(--s-3);
  border-radius: var(--r-pill);
  background: var(--action-deep);
  color: var(--action-ink);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

/* ------------------------------------------------------------
   DEUX ACTIONS CÔTE À CÔTE — PIED D'ÉCRAN

   Empilés en pleine largeur, deux boutons prennent le tiers bas de
   l'écran et repoussent le contenu sous le pli. Côte à côte, ils
   rendent cette hauteur à ce qui compte.

   `flex: 1 1 0` et non `flex: 1` : sans la base à zéro, le bouton au
   libellé le plus long se taille plus large que l'autre, et deux
   boutons de largeurs différentes se lisent comme deux niveaux
   d'importance alors que la hiérarchie doit passer par la couleur.

   LA TYPOGRAPHIE CHANGE AVEC LA LARGEUR, ET C'EST OBLIGATOIRE.

   Ces libellés étaient écrits pour la pleine largeur : capitales,
   0.08em d'interlettrage, et parfois --t-lg. À la moitié de la
   place, « COMMENCER LA PARTIE » et « CONTINUER À JOUER » se
   coupaient en plein mot. Même remède que dans les dialogues, où le
   problème est le même : 14 px, 0.04em, rembourrage à 8 px.

   La règle annule aussi btn--xl à l'intérieur de la rangée : un
   bouton ne peut pas être à la fois deux fois plus gros et deux fois
   plus étroit.
   ------------------------------------------------------------ */
.row--actions {
  gap: var(--s-2);
  align-items: stretch;
}

.row--actions > .btn,
.row--actions > .btn.btn--xl {
  font-size: var(--t-sm);
  letter-spacing: 0.04em;
  padding-left: var(--s-2);
  padding-right: var(--s-2);
}

.row--actions > .btn {
  flex: 1 1 0;
  min-width: 0;
}

/* Réserve de hauteur propre à l'écran de la carte, où le bouton
   d'analyse accueille une animation. Ailleurs, deux boutons de texte
   n'ont aucune raison de faire 84 px de haut. */
.row--attente > .btn {
  /* HAUTEUR RÉSERVÉE D'AVANCE.

     Le bouton d'analyse grandit quand l'animation s'y installe. S'il
     partait de la hauteur minimale, tout le pied d'écran sauterait
     au moment où l'analyse démarre — pile au moment où l'utilisateur
     regarde ce bouton pour savoir si son geste a été pris.

     Les deux boutons partent donc déjà à la hauteur qu'occupera le
     plus grand. Rien ne bouge, ni au départ ni à l'arrivée.

     84 et non 76 : la réserve calculée laissait encore cinq pixels
     de saut au rendu, sur le message le plus long — « Lecture des
     index de difficulté… », le seul du lot à passer sur deux lignes.
     C'est la mesure qui fixe ce nombre, pas l'addition. */
  min-height: 84px;
}

.tips__list {
  list-style: none;
  margin-top: var(--s-2);
}

.tips__list li {
  position: relative;
  padding-left: var(--s-4);
  margin-bottom: var(--s-2);
  color: var(--ink-soft);
  font-size: var(--t-sm);
}

.tips__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 6px;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--action-deep);
}

/* ------------------------------------------------------------
   CHAMPS DEVINÉS PAR LA LECTURE DE CARTE
   Le manuscrit est presque toujours incertain : on le signale
   au lieu de le présenter comme un fait acquis.
   ------------------------------------------------------------ */

.input--guessed {
  border-color: var(--pickup-line);
  background: var(--pickup-bg);
}

.guessed-note {
  margin-top: var(--s-1);
  font-size: var(--t-xs);
  color: var(--pickup-ink);
  font-weight: var(--w-semi);
}


/* ------------------------------------------------------------
   CODE DE VÉRIFICATION
   Gros, espacé, chiffres seulement : on le recopie depuis un
   email, souvent d'une main, parfois en plein soleil.
   ------------------------------------------------------------ */

.code-input {
  font-size: var(--t-2xl);
  letter-spacing: 0.35em;
  text-align: center;
  min-height: var(--touch-xl);
}


/* ------------------------------------------------------------
   CARTE DE SCORE PERMANENTE

   Toujours visible pendant le jeu, entre l'en-tête du trou et le
   compteur. Elle défile horizontalement et se recentre seule sur
   le trou en cours. Volontairement compacte : chaque pixel pris
   ici est un pixel de moins pour les gros boutons.
   ------------------------------------------------------------ */

/* LE TABLEAU EST DANS LE CORPS QUI DÉFILE, PAS À CÔTÉ.

   Il était une bande fixe entre l'en-tête et le corps. Voir le
   commentaire de view-play.js pour les chiffres : à eux quatre, les
   blocs fixes occupaient 89 % d'un iPhone 13 en Safari et ne
   laissaient que 75 px au compteur.

   `margin` négative et non `padding` retiré : le corps porte son
   rembourrage de 16 px, et le tableau doit le déborder pour toucher
   les deux bords, comme il le faisait quand il vivait dehors. Un
   tableau de score encadré de blanc se lit comme une carte parmi
   d'autres ; pleine largeur, il se lit comme la carte de score. */
.board {
  flex: 0 0 auto;
  /* MARGE NÉGATIVE À GAUCHE ET À DROITE SEULEMENT.

     Elle l'était aussi EN HAUT, pour annuler le rembourrage du corps
     du temps où le tableau en était le premier élément. Depuis que le
     nom du parcours passe avant lui, cette marge le tirait par-dessus
     et mangeait la ligne « Barbaroux · Compétition ».

     Une marge négative verticale n'annule un rembourrage que si rien
     ne la précède. Celle-ci dépendait donc d'un ordre qui a changé —
     exactement le genre de règle qui casse en silence. Les marges
     horizontales, elles, ne dépendent de rien : le tableau touche les
     deux bords quelle que soit sa place. */
  margin: var(--s-3) calc(var(--s-4) * -1) var(--s-4);
  overflow-x: auto;
  overflow-y: hidden;
  background: var(--paper-raised);
  border-bottom: var(--border-strong);

  /* Même retrait qu'au corps d'écran, voir base.css : la couche
     native d'iOS dessinait son propre indicateur horizontal
     par-dessus le tableau, insensible au masquage. Et ici le défaut
     était pire, parce que ce tableau est LUI-MÊME dans une zone qui
     défile : deux indicateurs natifs se croisaient. */
  scrollbar-width: none;
}

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

.board__table {
  border-collapse: collapse;
  min-width: max-content;
  font-size: var(--t-xs);
}

/* ------------------------------------------------------------
   RÈGLE UNIQUE DU TABLEAU DE SCORE

   Tout chiffre du tableau se lit à la MÊME taille : les pars, les
   index de difficulté, les scores, les sous-totaux et les totaux.

   Auparavant chaque famille avait la sienne — 10 px pour les
   distances, 12 pour les pars et les scores, 16 hérités du corps pour
   les totaux. Le tableau se lisait comme quatre tableaux empilés.

   Une seule déclaration ici, et tout ce qui vit dans .board__table en
   hérite. Les exceptions doivent désormais être explicites, donc
   visibles, donc justifiées. */
.board__table {
  font-size: var(--t-xs);
}

.board__table th,
.board__table td {
  border: 1px solid var(--rule);
  text-align: center;
  padding: 2px 0;
  font-size: inherit;
}

/* Colonne des prénoms figée au scroll horizontal.
   La cellule reste une VRAIE cellule de tableau : lui donner
   display:flex la sort du layout table, elle cesse alors de s'aligner
   avec l'en-tête et le contenu des colonnes scrollées passe par-dessus.
   La mise en ligne se fait donc dans un conteneur interne. */
.board__name {
  position: sticky;
  left: 0;
  z-index: 3;
  width: 88px;
  min-width: 88px;
  max-width: 88px;
  background: var(--paper-raised);
  border-right: var(--border-strong) !important;
  font-weight: var(--w-semi);
  font-size: var(--t-xs);
  text-align: left;
  padding: 2px var(--s-2) !important;

  /* CASSE DE LA COLONNE — une seule déclaration pour ses six lignes.

     Elle vivait auparavant sur .board__parrow et .board__hcprow
     uniquement : PAR et HP étaient capitalisés, les prénoms, la ligne
     net et les distances ne l'étaient pas. Quatre traitements
     typographiques dans une seule colonne.

     Ce n'est pas qu'une affaire d'homogénéité. En casse mixte, la
     hauteur d'encre d'un mot dépend de ses lettres : « Elijah » porte
     quatre jambages hauts et un bas, « Luca » aucun. À taille de
     police STRICTEMENT identique, le premier occupe 21 px de haut et
     le second 16 — trente pour cent d'écart, et l'œil conclut à deux
     tailles différentes. En capitales, toutes les lettres partagent
     une seule hauteur et l'illusion disparaît.

     Tracking à 0.02em et non --track-wide (0.08em) : cette valeur-là
     est calibrée pour des libellés de deux ou trois lettres. Sur un
     prénom de huit, elle coûte 8 px dans une colonne qui n'en offre
     que 51 au texte — voir le calcul sur .board__namewrap. */
  text-transform: uppercase;
  letter-spacing: 0.02em;

  white-space: nowrap;
  overflow: hidden;
}

/* Gouttière à --s-1 et non --s-2.

   Budget réel de la colonne, calculé et non estimé :
     88 px de large
     − 16 px de padding (--s-2 de chaque côté)
     − 13 px de pastille de repère (.tee--dot)
     −  4 px de gouttière
     = 55 px pour le prénom

   Avec 8 px de gouttière, il n'en restait que 51, et un prénom en
   capitales passait tout juste. Huit pixels entre un prénom et une
   pastille de treize, dans une colonne de quatre-vingt-huit, sont de
   toute façon disproportionnés.

   Les lignes joueurs affichent en plus la pastille de rôle
   (.rolemini--xs, 16 px + 3 px de marge) hors mode Chouette : le
   prénom tombe alors à 36 px et se tronque proprement par les points
   de suspension définis ci-dessous. */
.board__namewrap {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  min-width: 0;
}

/* Le prénom occupe toute la place disponible : la pastille est ainsi
   poussée contre le filet de droite, à la même abscisse sur chaque
   ligne. Sans cela, elle suit la longueur du prénom et les repères
   dansent d'une ligne à l'autre. */
.board__namewrap > span:not([class]) {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.board__hole {
  min-width: 42px;
  background: var(--paper-sunk);
  font-weight: var(--w-semi);
  color: var(--ink-soft);
}

.board__hole--now,
.board__cell--now {
  background: color-mix(in srgb, var(--brand) 22%, transparent);
  box-shadow: inset 0 -2px 0 var(--action-deep);
}

/* 42px : la marque fait 20.4px, et l'albatros ajoute TROIS anneaux
   qui débordent de 8px de chaque côté, plus 2px de padding — soit
   40.4px. En dessous, le troisième cercle mord sur la colonne
   voisine. Le score est rarissime, mais le tableau doit pouvoir
   l'afficher le jour où il tombe. */
.board__cell { min-width: 42px; }

/* Les marques doubles (eagle, double bogey) dessinent un anneau qui
   déborde de 4px au-delà de l'élément, via box-shadow. Sans ce padding
   vertical, l'anneau sort de la cellule et chevauche les filets. */
.board__table td.board__cell {
  padding: 10px 2px;
}

.board__cell .mark {
  min-width: 1.7em;
  height: 1.7em;
  font-size: var(--t-xs);
  border-width: 1.5px;
}

/* Le halo des marques doubles suit le fond du trou en cours, sinon
   un anneau blanc tranche au milieu de la colonne verte. */
.board__cell--now .mark {
  --mark-halo: #EDF3E1;
}

.board__tot {
  position: sticky;
  right: 0;
  z-index: 2;
  min-width: 38px;
  background: var(--paper-sunk);
  border-left: var(--border-strong) !important;
  font-weight: 500;
}

/* Sous-total de l'aller, en 18 trous. Volontairement PAS sticky :
   deux colonnes collées au bord droit se superposeraient. La barre
   épaisse est à droite et non à gauche, parce que l'aller clôt la
   première moitié — il appartient aux trous 1 à 9. */
.board__out {
  min-width: 38px;
  background: var(--paper-sunk);
  border-right: var(--border-strong) !important;
  font-weight: 500;
}

/* Sous-total du retour. Pas de barre épaisse à droite : celle de la
   colonne Tot, juste après, sépare déjà les deux — en doubler une
   seconde donnerait un trait deux fois trop gras. */
.board__in {
  min-width: 38px;
  background: var(--paper-sunk);
  font-weight: 500;
}

/* Index de difficulté du trou, à côté du par. */
/* Même traitement que le badge Par, dont il est le voisin immédiat.
   Il portait la classe .num, donc la monospace, par héritage. */
/* Le style des deux badges est défini plus haut, en une seule règle :
   ils sont identiques par construction, et non par duplication. */


/* ------------------------------------------------------------
   BADGE DE PAR CLIQUABLE
   Tant que le par est inconnu, le badge appelle l'action au lieu
   de constater un manque.
   ------------------------------------------------------------ */

.hole-bar__par {
  min-height: 34px;
  cursor: pointer;
}

.hole-bar__par--ask {
  border-color: var(--pickup-line);
  color: var(--pickup-ink);
  font-weight: var(--w-semi);
}

/* Pas d'état « --set ».

   Le badge Par portait ici color: var(--ink) quand le par était connu,
   alors que son jumeau HP reste en --ink-soft. Deux pastilles de forme
   identique, côte à côte, dans deux couleurs : l'œil en déduit que
   l'une compte plus que l'autre. Elle ne compte pas plus — la règle
   mère dit d'ailleurs explicitement que ce sont deux informations de
   référence, jumelles par construction.

   La seule distinction qui mérite une couleur est --ask ci-dessus :
   ambre tant que le par n'est pas renseigné, parce qu'il y a une
   action à faire. Une fois renseigné, le badge redevient une donnée
   comme HP. */


/* ------------------------------------------------------------
   LIGNE DE SCORE DANS L'HISTORIQUE
   Prénom à gauche, écart au par au milieu, total à droite :
   trois colonnes alignées pour comparer les joueurs d'un coup d'œil.
   ------------------------------------------------------------ */

.scoreline {
  list-style: none;
  margin-top: var(--s-3);
  border-top: var(--border);
  padding-top: var(--s-2);
}

/* Colonnes de largeur fixe : « +15 » et « +9 » n'ont pas la même
   largeur naturelle, et une grille en auto ferait danser le total
   d'une ligne à l'autre. */
.scoreline__row {
  display: grid;
  grid-template-columns: 1fr 3.5em 2.5em;
  align-items: baseline;
  gap: var(--s-3);
  padding: var(--s-1) 0;
}

.scoreline__name {
  font-weight: var(--w-semi);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Deux lignes : la date, puis la compétition ou le parcours. */
.scoreline__name--stacked {
  white-space: normal;
  min-width: 0;
}

.scoreline__par {
  font-variant-numeric: tabular-nums;
  font-size: var(--t-sm);
  text-align: right;
}

/* tabular-nums est indispensable ici : sans lui, le « 1 » de 41 est
   plus étroit que le « 3 » de 43 et les totaux ne s'alignent pas. */
.scoreline__total {
  font-weight: var(--w-black);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-lg);
  text-align: right;
}

/* Total non officiel : présent mais visuellement en retrait. */
.scoreline__total--soft { color: var(--pickup-ink); }



/* ------------------------------------------------------------
   ONGLETS
   ------------------------------------------------------------ */

.tabs {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.tab {
  flex: 1;
  min-height: 44px;
  border-radius: var(--r-md);
  border: var(--border);
  background: var(--paper-raised);
  font-weight: var(--w-semi);
  font-size: var(--t-sm);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Onglet actif dans la famille verte, comme le badge MARQUEUR.
   Le noir d'encre employé ici était à 148° — hors de la famille — et
   c'est ce qui faisait ces deux blocs sombres et étrangers au reste. */
.tab--on {
  background: var(--action-deep);
  border-color: var(--action-deep);
  color: #FFFFFF;
}

/* ------------------------------------------------------------
   STATISTIQUES DU JOUEUR
   ------------------------------------------------------------ */

.stats {
  display: flex;
  gap: var(--s-5);
  margin-top: var(--s-4);
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.stat__value {
  font-weight: var(--w-black);
  font-size: var(--t-xl);
  line-height: 1;
}

/* ------------------------------------------------------------
   COURBE DE PROGRESSION
   Un score bas est un bon score : l'axe vertical est inversé pour
   qu'une amélioration se lise comme une descente.
   ------------------------------------------------------------ */

.spark-wrap { margin-top: var(--s-4); }

.spark {
  display: block;
  width: 100%;
  height: 64px;
  overflow: visible;
}

.spark__line {
  fill: none;
  stroke: var(--action-deep);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.spark__dot { fill: var(--action-deep); }

.spark__dot--last {
  fill: var(--paper-raised);
  stroke: var(--action-deep);
  stroke-width: 3;
}

/* Une ligne cliquable doit LE MONTRER. Sans repère, le parent ne
   découvre la carte détaillée que par accident — et sur un écran
   tactile il n'y a pas de survol pour le lui apprendre.
   Le chevron est le signal universel de « ça mène ailleurs ». */
.scoreline__row--tap {
  cursor: pointer;
  grid-template-columns: 1fr 3.5em 2.5em 0.8em;
  border-radius: var(--r-sm);
  margin: 0 calc(var(--s-2) * -1);
  padding-left: var(--s-2);
  padding-right: var(--s-2);
}

.scoreline__row--tap::after {
  content: '\203A';
  color: var(--ink-faint);
  font-size: var(--t-lg);
  line-height: 1;
  text-align: right;
}

.scoreline__row--tap:active { background: var(--action-soft); }

/* Sous-titre d'une ligne : compétition, parcours. Le nom de la
   compétition est ce qui permet à un parent de reconnaître SA journée
   parmi d'autres — une date seule ne dit rien six mois plus tard. */
.scoreline__sub {
  display: block;
  font-weight: var(--w-regular);
  font-size: var(--t-xs);
  color: var(--ink-soft);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* La ligne d'aide qui annonce le geste, une seule fois par liste. */
.tapshint {
  font-size: var(--t-xs);
  color: var(--ink-soft);
  margin-top: var(--s-2);
}

/* Mention de navigation en pied de carte cliquable. Vert : c'est une
   action, même si le geste porte sur la carte entière. */
/* TOUTE CARTE QUI SE DÉCLARE BOUTON SE COMPORTE COMME UN BOUTON.

   Trois cartes de l'app portent role="button" — la dernière partie
   sur l'accueil, et deux dans l'historique. Aucune ne le montrait :
   au survol, le curseur restait une flèche, et rien ne bougeait. Le
   parent devait deviner qu'il pouvait cliquer.

   La règle porte sur l'attribut plutôt que sur une classe : une
   carte ajoutée demain avec role="button" en héritera sans qu'on
   ait à y penser, et une carte qui n'est pas cliquable ne l'aura
   jamais par accident.

   Le survol ne concerne que la souris. Sur un téléphone, :active
   donne le retour au doigt, et le liseré de focus sert au clavier —
   les trois publics sont couverts. */
[role="button"].player,
[role="button"].scoreline__row--tap {
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}

@media (hover: hover) {
  [role="button"].player:hover {
    border-color: var(--action-deep);
    box-shadow: 0 2px 8px rgba(20, 38, 28, 0.10);
  }
  [role="button"].player:hover .cardgo {
    color: var(--action-ink);
  }
  /* Les lignes de l'historique n'ont pas de bordure : c'est le fond
     qui répond. */
  [role="button"].scoreline__row--tap:hover {
    background: var(--action-soft);
  }
}

/* Le doigt aussi mérite une réponse : l'enfoncement se voit. */
[role="button"].player:active,
[role="button"].scoreline__row--tap:active {
  transform: scale(0.995);
}

.cardgo {
  margin-top: var(--s-3);
  padding-top: var(--s-2);
  border-top: var(--border);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--action-deep);
  text-align: right;
}
.scoreline__row--tap:active { opacity: 0.6; }


/* ------------------------------------------------------------
   LOGO CLIQUABLE
   Présent sur tous les écrans, il ramène à l'accueil. C'est le seul
   point fixe de l'app : sans lui, on entre dans un écran sans savoir
   comment en sortir.
   ------------------------------------------------------------ */

.brandlink {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0;
  background: none;
  border: none;
  transition: opacity var(--dur-fast) var(--ease);
}

.brandlink:active { opacity: 0.6; }

.brandlink .brandmark {
  width: 150px;
  max-width: 46vw;
  height: auto;
}

.brandlink .wordmark { font-size: var(--t-lg); }


/* ------------------------------------------------------------
   RÔLE SUR LA CARTE
   « Joueur » et « Marqueur » sont les termes imprimés sur la carte
   papier. On les reprend tels quels : c'est le vocabulaire que le
   parent a sous les yeux.
   ------------------------------------------------------------ */

.rolechip {
  display: inline-flex;
  align-items: center;
  padding: 3px var(--s-2);
  border-radius: var(--r-sm);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  border: 1.5px solid var(--rule);
  color: var(--ink-soft);
  background: var(--paper-sunk);
}

.rolechip--marqueur {
  border-color: var(--ink);
  color: var(--ink);
}

/* ------------------------------------------------------------
   DÉSIGNATION « MON JOUEUR »
   Notion propre à l'app, distincte du rôle sur la carte : celui
   dont on garde la progression d'une partie à l'autre.
   ------------------------------------------------------------ */

.follow {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 var(--s-3);
  border-radius: var(--r-pill);
  border: 1.5px solid var(--rule);
  background: var(--paper-raised);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: transform var(--dur-fast) var(--ease);
}

.follow:active { transform: scale(0.96); }

.follow--on {
  background: var(--action-deep);
  border-color: var(--action-deep);
  color: #FFFFFF;
}

/* Version non cliquable, affichée pendant la partie. */
.follow--tag {
  min-height: 26px;
  background: var(--action-deep);
  border-color: var(--action-deep);
  color: #FFFFFF;
  pointer-events: none;
}


/* ------------------------------------------------------------
   NOM DU PARCOURS
   Lu une fois en arrivant, il n'a pas besoin de plus de place.
   ------------------------------------------------------------ */

.course-name {
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ------------------------------------------------------------
   LIGNE DES PARS DANS LA CARTE
   L'app connaît les dix-huit pars : les afficher tous permet
   d'anticiper le trou suivant sans quitter l'écran.
   ------------------------------------------------------------ */

.board__parrow th,
.board__parrow td {
  background: color-mix(in srgb, var(--paper-sunk) 60%, var(--paper-raised));
}

/* Casse et tracking retirés d'ici : ils sont désormais posés une seule
   fois sur .board__name, pour toute la colonne. Les répéter ici
   redonnerait à cette ligne un traitement particulier. */
.board__parrow .board__name {
  font-size: var(--t-xs);
  color: var(--ink-soft);
}

.board__parrow .board__cell--now {
  background: color-mix(in srgb, var(--brand) 22%, transparent);
}

.board__par {
  display: inline-block;
  font-size: var(--t-xs);
  color: var(--ink-soft);
  line-height: 1.6;
}

/* Par inconnu : cliquable pour être renseigné depuis la carte. */
.board__par--ask {
  min-width: 22px;
  border: none;
  background: none;
  color: var(--pickup-ink);
  font-weight: var(--w-black);
}


/* ------------------------------------------------------------
   PASTILLE DE RÔLE ABRÉGÉE
   J = titulaire de la carte, M = celui qui la tient. En toutes
   lettres, la mention mangerait la largeur à côté du prénom.
   ------------------------------------------------------------ */

.rolemini {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  border-radius: var(--r-sm);
  border: 1.5px solid var(--rule);
  background: var(--paper-sunk);
  font-weight: var(--w-black);
  font-size: var(--t-xs);
  color: var(--ink-soft);
}

.rolemini--marqueur {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}

.rolemini--xs {
  width: 16px;
  height: 16px;
  font-size: 9px;
  border-width: 1px;
  margin-right: 3px;
}

/* Le rôle est une conséquence de la désignation, pas un choix :
   il s'affiche, il ne se clique pas. */
.rolechip { pointer-events: none; }


/* ------------------------------------------------------------
   CHAMPS DE FORMULAIRE
   L'erreur s'affiche sous le champ concerné, jamais en haut de page :
   sur mobile, un message hors écran n'existe pas.
   ------------------------------------------------------------ */

/* Le libellé et la mention obligatoire/facultatif sont deux blocs
   distincts : sans séparation, « PRÉNOM » et « OBLIGATOIRE » se
   collent et deviennent illisibles. */
.field__label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
}

.field__req {
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: 0;
  text-transform: none;
  color: var(--danger);
}

.field__opt {
  font-size: var(--t-xs);
  font-weight: var(--w-regular);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-faint);
}

.input--error {
  border-color: var(--danger);
  border-width: 2px;
  background: color-mix(in srgb, var(--danger) 5%, var(--paper-raised));
}

.fielderror {
  margin-top: var(--s-1);
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
  color: var(--danger);
}

.fielderror:empty { display: none; }

/* ------------------------------------------------------------
   ALERTE
   Plus ferme que .notice : quelque chose doit être corrigé avant
   de continuer.
   ------------------------------------------------------------ */

.alert {
  background: color-mix(in srgb, var(--danger) 6%, var(--paper-raised));
  border: 2px solid var(--danger);
  border-radius: var(--r-lg);
  padding: var(--s-4);
}

.alert .eyebrow { color: var(--danger); }


/* ------------------------------------------------------------
   ÉTIQUETTE DE RÔLE, CLIQUABLE
   Celui qui tient l'application est le marqueur ; les autres sont
   joueurs. Une seule étiquette porte donc à la fois le rôle et la
   désignation — deux boutons pour la même idée en faisaient une
   question posée deux fois.
   ------------------------------------------------------------ */

/* Un rôle n'est pas une action : c'est une information sur la partie.
   Les badges sortent donc de la famille verte, réservée aux boutons,
   pour que RETOUR et JOUEUR ne se confondent jamais.

   JOUEUR est neutre mais franc — 16:1 de contraste, loin du gris pâle
   d'origine qui plafonnait à 2.5 et se lisait comme « désactivé ».
   MARQUEUR reste vert plein : c'est le seul état qu'on choisit.

   La forme distingue aussi : les rôles sont des pastilles, les boutons
   des rectangles. */
.rolepick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  min-width: 148px;
  padding: 0 var(--s-4);
  border-radius: var(--r-pill);
  border: 1.5px solid var(--ink-soft);
  background: var(--paper-raised);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink);
  transition: transform var(--dur-fast) var(--ease);
}

.rolepick:active { transform: scale(0.96); }

.rolepick--on {
  background: var(--action-deep);
  border-color: var(--action-deep);
  color: #FFFFFF;
}


/* ------------------------------------------------------------
   PORTE D'ENTRÉE
   Un seul champ centré : il n'y a rien d'autre à faire sur cet écran.
   ------------------------------------------------------------ */

.gate {
  max-width: 340px;
  margin: 0 auto;
  padding: var(--s-6) 0;
}

.gate .wordmark {
  font-size: var(--t-2xl);
  text-align: center;
}

.gate input {
  font-size: var(--t-lg);
  letter-spacing: 0.05em;
  min-height: var(--touch-xl);
}

/* ------------------------------------------------------------
   BARRE DE NAVIGATION DU BAS

   Collée au bas de la colonne, au-dessus de l'encoche iPhone.
   Libellés seuls : un mot se lit en plein soleil, un pictogramme
   se devine.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   LA BARRE DU BAS PORTE L'HORIZON

   La ligne d'horizon vivait dans le corps de la page, en bandeau
   séparé, avec l'inconvénient de bouger au défilement et de ne
   toucher le menu que si la page était assez longue.

   En fond de la barre, elle est toujours là, toujours collée, sur
   tous les écrans. `background-blend-mode: multiply` marie l'image
   au fond craie : le blanc cassé du fichier disparaît, sans découpe
   à maintenir et sans dépendre de ce qu'il y a derrière.
   ------------------------------------------------------------ */

.tabbar {
  display: flex;
  position: sticky;
  bottom: 0;
  z-index: 20;
  border-top: var(--border-strong);
  padding-bottom: env(safe-area-inset-bottom);

  background: var(--paper);
}

/* L'horizon se pose JUSTE AU-DESSUS de la barre, pas dedans.

   En fond de la barre, l'image n'avait que soixante-dix pixels de
   haut pour se montrer : on n'en voyait que le bas, uniformément
   vert, et le menu virait à l'olive. La ligne d'horizon a besoin de
   sa hauteur pour exister.

   Posée au-dessus en élément décoratif, elle reste collée au menu
   sur tous les écrans, ne bouge pas au défilement, et ne teinte
   rien. `multiply` marie son blanc cassé au fond craie sans découpe
   à maintenir. */
.tabbar--horizon::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  /* 56 px, et c'est LA valeur de référence : les écrans qui portent
     ce bandeau réservent exactement la même hauteur en bas de leur
     corps. Elles étaient différentes — 76 ici, 56 là — et le bandeau
     recouvrait les derniers boutons de la page. Deux nombres qui
     doivent être égaux ne doivent pas être écrits deux fois ; à
     défaut de variable partagée, ce commentaire tient lieu de
     rappel. */
  height: 56px;
  background-image: url('../assets/imgMenu.webp');
  background-size: 100% 100%;
  background-position: center bottom;
  background-repeat: no-repeat;
  mix-blend-mode: multiply;
  pointer-events: none;
}

.tabbar__item {
  flex: 1;
  min-width: 0;
  min-height: var(--touch-min);
  display: flex;
  /* Marque au-dessus, mot en dessous. Le mot ne disparaît jamais :
     c'est lui qui tranche, la marque n'est qu'un repère de forme. */
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: var(--s-2) var(--s-1);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink-soft);

  /* Espacement resserré, et troncature de sécurité.

     Budget réel : quatre onglets sur un iPhone de 390 px font 97 px
     chacun, moins 8 px de marge intérieure — 89 px pour le mot.
     « COMPÉTITIONS », douze lettres en 12 px semi-gras, réclame
     environ 86 px sans espacement, et 98 px avec --track-wide
     (0.08 em). L'espacement large est calibré pour « JEUX » ou
     « PROFIL » ; sur douze lettres il coûte 11 px et ne rend rien.

     La troncature ne devrait jamais servir. Elle est là pour qu'un
     libellé plus long, ajouté un jour, se coupe proprement au lieu
     d'écraser les trois autres onglets. */
  letter-spacing: 0.02em;
  overflow: hidden;
  text-overflow: ellipsis;

  /* Le trait de sélection est en haut : en bas, il tomberait sous
     la zone lisible sur les iPhone à encoche. */
  border-top: 3px solid transparent;
  margin-top: -2px;
}

.tabbar__item--on {
  color: var(--action-deep);
  border-top-color: var(--action);
  background: var(--action-soft);
}

.tabbar__mark {
  display: block;
  width: 22px;
  height: 22px;
}

.tabbar__mark svg { width: 100%; height: 100%; display: block; }

/* Sur 320 px, « COMPÉTITIONS » déborde de sa colonne et mord sur ses
   voisins. Il rétrécit alors au lieu de sortir : un mot plus petit se
   lit encore, un mot coupé par le voisin ne se lit plus. */
.tabbar__label {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: clamp(0.58rem, 2.6vw, var(--t-xs));
}

.tabbar__item:active { background: var(--paper-sunk); }

/* ------------------------------------------------------------
   JEUX
   ------------------------------------------------------------ */

.rank {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.9em;
  height: 1.9em;
  border-radius: var(--r-pill);
  background: var(--paper-sunk);
  color: var(--ink-soft);
  font-size: var(--t-sm);
  font-weight: 500;
}

.player--lead {
  border-color: var(--action-deep);
  background: var(--action-soft);
}

.player--lead .rank {
  background: var(--action);
  color: var(--action-ink);
}

/* Trous pris en compte : pastille pleine si le trou est validé pour
   tous, pastille pâle sinon. */
.holedots {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
}

/* Cellule du tableau de la Chouette : le score joué au-dessus, les
   points gagnés en dessous. C'est le rapprochement des deux qui
   permet de trancher une contestation sans refaire le calcul. */
.owlcell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  line-height: 1.1;
}

.owlcell__score {
  font-size: var(--t-sm);
  color: var(--ink);
}

.owlcell__pts {
  font-size: var(--t-xs);
  color: var(--ink-faint);
}

.owlcell__pts--won {
  color: var(--action-deep);
  font-weight: 500;
}

.holedot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  border: var(--border);
  background: var(--paper-raised);
  color: var(--ink-faint);
  font-size: var(--t-xs);
}

.holedot--on {
  background: var(--action-soft);
  border-color: var(--action-deep);
  color: var(--ink);
}

/* ------------------------------------------------------------
   BANDEAU DE LA CHOUETTE

   Entre la carte et les compteurs : c'est là qu'on regarde entre
   deux trous. Aller chercher ses points dans un autre onglet, en
   marchant, personne ne le fait.
   ------------------------------------------------------------ */

.owlbar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding: var(--s-2) var(--s-4);
  background: var(--action-soft);
  border-bottom: var(--border);
}

.owlbar__tag {
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--action-deep);
}

.owlbar__rows {
  display: flex;
  gap: var(--s-4);
  flex: 1;
  min-width: 0;
}

.owlbar__row {
  display: flex;
  align-items: baseline;
  gap: var(--s-1);
  min-width: 0;
}

.owlbar__name {
  font-size: var(--t-xs);
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.owlbar__pts {
  font-weight: var(--w-black);
  font-size: var(--t-base);
  color: var(--ink);
}

/* En tête : le prénom passe en encre pleine et les points en vert.
   Pas de fond coloré — le bandeau en a déjà un. */
.owlbar__row--lead .owlbar__name { color: var(--ink); font-weight: var(--w-semi); }
.owlbar__row--lead .owlbar__pts  { color: var(--action-deep); }

.owlbar__note {
  font-size: var(--t-xs);
  color: var(--ink-faint);
  white-space: nowrap;
}

/* La note est aussi le chemin vers la saisie des handicaps : elle
   annonce ce qui manque ET permet d'y remédier. */
.owlbar__note--tap {
  padding: var(--s-1) var(--s-2);
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  color: var(--action-deep);
  font-weight: var(--w-semi);
}

.owlbar__note--tap:active {
  background: var(--paper-raised);
  border-color: var(--action-deep);
}

/* Résultat du trou qu'on vient de boucler, au-dessus du bouton qui
   mène au suivant. C'est l'instant où la question se pose. */
.owlhole {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding: var(--s-2) var(--s-3);
  margin-bottom: var(--s-3);
  background: var(--action-soft);
  border: 1.5px solid var(--action-deep);
  border-radius: var(--r-md);
}

.owlhole__tag {
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--action-deep);
}

.owlhole__rows {
  display: flex;
  gap: var(--s-4);
  flex: 1;
  justify-content: flex-end;
  flex-wrap: wrap;
}

.owlhole__row {
  display: flex;
  align-items: baseline;
  gap: var(--s-1);
}

.owlhole__name {
  font-size: var(--t-xs);
  color: var(--ink-soft);
}

.owlhole__pts {
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--ink-soft);
}

/* Celui qui a pris le trou : les deux en encre pleine. */
.owlhole__row--won .owlhole__name { color: var(--ink); font-weight: var(--w-semi); }
.owlhole__row--won .owlhole__pts  { color: var(--action-deep); font-weight: var(--w-black); }

/* ------------------------------------------------------------
   HANDICAP ET STROKE INDEX
   ------------------------------------------------------------ */

/* Ligne HP de la carte : le stroke index. Plus discrète que la ligne
   des pars — c'est une donnée de référence, pas un score. */
/* Même traitement que la ligne des pars : ce sont deux lignes de
   référence de même nature, imprimées côte à côte sur la carte
   papier. Les mettre à deux tailles différentes revenait à dire que
   l'une compte moins que l'autre. */
.board__hcprow th,
.board__hcprow td {
  background: color-mix(in srgb, var(--paper-sunk) 60%, var(--paper-raised));
}

/* Même chose : la casse vient de .board__name. Seul le fond distingue
   encore cette ligne. */
.board__hcprow .board__name {
  background: color-mix(in srgb, var(--paper-sunk) 60%, var(--paper-raised));
  font-size: var(--t-xs);
  color: var(--ink-soft);
}

.board__hcprow .board__cell--now {
  background: color-mix(in srgb, var(--brand) 22%, transparent);
}

.board__hcp {
  display: inline-block;
  font-size: var(--t-xs);
  color: var(--ink-soft);
}

/* Case vide : cliquable pour être renseignée, comme le par. */
.board__hcp--ask {
  border: 1px dashed var(--alt-line);
  border-radius: var(--r-sm);
  color: var(--alt-line);
}

/* Coups rendus sur le trou affiché. Bleu ardoise : c'est du comptage,
   pas une action ni un score. */
.strokebadge {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--s-2);
  min-height: 28px;
  border-radius: var(--r-pill);
  background: var(--count-soft);
  border: 1.5px solid var(--count);
  color: var(--count);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  white-space: nowrap;
}

/* Grille de saisie du stroke index : 18 valeurs, six par ligne.
   Une liste déroulante demanderait de viser deux fois. */
.hcpgrid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.hcpgrid__item {
  min-height: 52px;
  border-radius: var(--r-md);
  border: var(--border);
  background: var(--paper-raised);
  font-size: var(--t-base);
  color: var(--ink);
}

.hcpgrid__item--on {
  background: var(--action-deep);
  border-color: var(--action-deep);
  color: #FFFFFF;
}

/* Déjà attribué à un autre trou : signalé, jamais interdit — une
   carte mal lue ne doit pas bloquer la saisie. */
.hcpgrid__item--taken {
  /* Ce HP est déjà porté par un autre trou. On signale sans
     interdire : un stroke index ne se répète pas, mais une carte mal
     lue peut obliger à corriger, et bloquer le tap enfermerait.

     Le gris disait « indisponible » et se confondait avec un bouton
     désactivé. Le rouge dit « attention, celui-ci est pris » — c'est
     un avertissement, pas une porte fermée. */
  color: var(--danger);
  border-color: var(--danger);
  border-style: dashed;
}

.hcpgrid__item--taken.hcpgrid__item--on {
  color: #FFFFFF;
}

/* ------------------------------------------------------------
   LIGNES NET ET BRUT DE LA CARTE

   En Chouette au net, chaque joueur occupe DEUX lignes et l'ordre
   n'est pas décoratif : c'est le net qui donne le classement, donc
   c'est lui qui vient en premier, qui porte le prénom et qui reçoit
   le poids typographique. Le brut passe dessous sous son propre
   libellé.

   Le brut ne quitte jamais la carte — la règle tient. Il passe
   second, ce qui est autre chose que disparaître : c'est encore lui
   qu'on recopie sur la carte papier, et il reste lisible.

   Hors Chouette au net, il n'y a qu'une ligne, celle du brut, et
   aucune de ces deux règles ne s'applique.
   ------------------------------------------------------------ */

.board__netrow td,
.board__netrow th {
  background: var(--action-soft);
}

.board__netrow .board__name {
  background: var(--action-soft);
}

/* La ligne du résultat : les chiffres du net portent la graisse. */
.board__netrow .netmark {
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
  color: var(--ink);
}

.board__netrow .board__in,
.board__netrow .board__tot {
  font-weight: var(--w-semi);
}

/* Le brut relégué en seconde ligne : même traitement que la ligne
   net d'avant l'inversion — plus petit, plus clair, plus serré. */
.board__brutrow td,
.board__brutrow th {
  padding: 3px 2px !important;
}

.board__brutrow .board__name {
  color: var(--ink-soft);
  font-weight: var(--w-regular);
  font-style: italic;
}

.board__brutrow .mark,
.board__brutrow .board__in,
.board__brutrow .board__tot {
  font-size: var(--t-xs);
  color: var(--ink-soft);
}

.netmark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.6em;
  height: 1.5em;
  font-size: var(--t-xs);
  color: var(--ink-soft);
}

/* Un trou où le joueur reçoit un coup : le net y diffère du brut,
   et c'est précisément là que le regard doit se poser. */
.netmark--given {
  color: var(--action-deep);
  font-weight: 500;
  border-bottom: 2px solid var(--action-deep);
  border-radius: 0;
}

.netmark--empty { color: var(--ink-faint); }

/* Coups reçus par le joueur, rappelés dans la colonne des noms.
   Seule exception assumée du tableau : c'est une annotation, pas une
   valeur de la grille. Elle doit rester lisible sans concurrencer le
   prénom. Rien n'est affiché pour celui qui donne. */
.netmark__hcp {
  margin-left: auto;
  padding: 0 4px;
  border-radius: var(--r-sm);
  background: var(--paper-raised);
  color: var(--action-deep);
  font-size: 10px;
  font-style: normal;
  font-weight: 500;
}

/* ------------------------------------------------------------
   DÉPART MANQUÉ

   La balle n'a pas dépassé les repères avancés. Rien de calculable :
   c'est une déclaration, pas une mesure. Ambre, comme RAMASSÉ —
   l'autre petite honte du golf. Ni rouge, qui veut dire destructif
   dans l'app et « sous le par » sur la carte.
   ------------------------------------------------------------ */

.teemiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  min-height: 40px;
  padding: 0 var(--s-3);
  margin-top: var(--s-2);
  border-radius: var(--r-pill);
  border: 1.5px dashed var(--pickup-line);
  background: transparent;
  color: var(--pickup-ink);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  opacity: 0.65;
}

/* Déclaré : le contour se ferme et l'aplat se remplit. Plus de doute
   possible en relisant. */
.teemiss--on {
  border-style: solid;
  background: var(--pickup);
  opacity: 1;
}

.teemiss:active { transform: scale(0.97); }

/* Point ambre dans le coin de la case, sur la carte de score. */
.markwrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.teedot {
  position: absolute;
  top: -2px;
  right: -3px;
  width: 7px;
  height: 7px;
  border-radius: var(--r-pill);
  background: var(--pickup-line);
  border: 1px solid var(--paper-raised);
}

/* L'APÉRO, À LA FIN DE LA PARTIE

   Le décompte vivait dans le bandeau de comptage, trou après trou.
   Il y devenait une seconde course, en concurrence avec le
   classement, sur un bandeau qui n'a la place ni de l'un ni de
   l'autre. Il ne se lit plus qu'une fois la partie finie — c'est de
   toute façon à ce moment-là qu'on paie.
   ------------------------------------------------------------ */

.apero {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--pickup-bg);
  border: 1.5px solid var(--pickup-line);
}

.apero__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  font-size: var(--t-sm);
  color: var(--pickup-ink);
  opacity: 0.75;
}

/* Celui qui en a le plus. C'est lui qui paie. */
.apero__row--worst {
  opacity: 1;
  font-weight: var(--w-semi);
  font-size: var(--t-base);
}

.apero__name { white-space: nowrap; }

/* ------------------------------------------------------------
   LIGNES DE DISTANCES

   Une ligne par repère effectivement joué. Une carte porte souvent
   quatre départs : en afficher quatre quand deux sont joués noierait
   l'information sous du bruit.
   ------------------------------------------------------------ */

.board__distrow td,
.board__distrow th {
  padding: 2px 0 !important;
  background: var(--paper);
}

.board__distrow .board__name {
  background: var(--paper);
  color: var(--ink-soft);
}

.distmark {
  display: inline-block;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------
   BOUTON RETOUR

   Haut à gauche, sur tous les écrans, sans exception. C'est la
   convention d'iOS comme d'Android, et elle tient à une logique
   spatiale : un écran entré par la droite se quitte par la gauche.
   Le haut à droite reste réservé à ce qui termine — Enregistrer,
   Terminé — et à l'aide.

   Un bouton de navigation qui change de place d'un écran à l'autre
   cesse d'être un repère et redevient quelque chose à chercher.
   ------------------------------------------------------------ */

.backbtn {
  gap: var(--s-1);
  padding: 0 var(--s-3);
  font-size: var(--t-xs);
}

/* Le chevron porte le sens, le mot le confirme. Un pictogramme seul
   se devine ; un mot seul se repère moins bien du coin de l'œil. */
.backbtn__chevron {
  font-size: var(--t-lg);
  line-height: 1;
  margin-top: -2px;
}

/* ------------------------------------------------------------
   ATTENTE DE LECTURE DE CARTE

   La lecture prend cinq à quinze secondes. Un libellé figé pendant
   ce temps laisse croire que l'app a planté — c'est la durée où l'on
   appuie une seconde fois, où l'on quitte, où l'on doute.
   ------------------------------------------------------------ */

/* L'ATTENTE S'EMPILE, ELLE NE S'ALIGNE PLUS.

   Le golfeur et son texte étaient côte à côte, ce qui marchait tant
   que le bouton faisait toute la largeur. Depuis qu'ils sont deux sur
   une ligne, le bouton n'offre plus que 120 à 129 px de largeur
   utile — et le golfeur en réclame 120 à lui seul. Il ne restait
   rien pour le texte : le bonhomme sortait par la gauche et les mots
   étaient coupés.

   Ce n'était pas un défaut de l'animation, c'était le reste d'une
   mise en page qui n'existe plus. Empilés, les deux tiennent
   largement. */
.scanning {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  max-width: 100%;
}

/* Le texte ne suit plus la taille du libellé normal — il ne peut
   plus : « difficulté… » mesure 146 px à l'ancienne taille, plus
   large que le bouton entier. À cette taille-ci, le mot le plus long
   du lot tient sur une ligne.

   Le saut de taille au démarrage de l'analyse n'est plus un défaut
   d'affichage mais un changement d'état : le bouton cesse d'être un
   bouton et devient un témoin d'activité. */
.scanning__text {
  font-size: var(--t-xs);
  line-height: 1.25;
  text-align: center;
  max-width: 100%;
}

/* Le golfeur : trois traits et deux cercles, dessinés en SVG. Aucune
   image à charger, et l'animation coûte trois lignes de CSS. */
/* Affiché à la taille exacte de son viewBox (120 x 40), et non
   comprimé à 96 x 32 comme avant.

   C'est ce qui rendait le drapeau illisible : agrandir son tracé
   seul l'aurait rendu disproportionné par rapport au golfeur. Le
   défaut n'était pas dans le drapeau, il était dans l'échelle. */
/* 84 x 28, et non plus 120 x 40.

   La taille du viewBox était la bonne dans un bouton pleine largeur.
   Dans un demi-bouton, elle dépasse à elle seule la place
   disponible. Le rapport 3/1 est conservé, donc le geste et le
   drapeau restent justes — c'est l'échelle qui change, pas le
   dessin. */
.swinger {
  width: 84px;
  height: 28px;
  flex: 0 0 auto;
}

.swinger__head {
  fill: var(--action-ink);
}

.swinger__body,
.swinger__legs,
.swinger__arms path {
  stroke: var(--action-ink);
  stroke-width: 2.5;
  stroke-linecap: round;
  fill: none;
}

.swinger__club {
  stroke-width: 2;
}

/* Balayage LATÉRAL, ouvert vers le haut à l'armé.

   Le club part de la balle, remonte vers l'arrière jusqu'à hauteur
   d'épaule, puis revient frapper — de gauche à droite, jamais
   par-dessus la tête.

   Mesuré sur la géométrie du bonhomme, bras et club confondus soit
   22,5 px depuis l'épaule : l'arc couvre 41,7 px à l'horizontale pour
   18,6 px à la verticale, soit un rapport de 2,2 pour 1. Une version
   antérieure montait à -137°, ce qui plaçait la tête de club
   au-dessus du crâne : le geste se lisait alors comme vertical, quel
   que soit le reste. */
.swinger__arms {
  transform-origin: 26px 17px;
  animation: swing 1.8s var(--ease) infinite;
}

@keyframes swing {
  0%   { transform: rotate(3deg); }
  32%  { transform: rotate(143deg); }
  46%  { transform: rotate(143deg); }
  56%  { transform: rotate(3deg); }
  68%  { transform: rotate(18deg); }
  100% { transform: rotate(3deg); }
}

/* La balle part au moment de la frappe et file sur la DROITE.

   La première version la faisait monter puis retomber : une jolie
   parabole, mais dans une pastille de 34 px elle se lisait comme un
   saut vertical. Un drive se lit à sa portée, pas à sa hauteur — la
   trajectoire est donc quasi rasante, avec juste ce qu'il faut de
   montée pour qu'on la voie décoller. */
.swinger__ball {
  fill: var(--action-ink);
  animation: drive 1.8s var(--ease) infinite;
}

/* Le sol : sans lui, la balle flotte et l'on ne voit pas qu'elle
   parcourt une distance. Un trait suffit à donner l'échelle. */
.swinger__ground {
  stroke: var(--action-deep);
  stroke-width: 1;
  opacity: 0.3;
}

@keyframes drive {
  0%, 56%   { transform: translate(0, 0);        opacity: 1; }
  66%       { transform: translate(20px, -7px);  opacity: 1; }
  78%       { transform: translate(44px, -10px); opacity: 1; }
  90%       { transform: translate(62px, -4px);  opacity: 1; }
  97%       { transform: translate(66px, 0);     opacity: 0; }
  100%      { transform: translate(0, 0);        opacity: 0; }
}

/* Quelqu'un qui a réglé son téléphone pour limiter les animations ne
   doit pas subir celle-ci : le texte suffit à dire que ça travaille. */
@media (prefers-reduced-motion: reduce) {
  .swinger__arms,
  .swinger__ball {
    animation: none;
  }
}


/* ------------------------------------------------------------
   LOGO EN TÊTE D'ÉCRAN

   Sur sa propre ligne et centré, au-dessus des boutons. Le placer
   entre « Retour » et « Comprendre » ne tenait pas sur un iPhone SE :
   il y restait 37 px pour un mot qui en demande 82.
   ------------------------------------------------------------ */

.headmark {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 44px;
  padding-bottom: var(--s-4);
}

/* L'aide, sur les écrans sans retour : une pastille calée à droite du
   logo, réduite à son point d'interrogation. Le mot disparaît par
   font-size:0 sur le bouton, restauré sur la pastille — un
   display:none ne suffirait pas, le libellé étant un nœud de texte
   et non un élément. */
.headmark__action {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
}

/* Le cercle vert SEUL. Le bouton n'est plus qu'une zone tactile
   invisible autour de lui : ni fond, ni contour.

   Un bouton blanc entourant une pastille verte faisait deux formes
   concentriques pour un seul objet, et l'anneau blanc se détachait du
   fond crème. La cible tactile, elle, reste à 44 px — c'est la zone
   qu'on touche, pas ce qu'on voit. */
.headmark__action .help-btn {
  width: 44px;
  min-height: 44px;
  padding: 0;
  gap: 0;
  border: none;
  background: transparent;
  font-size: 0;

  /* Sans cette ligne, la pastille se cale à GAUCHE : .help-btn
     n'a pas de justify-content, ce qui ne se voit pas sur un bouton
     large mais saute aux yeux dès qu'il devient carré. */
  justify-content: center;
}

.headmark__action .help-btn__mark {
  width: 34px;
  height: 34px;
  font-size: var(--t-base);
  line-height: 1;
}

.headmark__action .help-btn:active .help-btn__mark {
  transform: scale(0.92);
}

/* Au moins aussi présent que les boutons qu'il surmonte : plus petit,
   il passait pour une mention légale plutôt que pour la marque. */
.wordmark--sm {
  font-size: var(--t-2xl);
}

/* ------------------------------------------------------------
   BOÎTE DE DIALOGUE

   Remplace confirm() et alert(). Les boîtes natives affichent
   l'adresse du site en titre, imposent « OK » et « Cancel » en
   anglais sans dire ce que l'action fait, et bloquent tout le fil
   d'exécution.
   ------------------------------------------------------------ */

.dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(19, 36, 27, 0.45);
  backdrop-filter: blur(2px);
  animation: dialog-fade var(--dur-base) var(--ease);
}

.dialog {
  position: fixed;
  z-index: 91;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  /* La colonne de l'app fait 480 px : la boîte ne doit jamais la
     dépasser, même sur un grand écran. */
  width: calc(100% - var(--s-6));
  max-width: 420px;

  background: var(--paper-raised);
  border: var(--border-strong);
  border-radius: var(--r-lg);
  padding: var(--s-5) var(--s-4) var(--s-4);
  box-shadow: 0 20px 60px rgba(19, 36, 27, 0.28);
  animation: dialog-rise var(--dur-base) var(--ease);
}

/* Une action irréversible se signale avant d'être lue : le liseré
   rouge en haut du cadre est vu avant le titre. */
.dialog--danger {
  border-color: var(--danger);
  border-top-width: 6px;
}

.dialog__title {
  font-weight: var(--w-black);
  font-size: var(--t-lg);
  line-height: 1.2;
}

.dialog__text {
  margin-top: var(--s-3);
  font-size: var(--t-sm);
  color: var(--ink-soft);
  line-height: 1.5;
}

.dialog__text--soft { color: var(--ink-faint); }

.dialog__actions {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-5);
}

/* DEUX LIGNES AU MAXIMUM, SUR TOUS LES APPAREILS.

   Un bouton de dialogue occupe la moitié d'une boîte, elle-même plus
   étroite que l'écran. Sur un iPhone 13 mini, il reste 90 px pour le
   texte une fois les rembourrages retirés — et le libellé y arrive
   habillé en capitales avec 0.08em d'interlettrage, deux réglages
   pensés pour des boutons pleine largeur.

   Les vingt-deux libellés de dialogue de l'application ont été
   mesurés à 360 px. Avec les réglages d'origine, DOUZE dépassaient
   deux lignes, dont « Enregistrer quand même » sur quatre, et deux
   dont un mot ne tenait même pas sur une ligne — « supprimer » et
   « l'essentiel » étaient coupés en plein milieu.

   Trois valeurs changent, et aucune n'est choisie à l'œil : la
   taille passe à 14 px, l'interlettrage à 0.04em, le rembourrage
   latéral à 8 px. La largeur utile passe ainsi de 90 à 126 px, et
   les TRENTE ET UN libellés de dialogue de l'application tiennent
   alors en deux lignes ou moins — vérifié à 360, 375, 390 et 393 px,
   soit du plus petit Android au plus grand iPhone du parc.

   Le rembourrage à 8 px n'est pas une coquetterie : à 12 px, deux
   libellés se coupaient encore en plein mot sur un écran de 360.

   La règle ne sort pas du dialogue : les boutons pleine largeur du
   reste de l'app gardent leur taille, ils ont la place. */
.dialog__actions .btn {
  font-size: var(--t-sm);
  letter-spacing: 0.04em;
  padding-left: var(--s-2);
  padding-right: var(--s-2);
}

@keyframes dialog-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes dialog-rise {
  from { opacity: 0; transform: translate(-50%, calc(-50% + 12px)); }
  to   { opacity: 1; transform: translate(-50%, -50%); }
}

@media (prefers-reduced-motion: reduce) {
  .dialog-backdrop,
  .dialog { animation: none; }
}

/* ------------------------------------------------------------
   LIGNES SYMÉTRIQUES

   Deux boutons dimensionnés par la longueur de leur libellé ne
   s'équilibrent jamais : « Retour » fait six lettres, « Comprendre »
   en fait dix. Une grille de deux colonnes égales règle la question
   une fois pour toutes, quel que soit le texte.
   ------------------------------------------------------------ */

.headrow,
.footrow {
  display: flex;
  justify-content: space-between;
  gap: var(--s-2);
  align-items: stretch;
}

/* Même largeur pour les deux, mais bornée : étirés sur la moitié de
   l'écran, ils prenaient plus de place que le titre qu'ils encadrent.
   Le plafond est calé sur le plus long des deux libellés, marges
   comprises. */
.headrow > * {
  flex: 1;
  max-width: 156px;
  justify-content: center;
}

/* LE PIED N'EST PLUS BORNÉ, ET SON ÉCART SUIT CELUI DE LA CARTE.

   Le plafond de 156 px et l'écart de 12 valaient du temps où ces
   deux boutons encadraient un titre dans un en-tête chargé. Ils sont
   maintenant seuls au bas d'une page, sous quatre boutons de carte
   qui font 162 px et se touchent à 8.

   Résultat mesuré : bords extérieurs alignés, mais boutons plus
   étroits — donc la couture centrale tombait onze pixels plus loin
   que celle du dessus. Deux rangées presque alignées se lisent plus
   mal qu'une rangée franchement différente : l'œil cherche l'erreur.

   `flex: 1 1 0` et non `flex: 1` : sans la base à zéro, le libellé
   le plus long se taille plus large, et l'alignement se perd
   là où il était censé se gagner. */
.footrow > * {
  flex: 1 1 0;
  min-width: 0;
  justify-content: center;
}

/* 44 px : la cible tactile minimale recommandée, pas un pixel de plus.
   À 56 px avec un contour de 2 px, ces deux boutons pesaient autant
   que le titre qu'ils encadrent — dans un en-tête qui porte déjà le
   logo, le parcours, la barre de trou et le badge de compétition. */
.headrow > .btn {
  min-height: 44px;
  border-width: 1.5px;
}

/* Un enfant vide — quand il n'y a pas de bouton d'aide — occupe
   quand même sa colonne : sans cela le bouton restant s'étalerait
   sur toute la largeur. */
.headrow > span:empty { display: block; }

/* Bouton fin : même famille, même contour, moitié de la hauteur.
   Pour ce qui termine ou quitte, en bas d'écran, où l'action
   principale est ailleurs. */
.btn--thin {
  min-height: 44px;
  font-size: var(--t-xs);
  padding: 0 var(--s-3);
}

.footrow { margin-top: var(--s-2); }

/* Un seul bouton dans la rangée : on le centre.

   space-between n'a de sens qu'entre deux éléments. Seul, avec son
   max-width de 156px, le bouton se collait au bord gauche du pied
   d'écran — ce qui se lit comme un défaut d'alignement plutôt que
   comme une intention.

   Le cas arrive au dernier trou, depuis que « Terminer » y a été
   retiré : il faisait doublon avec « Vérifier la carte », qui mène
   au même écran. */
.footrow:has(> *:only-child) {
  justify-content: center;
}

/* Deux boutons empilés dans un pied d'écran ont la même taille : la
   hiérarchie passe par la couleur, jamais par la dimension. */
.screen__foot > .btn--block + .btn--block {
  min-height: var(--touch-xl);
  font-size: var(--t-lg);
}


/* La signature est montée par le routeur, entre l'écran et le menu.
   Elle vivait dans le corps de chaque page et flottait donc à une
   hauteur qui dépendait de la longueur du contenu. */
.signature {
  border-top: var(--border);
  background: var(--paper);
  padding: var(--s-3) var(--s-4) var(--s-2);
}

/* Partie menée à son terme : un constat, pas une alerte. Vert de la
   famille, contour franc, aucune action à réparer. */
.notice--done {
  background: var(--action-soft);
  border-color: var(--action-deep);
}

/* Parcours et badge de compétition sur une seule ligne. Le badge
   occupait une ligne entière pour un mot, dans un en-tête qui en
   compte déjà cinq. */
.course-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: 34px;
}

.course-line .course-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.course-line .flag { flex: 0 0 auto; }


/* Le green au bout du parcours : un trou et son drapeau. La balle
   disparaît en l'atteignant, ce qui la fait lire comme rentrée. */
.swinger__hole {
  fill: var(--action-deep);
  opacity: 0.45;
}

.swinger__pole {
  stroke: var(--action-ink);
  stroke-width: 1.8;
  stroke-linecap: round;
}

.swinger__flag {
  fill: var(--under-par);
}

/* ------------------------------------------------------------
   TABLEAU DE VÉRIFICATION DE LA CARTE LUE

   Ce que le modèle a compris, disposé comme sur la carte papier.
   Trois lignes de chiffres à la queue leu leu — « Pars lus :
   4 4 5 3 5 4… » — ne se vérifient pas : rien ne dit à quel trou
   correspond quelle valeur. Un tableau, si.
   ------------------------------------------------------------ */

.readtable {
  font-size: var(--t-xs);
}

.readtable th[scope="row"] {
  text-align: left;
  white-space: nowrap;
  font-weight: var(--w-semi);
  color: var(--ink-soft);
}

/* La ligne des pars est celle qu'on relit en priorité : c'est elle
   qui décide des birdies et des bogeys. */
.readtable__par td,
.readtable__par th {
  background: color-mix(in srgb, var(--paper-sunk) 60%, var(--paper-raised));
  font-weight: 500;
}




/* ------------------------------------------------------------
   CARTES DE JEU

   Une carte par jeu dans l'onglet Jeux, construite depuis le
   registre de games.js. L'écran n'en connaît pas le nombre : trois
   aujourd'hui, quatre demain, la règle de style ne change pas.
   ------------------------------------------------------------ */

.gamecard {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  /* Grande zone tactile : 88 px de haut, soit bien au-delà du
     minimum. On choisit un jeu debout, une fois par partie — autant
     que la cible soit franche. */
  min-height: 88px;
  padding: var(--s-4);
  border-radius: var(--r-lg);
  background: var(--paper-raised);
  border: 1.5px solid var(--rule);
  box-shadow: 0 1px 2px rgba(20, 38, 28, 0.05), 0 4px 12px rgba(20, 38, 28, 0.04);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

.gamecard:active { transform: scale(0.99); }

.gamecard:active { transform: scale(0.995); }

/* LE NOM NE CÈDE JAMAIS : c'est ce qu'on vient lire.

   J'avais d'abord fait l'inverse — nom tronqué, effectif entier — et
   « Chouette » devenait « C… ». Un nom coupé au premier caractère
   n'identifie plus rien, alors qu'un effectif qui passe à la ligne
   reste parfaitement lisible.

   Sur 320 px, les deux ne tiennent pas côte à côte : ils s'empilent
   alors, le nom au-dessus. Aucune media query — c'est le contenu qui
   décide, pas la fenêtre. */
.gamecard__name {
  font-size: var(--t-lg);
  font-weight: var(--w-black);
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
}

/* Le nombre de joueurs se lit avant le reste : c'est lui qui dit si
   le jeu est jouable ce jour-là, avec les gens qui sont là. */
.gamecard__players {
  flex: none;
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
}

.gamecard__text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 2px var(--s-2);
}

/* Le chevron dit que la carte mène quelque part. Sans lui, un bloc
   avec un titre et un texte ressemble à de la documentation. */
.gamecard__chevron {
  flex: none;
  font-size: var(--t-xl);
  line-height: 1;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------
   PANNEAU DE LA PARTIE EN COURS

   Fond photographique et texte clair. C'est la seule zone sombre de
   l'application : partout ailleurs le fond craie reste obligatoire
   pour la lisibilité en plein soleil.

   D'où le voile. L'image seule ne garantit rien — un ciel clair ou
   un green éclairé passeraient sous du texte blanc. Le dégradé pose
   un noir vert dense à GAUCHE, là où vit tout le texte, et s'efface
   vers la droite pour laisser voir le drapeau. Le contraste ne
   dépend donc plus de ce que l'image contient.
   ------------------------------------------------------------ */

.livegame {
  display: flex;
  flex-direction: column;
  /* NE JAMAIS ÊTRE COMPRIMÉ.

     Dans une colonne flexible, un bloc rétrécit par défaut quand la
     place manque. Combiné à son `overflow: hidden` — nécessaire pour
     que la photo respecte les coins arrondis — le panneau se faisait
     tailler de 278 à 153 px, et perdait sa bande de trous et ses deux
     boutons. Aucune règle ne les cachait : le bloc était simplement
     rogné.

     Le contenu doit primer sur la place disponible : s'il manque de
     hauteur, c'est la page qui défile, pas le panneau qui se coupe. */
  flex: none;
  gap: var(--s-3);
  padding: var(--s-4);
  border-radius: var(--r-lg);
  background: var(--paper-raised);
  border: var(--border-strong);
  box-shadow: var(--shadow-raised);
}

.livegame--photo {
  position: relative;
  overflow: hidden;
  border: 0;
  color: #FFFFFF;

  background-image:
    linear-gradient(100deg,
      rgba(11, 26, 16, 0.97) 0%,
      rgba(11, 26, 16, 0.92) 38%,
      rgba(11, 26, 16, 0.55) 68%,
      rgba(11, 26, 16, 0.30) 100%),
    url('../assets/imgGreen.webp');
  background-size: cover;
  background-position: right center;
  background-repeat: no-repeat;
}

.livegame__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-3);
}

/* « Partie en cours » : une étiquette pleine plutôt qu'un eyebrow
   gris, qui disparaîtrait sur le fond sombre. */
.livegame__badge {
  align-self: flex-start;
  padding: var(--s-1) var(--s-3);
  border-radius: var(--r-pill);
  background: var(--action);
  color: var(--action-ink);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.livegame__title {
  font-size: var(--t-2xl);
  font-weight: var(--w-black);
  letter-spacing: var(--track-tight);
  line-height: 1.05;
  color: #FFFFFF;
}

.livegame__players {
  font-size: var(--t-base);
  font-weight: var(--w-medium);
  color: rgba(255, 255, 255, 0.92);
}

/* Nomme la bande des trous. Sans ce titre, neuf chiffres alignés se
   lisent comme un sélecteur, donc comme quelque chose à toucher. */
.livegame__label {
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
}

.livegame__actions {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-1);
}

/* ------------------------------------------------------------
   BOUTONS D'ACTION DU PANNEAU

   Côte à côte plutôt qu'empilés : la reprise garde l'aplat plein et
   la plus grande part, l'arrêt reste secondaire. Le rapport 3/2
   n'est pas décoratif — l'action principale doit être la plus grande
   cible, et son libellé est le plus long.

   La marque précède le mot : un triangle se comprend avant qu'on ait
   fini de lire « Reprendre ».
   ------------------------------------------------------------ */

.actionbtn {
  flex: 2;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--touch-min);
  padding: var(--s-3);
  font-size: var(--t-sm);
  font-weight: var(--w-black);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.actionbtn--main { flex: 3; }

.actionbtn__mark {
  flex: none;
  width: 14px;
  height: 14px;
}

/* Triangle de lecture, dessiné au clip plutôt qu'en image : il suit
   la couleur du texte du bouton, quelle qu'elle devienne. */
.actionbtn__mark--play {
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.actionbtn__mark--stop {
  background: currentColor;
  border-radius: 2px;
}

/* Pas de media query : voir la note sur .resume. Les deux boutons
   tiennent côte à côte dans la colonne de 480 px, et leurs libellés
   sont assez courts pour ne pas se casser. */

/* Sur le fond sombre, le bouton destructif s'inverse : aplat clair,
   texte rouge. Un contour rouge sur du vert noir serait invisible. */
.livegame--photo .btn--danger {
  background: var(--paper-raised);
  border-color: var(--danger);
  color: var(--danger);
}

/* La bande des trous, sur fond sombre : contour clair, et le vert de
   marque pour les trous comptés. */
.holedots--live { margin-top: 0; }

.livegame--photo .holedot {
  border-color: rgba(255, 255, 255, 0.32);
  color: rgba(255, 255, 255, 0.55);
  background: transparent;
}

.livegame--photo .holedot--on {
  background: var(--action);
  border-color: var(--action);
  color: var(--action-ink);
  font-weight: var(--w-semi);
}

/* ------------------------------------------------------------
   BLOC D'INFORMATION

   Une règle de comptage se signale. La pastille « i » remplace une
   phrase d'introduction : le lecteur sait en un coup d'œil qu'il
   s'agit d'une explication et non d'une alerte.
   ------------------------------------------------------------ */

.infonote {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--paper-sunk);
}

.infonote__mark {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: var(--r-pill);
  background: var(--action-deep);
  color: #FFFFFF;
  font-size: var(--t-sm);
  font-weight: var(--w-black);
  font-style: italic;
  display: flex;
  align-items: center;
  justify-content: center;
}

.infonote__text {
  font-size: var(--t-sm);
  line-height: 1.45;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------
   EN-TÊTE PAYSAGE

   Le paysage n'est pas une image posée dans la page mais le FOND de
   l'en-tête : il passe derrière le logo, le bouton retour et le
   titre, puis s'arrête net où commence la liste.

   Trois choix pour qu'il reste discret. `multiply` marie son blanc
   cassé au fond craie, sans découpe à maintenir. `opacity` le pâlit
   franchement — sur une illustration déjà claire, un texte foncé
   passe partout, mais autant garder de la marge. Et un dégradé de
   masque efface progressivement le haut, pour que le logo ne se pose
   jamais sur une colline.
   ------------------------------------------------------------ */

.screen__head--paysage {
  position: relative;
  border-bottom: 0;

  /* HAUTEUR MINIMALE, parce que tous les en-têtes n'ont pas le même
     contenu. Avec un bouton retour, la hauteur venait toute seule ;
     sur le Profil au premier lancement, qui n'en a pas, le paysage se
     retrouvait comprimé derrière le logo et le titre lui passait
     dessus. Le décor ne doit pas dépendre de la présence d'un
     bouton. */
  min-height: 168px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* Juste ce qu'il faut pour que les collines vivent SOUS le titre.
     Au-delà, l'écart entre « Jeux » et la liste devient un trou. */
  padding-bottom: var(--s-5);
}

/* ANCRÉ EN BAS, PAS ÉTIRÉ SUR TOUT L'EN-TÊTE.

   `inset: 0` collait le paysage aux quatre bords : sa hauteur suivait
   donc celle de l'en-tête, et il remontait derrière le logo dès que
   celui-ci était court. Ancré par le bas sur une hauteur fixe, il
   occupe la même bande sur tous les écrans, avec ou sans bouton
   retour — c'est ce qui rend les en-têtes identiques. */
.screen__head--paysage::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 96px;
  z-index: 0;
  /* UN AUTRE FRAGMENT DU MÊME PAYSAGE.

     Le bandeau du bas et cet en-tête sortent du même dessin, mais
     pas du même endroit : imgHeader est la moitié DROITE de
     l'illustration, celle du drapeau et des sapins. Même univers,
     jamais la même image.

     J'ai d'abord essayé d'agrandir et de décaler le fichier du bas.
     Agrandi, il devenait plus haut que l'en-tête et ses arbres
     remontaient derrière le logo ; le repousser vers le bas les
     faisait disparaître. Un fragment découpé à la bonne hauteur ne
     pose pas ce problème : il tient dans le bas de l'en-tête par
     construction. */
  background-image: url('../assets/imgHeader.webp');

  /* Le paysage occupe LE BAS de l'en-tête, sur une hauteur fixe,
     et non toute sa surface. Étalé sur l'ensemble, il remontait
     derrière le logo dès que l'en-tête était court — le Profil au
     premier lancement, qui n'a pas de bouton retour. Une hauteur en
     pixels ne dépend pas du contenu qu'il y a au-dessus. */
  background-size: 100% auto;
  background-position: center bottom;
  background-repeat: no-repeat;
  mix-blend-mode: multiply;

  /* 0.85 et non 0.5.

     Le fichier lui-même est déjà très pâle : ses collines sont à
     #C0C896, à peine plus sombres que le fond craie. À 50 %, l'écart
     avec le fond tombait à 49 niveaux sur 255 ; à 15 %, il serait de
     15 — autant ne rien mettre. À 85 %, l'écart atteint 83, ce qui
     reste discret mais se voit.

     Le réglage de la discrétion se fait donc dans le FICHIER, pas
     ici : une image plus pâle se règle en la redessinant, pas en
     baissant l'opacité de ce qui est déjà pâle. */
  opacity: 0.85;
  pointer-events: none;

  /* Le paysage naît en bas et s'efface vers le haut : le logo reste
     sur du craie pur, les collines n'apparaissent qu'à hauteur du
     titre. */
  /* Le paysage monte PROGRESSIVEMENT et redescend à la fin.

     Rien en haut : le logo reste sur du craie pur. À peine visible à
     hauteur du bouton retour, pour qu'aucune colline ne le traverse.
     Le plus dense derrière le titre. Puis un fondu franc vers le bas,
     sans quoi le header se terminerait sur une ligne nette — c'est ce
     bord qui trahissait une image collée. */
  /* Le fondu ne mange plus que la toute fin. Auparavant il commençait
     à 72 % et effaçait précisément la bande où vivent les arbres :
     le paysage devenait un lavis vert sans forme. */
  -webkit-mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0,0,0,0.35) 30%, #000 62%, #000 88%, transparent 100%);
  mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0,0,0,0.35) 30%, #000 62%, #000 88%, transparent 100%);
}

/* Le contenu repasse devant le fond. */
.screen__head--paysage > * { position: relative; z-index: 1; }

/* Voir la règle dans view-head.js : un titre sans bouton de retour
   se centre, parce que le logo au-dessus l'est. L'eyebrow suit le
   titre — les deux forment un seul bloc et ne peuvent pas s'aligner
   différemment. */
.screen__head--titrecentre h1,
.screen__head--titrecentre .eyebrow { text-align: center; }

/* LE RETOUR, RÉDUIT ET ALIGNÉ SUR LE TITRE.

   Ailleurs dans l'app, ce bouton est une cible de 44 px calée sur une
   colonne : il encadre un titre entre deux actions. Ici il n'encadre
   rien — il n'y a pas de bouton d'aide — et sa colonne l'étirait sur
   156 px, bien au-delà du mot « Jeux » qu'il surmonte.

   Il se réduit donc à son contenu et vient se poser exactement au-
   dessus du titre, même bord gauche. Sa hauteur descend à 34 px :
   c'est en dessous du minimum tactile de l'app, mais ce bouton-là se
   touche à l'arrêt, sans gant, et le geste est réversible.

   Fond transparent pour que le paysage passe dessous : c'est le
   contour seul qui le désigne comme bouton. */
.screen__head--paysage .headrow > * {
  flex: none;
  max-width: none;
}

/* Chacun son bord : le retour à gauche, l'aide à droite. `flex-start`
   les collait l'un à l'autre dès qu'il y avait les deux. */
.screen__head--paysage .headrow {
  justify-content: space-between;
}

/* Les deux boutons de l'en-tête paysage sont taillés pareil : même
   hauteur, même contour, fond transparent pour laisser voir les
   collines. Deux boutons voisins de hauteurs différentes se lisent
   comme une erreur. */
.screen__head--paysage .backbtn,
.screen__head--paysage .help-btn {
  min-height: 34px;
  padding: 0 var(--s-2);
  background: transparent;
  border-width: 1.5px;
}

/* ------------------------------------------------------------
   MARQUES DES JEUX

   Un carré coloré par jeu, dessiné en SVG. Trois teintes prises dans
   la palette existante : le vert profond de l'action pour la
   Chouette, l'ardoise du comptage pour le Stableford, l'ambre du
   ramassé pour le Match Play. Aucune couleur nouvelle n'entre dans
   l'application pour trois icônes.
   ------------------------------------------------------------ */

.gameicon {
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: var(--r-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
}

.gameicon svg { width: 26px; height: 26px; }

.gameicon--chouette   { background: var(--action-deep); }
.gameicon--stableford { background: var(--count); }
.gameicon--matchplay  { background: var(--pickup-line); }

/* ------------------------------------------------------------
   REPLIS

   <details> natif. Le titre se touche, le contenu apparaît. Utile
   une fois par partie — la règle, le détail trou par trou — donc
   fermé par défaut plutôt que d'occuper l'écran en permanence.
   ------------------------------------------------------------ */

.fold {
  border-top: var(--border);
  padding-top: var(--s-2);
}

.fold__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-2) 0;
  min-height: var(--touch-min);
  cursor: pointer;
  list-style: none;
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-soft);
  -webkit-tap-highlight-color: transparent;
}

/* Le triangle par défaut de Safari et de Chrome, retiré des deux
   côtés : le chevron maison le remplace, et il tourne. */
.fold__head::-webkit-details-marker { display: none; }

.fold__chevron {
  flex: none;
  font-size: var(--t-lg);
  line-height: 1;
  color: var(--action-deep);
  transform: rotate(90deg);
  transition: transform var(--dur-fast) var(--ease);
}

.fold[open] .fold__chevron { transform: rotate(-90deg); }

.fold__head:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.fold__body { padding-bottom: var(--s-3); }

/* Séparation entre ce qui concerne la partie en cours et ce qui
   propose autre chose. Un filet, pas un titre : le titre viendrait
   dire une seconde fois ce que la section dit déjà. */
.sectionrule {
  border: 0;
  border-top: var(--border);
  margin: var(--s-4) 0 0;
}

/* Cartes de jeu en second plan : une partie tourne déjà, celles-ci
   ne sont plus l'action du moment. Fond de page au lieu du blanc,
   ombre retirée, titre ramené à la taille du texte courant. */
.gamecard--quiet {
  background: transparent;
  box-shadow: none;
  padding: var(--s-3) var(--s-4);
}

.gamecard--quiet .gamecard__name { font-size: var(--t-base); }


/* CÔTE À CÔTE : deux mondes d'égale importance, comparables d'un
   coup d'œil. Empilées, elles obligeaient à défiler pour découvrir
   la seconde — donc à croire que la première compte davantage. */
.homecards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-3);
  align-items: stretch;
}

/* Deux colonnes toujours : la colonne de l'app est bornée à 480 px,
   donc la largeur utile ne varie presque pas. Une media query serait
   ici sans effet — voir la note sur .resume. */

/* ------------------------------------------------------------
   CARTES D'ACCUEIL : PHOTO EN HAUT, TEXTE SUR APLAT

   Le texte ne se pose plus sur l'image. Sur un aplat il reste
   lisible quoi qu'il arrive ; sur une photo, sa lisibilité dépend
   d'un voile réglé à la main, donc de ce que l'image contient.

   Les deux cartes n'ont pas le même fond, et c'est voulu : la
   compétition en vert-noir, les jeux en clair. Deux mondes, deux
   températures. Le clair a un avantage que l'app connaît bien — il
   reste lisible en plein soleil.
   ------------------------------------------------------------ */

.homecard {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: var(--r-lg);
  overflow: hidden;

  /* Pas de contour : clair, il se voyait contre la photo et
     disparaissait contre le corps sombre, ce qui donnait l'illusion
     d'une carte plus large que son image. Le fond plein du corps
     délimite déjà la carte. */
  box-shadow: var(--shadow-raised);
}

/* 80 px, ET NON 96. LA MARGE PLUTÔT QUE LE RABOTAGE.

   L'accueil tenait « tout juste » dans mes mesures et débordait sur
   l'appareil. Deux fois de suite j'ai grappillé des pixels sur des
   écarts jusqu'à tomber à zéro théorique — et deux fois le compte
   était faux, parce que mon banc d'essai ne reproduisait pas
   exactement l'appareil.

   Un écran qui tient à six pixels près ne tient pas : il suffit
   d'une police légèrement différente, d'un réglage de taille de
   texte système, d'un modèle au safe area d'un autre ordre.

   Ces seize pixels, plus les seize repris à la réserve du bandeau,
   donnent trente-deux pixels de marge réelle. La photo reste
   largement lisible : c'est une vignette d'ambiance, pas le sujet
   de la carte. */
.homecard__photo {
  height: 80px;
  background-size: cover;
  background-repeat: no-repeat;
}

/* CADRAGE : ON VISE LE SUJET, PAS LE CENTRE.

   Les deux photos n'ont pas du tout les mêmes proportions — l'une
   est en hauteur, l'autre en largeur — et un cadrage centré ne
   convient à aucune des deux. Sur la première, le centre tombe dans
   le ciel et le drapeau disparaît sous la coupe ; sur la seconde,
   il faut descendre pour garder le fairway plutôt que la montagne.

   Ces deux valeurs sont donc liées AUX IMAGES : si tu en changes une,
   c'est ici qu'il faudra reviser le cadrage. */
.homecard--compet .homecard__photo {
  background-image: url('../assets/imgAcceuil1.webp');
  /* Bande large et basse : le centre tombe sous le drapeau. On
     remonte pour le garder dans le cadre. */
  background-position: center 30%;
}

.homecard--jeux .homecard__photo {
  background-image: url('../assets/imgAcceuil2.webp');
  background-position: center 62%;
}

/* La marque chevauche la limite entre photo et aplat : c'est elle
   qui coud les deux moitiés et empêche la carte de se lire comme
   deux blocs empilés. */
.homecard__mark {
  /* Posée dans le flux, à cheval sur la limite grâce aux marges
     négatives : elle suit donc la photo sans dépendre d'une distance
     fixe depuis le haut. */
  position: static;
  align-self: center;
  margin-top: -22px;
  margin-bottom: -22px;
  z-index: 1;
  width: 44px;
  height: 44px;
  border-radius: var(--r-pill);
  background: var(--action);
  color: var(--action-ink);
  border: 3px solid var(--paper-raised);
  display: flex;
  align-items: center;
  justify-content: center;
}

.homecard__mark svg { width: 22px; height: 22px; }

.homecard__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--s-1);
  /* 34 px en haut, et non un jeton d'espacement : c'est la moitié du
     disque de la marque (52 px) plus une respiration. En dessous, le
     titre passe sous l'icône — c'est arrivé en réduisant ce
     rembourrage sans regarder ce qu'il retenait. */
  padding: 28px var(--s-3) var(--s-3);
}

/* LA COULEUR EST PORTÉE PAR LA CARTE, PAS PAR LE CORPS.

   Le corps seul était coloré, et la photo, dont les bords sont
   clairs, se fondait dans le fond de page : la carte semblait plus
   étroite en haut qu'en bas. Les mesures disaient pourtant la même
   largeur — c'était un effet de contraste, pas de géométrie.

   En posant la couleur sur la carte entière, le bloc se lit d'un
   seul tenant, quelle que soit la photo qu'on y mettra demain. */
.homecard--compet { background: #16281C; }
.homecard--jeux   { background: var(--paper-raised); }

.homecard__title {
  font-size: var(--t-lg);
  font-weight: var(--w-black);
  letter-spacing: var(--track-tight);
  line-height: 1.1;
  text-transform: uppercase;
}

.homecard--compet .homecard__title { color: #FFFFFF; }
.homecard--jeux   .homecard__title { color: var(--ink); }

/* Le sous-titre nomme la SITUATION, pas la fonctionnalité. */
.homecard__sub {
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  line-height: 1.3;
}

.homecard--compet .homecard__sub { color: var(--brand); }
.homecard--jeux   .homecard__sub { color: var(--action-deep); }

.homecard__line {
  /* Bornée en largeur : sur un écran large, une ligne de texte
     centrée qui court sur 480 px devient pénible à lire. */
  width: 100%;
  margin-top: var(--s-1);
  padding-top: var(--s-2);
  /* Trois lignes réservées, pour la même raison que la liste. */
  min-height: calc(1.45em * 3 + var(--s-2));
  font-size: var(--t-xs);
  line-height: 1.45;
}

.homecard--compet .homecard__line {
  color: rgba(255, 255, 255, 0.86);
  border-top: 1px solid rgba(255, 255, 255, 0.20);
}

.homecard--jeux .homecard__line {
  color: var(--ink-soft);
  border-top: var(--border);
}

/* Les jeux, nommés. « Jeux » ne dit rien, « Chouette · Stableford ·
   Match Play » dit tout — c'est ce qui donne envie d'ouvrir.

   Hauteur réservée sur LES DEUX cartes, vide comprise : c'est elle
   qui garde les deux corps à la même hauteur et les deux boutons
   alignés, quelle que soit la longueur des textes. */
.homecard__list {
  min-height: calc(1.4em * 2);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  color: var(--action-deep);
  line-height: 1.4;
}

.homecard__btn {
  width: 100%;
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 48px;
  /* Pas d'interlettrage élargi : sur 190 px, il casse le libellé en
     deux lignes. */
  font-size: var(--t-xs);
  font-weight: var(--w-black);
  text-transform: uppercase;
  white-space: nowrap;
}

.homecard__arrow { font-size: var(--t-base); line-height: 1; }

/* ------------------------------------------------------------
   LIGNE DE REPRISE

   Une ligne, pas une carte. Elle ne concerne qu'un cas — une partie
   déjà commencée — et occupait auparavant un bloc entier avec deux
   gros boutons, dont un destructif, avant les deux portes.
   ------------------------------------------------------------ */

.resume {
  display: flex;
  /* UNE SEULE LIGNE, ET ELLE TIENT.

     Le repli automatique envoyait le bouton sous le texte dès qu'un
     nom de parcours était long, et la ligne devenait un bloc. Ce
     n'est pas ce qu'on veut : c'est un rappel discret, pas une
     carte.

     Dans 480 px, une fois l'icône, le trou et le bouton posés, il
     reste environ 150 px pour le titre. « Chouette » y entre,
     « Barbaroux Golf, Hotel & Spa » non — il se coupe donc
     proprement par des points de suspension. Un titre tronqué reste
     lisible ; un bouton qui saute à la ligne casse la forme. */
  flex-wrap: nowrap;
  align-items: center;
  /* Aucun espace ENTRE les deux moitiés : il se serait ajouté à la
     frontière, et le séparateur se serait posé quatre pixels — la
     moitié de l'espace — à droite du centre. Chaque moitié porte sa
     propre respiration. */
  gap: 0;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-lg);
  background: var(--paper-raised);
  border: var(--border);
  box-shadow: var(--shadow-raised);
}

.resume__mark {
  flex: none;
  width: 30px;
  height: 30px;
  color: var(--action-deep);
}

.resume__mark svg { width: 100%; height: 100%; display: block; }

/* LE SÉPARATEUR TOMBE AU MILIEU, ET C'EST UNE CONSTRUCTION.

   Le bloc de texte était simplement élastique : il prenait tout ce
   qui restait, si bien que la position du trait dépendait de la
   largeur du bouton. Elle tombait dix pixels trop à droite, et
   aurait bougé au moindre changement de libellé.

   En donnant la même part aux deux moitiés — le texte à gauche, le
   trou et le bouton à droite — le trait se pose au centre quoi qu'on
   écrive dedans.

   `overflow: hidden` reste le filet : si le texte grandit un jour,
   il se coupe au lieu de déborder sur ses voisins. */
/* La moitié gauche : l'icône ET le texte. C'est ce couple qui doit
   peser la moitié de la ligne, pas le texte seul. */
.resume__left {
  flex: 1 1 50%;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding-right: var(--s-2);
}

.resume__text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

/* La moitié droite : le trou et le bouton, poussés vers la fin. */
.resume__right {
  flex: 1 1 50%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-2);
}

/* Le seul texte de la ligne : une étiquette d'état, pas un titre de
   contenu. Taille réduite et interlettrage normal — en corps
   supérieur, la ligne réclamait 432 px pour 398 disponibles, et le
   texte débordait sur le séparateur. */
.resume__title {
  /* 0.7rem et non --t-xs : sur un iPhone de 390 px, les douze
     pixels du jeton faisaient déborder la ligne de quelques unités.
     C'est la seule taille hors barème de la feuille, et elle est ici
     pour une raison mesurée, pas par goût. */
  font-size: 0.7rem;
  font-weight: var(--w-black);
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
  line-height: 1.2;
  white-space: nowrap;
}

/* Où l'on en est, séparé par un filet : l'état de la partie et sa
   progression sont deux natures d'information différentes.

   Le filet avait été retiré parce qu'il touchait le texte faute de
   place. Le vrai problème n'était pas le trait mais l'espace : il
   revient, avec de l'air des deux côtés, et la place a été prise
   ailleurs — sur les marges, pas sur la lisibilité. */
.resume__where {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s-1);
  /* Le filet est porté par cette moitié, donc posé exactement à la
     frontière des deux parts égales. */
  padding-left: var(--s-2);
  border-left: var(--border);
  margin-right: auto;
  font-size: var(--t-sm);
  font-weight: var(--w-medium);
  color: var(--ink);
  white-space: nowrap;
}

.resume__flag { width: 16px; height: 16px; color: var(--action-deep); }
.resume__flag svg { width: 100%; height: 100%; display: block; }

/* Contour vert sur fond blanc. Le vert plein appartient aux deux
   portes juste au-dessus : deux aplats identiques sur le même écran
   se disputeraient le regard, alors que reprendre n'est pas au même
   niveau que choisir ce qu'on va jouer. */
.resume__btn {
  background: var(--paper-raised);
  border: 2px solid var(--action-deep);
  color: var(--action-deep);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  /* Plus large, moins haut que le standard de l'app. Les 56 px du
     jeton --touch-min valent pour les boutons qu'on vise en marchant,
     avec des gants : ceux du compteur. Celui-ci se touche à l'arrêt,
     avant de partir, et 48 px restent au-dessus du minimum
     recommandé. La largeur gagnée compense la hauteur perdue. */
  min-height: 48px;
  padding: 0 var(--s-3);
  font-size: var(--t-xs);
  font-weight: var(--w-black);
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
  white-space: nowrap;
}

/* PAS DE MEDIA QUERY ICI, ET C'EST UNE RÈGLE POUR TOUTE L'APP.

   Une media query mesure la FENÊTRE. Or l'application vit toujours
   dans une colonne plafonnée à 480 px, quelle que soit la taille de
   l'écran : sur un ordinateur, la fenêtre fait 1400 px et la règle
   ne se déclenche jamais, alors que le contenu, lui, est bien à
   l'étroit. La page était donc correcte sur téléphone et comprimée
   sur ordinateur — pour exactement la même largeur utile.

   La mise en page interne doit donc être élastique par
   construction : on autorise le retour à la ligne, on laisse le
   bouton prendre toute la largeur, et rien ne dépend de la fenêtre. */



/* La phrase sous la question : plus petite et plus discrète que la
   question elle-même, qui est ce qui oriente. Un filet court la
   sépare du titre, comme une respiration. */
.greeting__note {
  margin-top: var(--s-1);
  padding-top: var(--s-2);
  border-top: 2px solid var(--action);
  display: inline-block;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--ink-soft);
}


/* ------------------------------------------------------------
   L'ACCUEIL REMPLIT LA HAUTEUR

   La page est plus courte que l'écran depuis que les dernières
   parties ont quitté l'accueil : restait un grand vide entre le
   dernier bloc et le menu.

   Plutôt que de combler ce vide avec du contenu qui existe déjà
   ailleurs, on laisse les deux portes s'étirer. Elles gagnent en
   photo, ce qui les rend plus engageantes, et le vide disparaît.

   Les bornes comptent : la photo ne descend jamais sous 120 px, où
   elle ne montrerait plus rien, ni au-dessus de 260 px, où la carte
   deviendrait une affiche sur une tablette.
   ------------------------------------------------------------ */

/* CENTRÉ QUAND IL RESTE DE LA PLACE.

   Sur un téléphone, le contenu remplit l'écran et cette règle ne
   change rien. Sur une fenêtre de bureau, deux fois plus haute, tout
   l'excédent s'accumule d'un seul côté : une colonne de vide entre
   le dernier bloc et le bas de l'écran.

   Centré, l'excédent se partage entre le haut et le bas. Il ne
   disparaît pas — il ne peut pas, la fenêtre est plus haute que le
   contenu — mais il cesse de se lire comme un oubli.

   Classe RÉUTILISABLE : tout écran plus court que la fenêtre en a
   besoin, pas seulement l'accueil.

   ⚠ `safe` N'EST PAS UNE COQUETTERIE.

   Un conteneur flexible centré dont le contenu DÉBORDE déborde des
   deux côtés à parts égales — y compris par le haut, où il n'existe
   aucun défilement négatif pour aller le rechercher. Le premier
   élément de la page devenait alors définitivement inatteignable.

   Sur cet écran, c'est le premier joueur qui disparaissait, et avec
   lui l'avertissement « il manque un joueur » : le bouton de
   lancement semblait bloqué alors qu'il répondait, en affichant un
   message dans une zone hors d'atteinte.

   `safe center` centre tant que ça tient, et repasse en alignement
   haut dès que ça déborde. La déclaration simple qui précède sert de
   repli pour les navigateurs qui ignorent le mot-clé. */
.screen__body--centre {
  display: flex;
  flex-direction: column;
  justify-content: center;
  justify-content: safe center;
  gap: var(--s-3);
  /* Place réservée à l'horizon, qui se dessine par-dessus le bas de
     l'écran. Sans elle, le dernier élément de la page passe dessous
     et devient invisible. */
  padding-bottom: 80px;
}

/* L'ACCUEIL PART DU HAUT, IL N'EST PLUS CENTRÉ.

   Il partageait le centrage de l'écran ci-dessus. Tant que la
   signature du sponsor occupait le bas, le compte tombait juste.
   Elle est partie, le contenu a raccourci de soixante-douze pixels,
   et le centrage a réparti le vide EN DEUX : mesuré sur iPhone 15,
   soixante-douze pixels au-dessus de « Bonjour » et cinquante-six
   sous les cartes. Sur un Pro Max, cent onze au-dessus.

   Un vide en haut d'écran repousse le titre vers le milieu de la
   page sans rien apporter. Aligné en haut, le même vide tombe une
   seule fois, tout en bas, au-dessus des collines — là où il ne
   sépare plus rien et où le décor le remplit. C'est exactement
   l'argument déjà écrit pour .homeblock, qui ne valait pas moins
   ici.

   Effet secondaire : le défaut du centrage — un contenu trop haut
   qui déborde par le HAUT, hors d'atteinte du défilement — ne peut
   plus se produire du tout sur cet écran. */
.screen__body--home {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: var(--s-2);

  /* 64 px : la hauteur du bandeau de collines, plus huit.

     C'était 80, soit vingt-quatre pixels de dégagement au-dessus
     d'un bandeau qui en fait cinquante-six. Huit suffisent à ce que
     rien ne touche les arbres, et les seize récupérés servent
     ailleurs — là où ils manquaient vraiment. */
  padding-bottom: 64px;
}

/* PLUS AUCUN ÉTIREMENT. LES CARTES FONT LEUR TAILLE.

   J'ai essayé deux fois de leur faire remplir la hauteur libre, et
   les deux fois le surplus a resurgi ailleurs : d'abord dans le
   corps de la carte, sous le texte, puis entre les cartes et la
   ligne de reprise — un plafond ne fait pas disparaître l'excédent,
   il le déplace.

   Les cartes prennent donc la hauteur de leur contenu. L'espace qui
   reste tombe une seule fois, tout en bas, au-dessus de l'horizon,
   là où il ne sépare plus rien. Un vide en fin de page est une marge ;
   un vide au milieu est un défaut. */
.homeblock {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}


/* L'écran Jeux est court : sa liste commence tout de suite après le
   titre. Le rembourrage standard du corps y ajoutait un palier vide
   entre « Jeux » et « Choisir un jeu ».

   En bas, il réserve la place du bandeau d'horizon, comme l'accueil.
   Sans elle, sur un petit écran, la troisième carte passait dessous
   et devenait invisible — le même défaut que le lien d'abandon la
   semaine passée, au même endroit et pour la même raison. */
.screen__body--jeux {
  padding-top: var(--s-2);
  /* Même réserve que l'accueil : le bandeau fait 56 px, on garde une
     marge au-dessus de ses collines. */
  padding-bottom: 80px;
}


/* ------------------------------------------------------------
   ÉCRAN DE PRÉPARATION D'UNE PARTIE
   ------------------------------------------------------------ */

/* UN SEUL PANNEAU pour tous les joueurs. Trois cadres empilés se
   lisent comme trois choses sans rapport ; un panneau dit « voici le
   groupe », les filets disent « voici les personnes ». */
.playerpanel {
  border-radius: var(--r-lg);
  background: var(--paper-raised);
  border: var(--border);
  overflow: hidden;
}

.playercard { padding: var(--s-3); }

/* Un filet, pas un cadre : les joueurs se suivent dans un même
   ensemble au lieu de flotter séparément. */
.playercard + .playercard { border-top: var(--border); }

/* TOUT CE QUI APPARTIENT AU JOUEUR S'ALIGNE SOUS SON PRÉNOM.

   30 px de pastille plus 12 px d'écart : c'est exactement de combien
   le champ du prénom est décalé vers la droite. Sans cette
   indentation, les coups reçus et les repères repartaient du bord de
   la carte, et le bloc comptait trois bords gauches différents.

   Écrire la valeur en dur serait fragile — elle est donc calculée à
   partir des mêmes jetons que la pastille et l'écart. */
.playercard__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-left: calc(30px + var(--s-3));
  margin-top: var(--s-2);
}

.playercard__body:empty { display: none; }

/* Le numéro : un repère de position, pas une valeur. Pastille pleine
   dans le vert profond, comme les marques des jeux. Sa largeur — 30 px
   — est reprise par l'indentation du corps ci-dessus. */
.playercard__num {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: var(--r-pill);
  background: var(--action-deep);
  color: #FFFFFF;
  font-size: var(--t-sm);
  font-weight: var(--w-black);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Titre de section : une marque, un mot. La marque dit la nature de
   ce qui suit — des gens, un format, un lieu — avant que le mot soit
   lu. */
.sectiontitle {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--action-deep);
}

.sectiontitle__mark {
  flex: none;
  width: 17px;
  height: 17px;
}

.sectiontitle__mark svg { width: 100%; height: 100%; display: block; }

/* Marque à l'intérieur d'un bouton : elle précède le mot et prend sa
   couleur, donc elle suit l'état du bouton sans réglage. */
.btn__mark {
  flex: none;
  width: 19px;
  height: 19px;
  margin-right: var(--s-1);
}

.btn__mark svg { width: 100%; height: 100%; display: block; }


/* ------------------------------------------------------------
   PANNEAU DES RÈGLES D'UN JEU

   Un barème se lit en tableau : trois colonnes, la valeur alignée à
   droite. C'est la colonne des points que l'œil parcourt, et elle
   doit tomber au même endroit d'une ligne à l'autre.
   ------------------------------------------------------------ */

.rules {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.rules__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-2);
}

.rules__title {
  font-size: var(--t-xl);
  font-weight: var(--w-black);
  letter-spacing: var(--track-tight);
  line-height: 1.1;
}

/* La variante est annoncée, pas cachée : elle dit que ce barème est
   un choix de l'app et non une règle universelle. */
.rules__variant {
  padding: var(--s-1) var(--s-3);
  border-radius: var(--r-pill);
  border: 1.5px solid var(--action-deep);
  color: var(--action-deep);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.rules__intro {
  font-size: var(--t-base);
  line-height: 1.5;
  color: var(--ink);
}

.rules__card {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-4);
  border-radius: var(--r-lg);
  background: var(--paper-raised);
  border: var(--border);
}

.rules__row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) 0;
}

.rules__row + .rules__row { border-top: var(--border); }

/* La place, en pastille : elle se compare d'un coup d'œil sans être
   lue. Une médaille dessinée ferait la même chose en dix fois plus
   lourd. */
.rules__rank {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: var(--r-pill);
  background: var(--paper-sunk);
  color: var(--ink-soft);
  font-size: var(--t-sm);
  font-weight: var(--w-black);
  display: flex;
  align-items: center;
  justify-content: center;
}

.rules__row--best .rules__rank {
  background: var(--action);
  color: var(--action-ink);
}

.rules__text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  font-size: var(--t-sm);
}

.rules__desc { color: var(--ink-soft); font-size: var(--t-xs); }

/* La valeur : largeur fixe pour que la colonne s'aligne, quelle que
   soit la longueur du libellé à sa gauche. */
.rules__pts {
  flex: none;
  width: 64px;
  padding: var(--s-2) 0;
  border-radius: var(--r-md);
  background: var(--paper-sunk);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.rules__row--best .rules__pts { background: var(--action-soft); }

.rules__ptsnum {
  font-size: var(--t-lg);
  font-weight: var(--w-black);
  line-height: 1.1;
}

.rules__ptsunit {
  font-size: 0.62rem;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-soft);
}

.rules__lead { font-size: var(--t-sm); color: var(--ink); }

.rules__list {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  font-size: var(--t-sm);
  color: var(--ink-soft);
  line-height: 1.45;
}

/* Puce dessinée en CSS : la liste native est neutralisée par le
   reset de base.css. */
.rules__list li { padding-left: var(--s-4); position: relative; }

.rules__list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 5px;
  height: 5px;
  border-radius: var(--r-pill);
  background: var(--action-deep);
}

.rules__source {
  font-size: var(--t-sm);
  line-height: 1.45;
  color: var(--ink-soft);
}

.rules__link {
  align-self: flex-start;
  color: var(--action-deep);
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
}


/* ------------------------------------------------------------
   LA LIGNE DE RÉGLAGE D'UN JOUEUR

   Coups reçus et repère de départ, côte à côte sous le prénom. Ils
   occupaient deux étages entiers — un champ, puis six pastilles —
   soit près de deux cents pixels par joueur. À trois joueurs, la
   moitié de l'écran partait avant le format et le parcours.
   ------------------------------------------------------------ */

.playerline {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-2);
  padding-left: calc(30px + var(--s-3));
}

.playerline__field {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* Une donnée secondaire : le libellé ne doit pas peser autant que le
   prénom, qui est le vrai sujet de la ligne. */
.playerline__label {
  font-size: var(--t-xs);
  color: var(--ink-soft);
  white-space: nowrap;
}

/* Champ réduit à ce qu'il contient : deux chiffres. Étalé sur 180 px,
   il annonçait une saisie longue pour un nombre à un chiffre. */
.playerline input[type="number"] {
  width: 62px;
  min-height: 38px;
  padding: 0 var(--s-2);
  text-align: center;
  font-weight: var(--w-semi);
}

.playerline__sep {
  width: 1px;
  align-self: stretch;
  background: var(--rule);
}

.playerline__tee {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 38px;
  padding: 0 var(--s-2);
  border-radius: var(--r-md);
}

.playerline__tee:active { background: var(--paper-sunk); }

.playerline__teename {
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
  color: var(--ink);
}

.playerline__chev {
  font-size: var(--t-base);
  line-height: 1;
  color: var(--ink-faint);
}

/* La pastille de couleur : c'est elle qui porte l'information, le nom
   ne fait que la confirmer. Contour vert foncé fin plutôt qu'un gros
   cerne noir — le noir n'appartient à aucune autre partie de l'app. */
.teedot--pick {
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: var(--r-pill);
  background: var(--tee-color, #FFFFFF);
  border: 1.5px solid var(--action-deep);
}

/* ------------------------------------------------------------
   FEUILLE DE CHOIX DU REPÈRE

   Six lignes nommées plutôt que six lettres. « W » ne dit rien à
   personne ; « Blanc — repère de compétition » dit tout, et à qui il
   s'adresse.
   ------------------------------------------------------------ */

.teelist {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  margin-top: var(--s-3);
}

.teerow {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: var(--touch-min);
  padding: 0 var(--s-3);
  border-radius: var(--r-md);
  border: 1.5px solid transparent;
  text-align: left;
}

.teerow--on {
  background: var(--action-soft);
  border-color: var(--action-deep);
}

.teerow__label {
  font-size: var(--t-sm);
  color: var(--ink);
}

.teerow--on .teerow__label { font-weight: var(--w-semi); }

/* ------------------------------------------------------------
   EN-TÊTE ET APPEL À L'ACTION, RESSERRÉS

   L'en-tête prenait le quart de l'écran et le bouton de lancement
   soixante-seize pixels. Le titre du jeu doit rester ce qu'on voit ;
   le reste doit lui laisser la place.
   ------------------------------------------------------------ */

.screen__head--paysage { padding-bottom: var(--s-4); }

.screen__head--paysage .screen__title,
.screen__head--paysage h1 { font-size: var(--t-xl); }

.screen__foot .btn--xl { min-height: 60px; }

/* Les deux boutons de format partagent la largeur et cèdent avant la
   colonne : sur un iPhone SE, « 18 trous » avec sa marque et son
   interlettrage dépassait de dix pixels. Un bouton qui rétrécit reste
   lisible ; un bouton qui sort de l'écran est perdu. */
.row > .btn { min-width: 0; }


/* ============================================================
   LE PANNEAU D'AIDE — ACCORDÉON

   Mesuré avant : 4564 px de contenu pour 699 px visibles. Sept
   écrans d'un seul tenant. Replié, l'ensemble tient sur un écran.

   Ces règles ne portent QUE sur `.sheet--aide`. La feuille du bas
   ordinaire — règles d'un jeu, boîtes de confirmation — n'est pas
   touchée : elle n'a pas le même problème et n'appelle pas le même
   remède.
   ============================================================ */

/* La feuille devient un panneau : pleine hauteur, sans rembourrage
   propre — chaque bande gère le sien, sinon l'en-tête collant et le
   bandeau de collines ne peuvent pas toucher les bords. */
.sheet--aide {
  top: max(3dvh, env(safe-area-inset-top));
  bottom: 0;
  padding: 0;
  overflow-y: auto;
  max-height: none;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--paper);
}

/* L'EN-TÊTE NE PART PAS AVEC LE DÉFILEMENT.

   Le bouton « Fermer » vivait tout en bas du contenu. Avec huit
   fiches dépliées, il se retrouvait à sept écrans de distance : on
   sortait du panneau en tapant à côté, faute de le trouver. Une
   croix collante en haut à droite est toujours à portée de pouce. */
.aide__tete {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-4);
  background: var(--paper);
  border-bottom: var(--border);
}

.aide__fermer {
  position: absolute;
  right: var(--s-4);
  width: 36px;
  height: 36px;
  border-radius: var(--r-pill);
  background: var(--action-deep);
  color: var(--action-ink);
  display: flex;
  align-items: center;
  justify-content: center;
}

.aide__fermermarque { display: flex; }

.aide__fermer svg { width: 18px; height: 18px; }

/* UN SVG EST UNE LETTRE, PAS UNE IMAGE.

   Mesuré : la croix de fermeture était trois pixels au-dessus du
   centre de sa pastille. Les quatre autres marques du panneau
   tombaient à zéro. La différence : leur enveloppe portait une
   classe avec `display: flex`, celle de la croix n'en avait pas.

   Par défaut un <svg> est en ligne, donc posé sur la ligne de base
   du texte, avec dessous la place réservée aux jambages du p et du
   g. Cette place fait partie de l'enveloppe. Centrer l'enveloppe
   centre donc le dessin ET son vide, ce qui remonte le dessin.

   Une seule règle, à la racine du panneau, plutôt qu'une correction
   sur la croix : ce n'est pas un défaut de la croix, c'est le
   comportement par défaut du navigateur, et il se reproduira sur la
   prochaine marque qu'on ajoutera. */
.sheet--aide svg { display: block; }

/* LE BANDEAU DE COLLINES EST LE MÊME QU'AILLEURS.

   `imgMenu.webp` sert déjà de ligne d'horizon au-dessus du menu et
   de fond aux en-têtes paysage. Le reprendre ici coûte zéro octet —
   l'image est déjà en cache — et rattache le panneau à l'app au lieu
   d'en faire une fenêtre étrangère.

   `multiply` marie son blanc cassé au fond craie sans découpe à
   maintenir. Même traitement que .tabbar--horizon. */
.aide__hero {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  /* 56 px en bas, exactement la hauteur du bandeau : le texte ne
     doit jamais entrer dans les collines. C'est LA valeur de
     référence, la même que .tabbar--horizon et que la réserve du
     corps de l'accueil. Trois endroits, un seul nombre. */
  padding: var(--s-2) var(--s-4) 56px;
}

.aide__hero::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 56px;
  background-image: url('../assets/imgMenu.webp');
  background-size: 100% 100%;
  background-position: center bottom;
  background-repeat: no-repeat;
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* 44 px, et non 48. LES QUATRE PIXELS COMPTENT ICI.

   Objectif mesuré : que les huit questions repliées tiennent sur un
   écran, sans défiler. Sur iPhone 15 la huitième dépassait de quatre
   pixels — assez pour qu'on croie qu'il n'y en a que sept. Le hero
   est décoratif, la liste ne l'est pas : c'est le hero qui cède. */
.aide__heromarque {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: var(--r-pill);
  background: var(--action);
  color: var(--action-ink);
  display: flex;
  align-items: center;
  justify-content: center;
}

.aide__heromarque svg { width: 26px; height: 26px; }

.aide__titre { font-size: var(--t-xl); }

.aide__lede {
  margin-top: var(--s-1);
  font-size: var(--t-sm);
  color: var(--ink-soft);
}

.aide__liste {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-4) var(--s-4);
}

/* ------------------------------------------------------------
   UNE FICHE

   LA COULEUR CLASSE, ELLE NE DÉCORE PAS.

   Le modèle proposait huit pastilles de huit teintes, dont un violet
   et un orange qui n'existent nulle part dans l'application. Huit
   couleurs, c'est huit choses à retenir — et tokens.css interdit
   d'ajouter des teintes saturées à côté du vert d'action.

   Les pastilles reprennent donc les quatre familles déjà en place,
   et chacune veut dire quelque chose :

     vert    — ce que fait l'app, et le jeu qui se passe bien
     rouge   — ce qui coûte des coups
     ardoise — ce qui demande une procédure ou une carte officielle
     ambre   — ce qui interrompt le trou, ou se lit après

   Quatre familles se retiennent, huit teintes non. Le modèle
   répétait d'ailleurs déjà le vert trois fois.
   ------------------------------------------------------------ */

.fiche {
  border: var(--border);
  border-radius: var(--r-lg);
  background: var(--paper-raised);
  overflow: hidden;
}

/* La fiche ouverte se détache : contour à sa couleur, pas une ombre.
   Une ombre sur fond craie se voit à peine en plein soleil. */
.fiche[open] {
  border-color: currentColor;
  background: var(--paper);
}

/* HAUTEUR FIXE, ET LE TITRE PEUT PASSER À LA LIGNE.

   Mesuré : la largeur utile d'une tête est de 251 px sur un iPhone
   15, et « Les bons réflexes sur le parcours » en demande 299 à la
   taille de base. Aucun réglage de police ne fait tenir les huit
   libellés du modèle sur une ligne à cette largeur — c'est un fait
   de mesure, pas un choix.

   J'ai d'abord raccourci les libellés. Mauvaise réponse : ce sont
   les mots que le modèle demande. La bonne réponse est de découpler
   la hauteur de la RANGÉE de la longueur du TEXTE.

   La rangée fait donc 80 px, toujours, et son contenu est centré
   dedans. Un titre d'une ligne et un titre de deux lignes occupent
   la même rangée. La liste redevient régulière sans qu'aucun mot
   n'ait à être coupé. */
.fiche__tete {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  /* 88 px : la hauteur du pire cas, titre sur deux lignes ET
     sous-titre sur deux lignes, mesuré à 84,4 px. La rangée la
     contient au lieu de la subir.

     Chiffres à l'origine de ce nombre, sur un écran de 375 px où la
     largeur utile tombe à 233 : « Les bons réflexes sur le
     parcours » demande 261 px, « Sécurité, rythme de jeu et respect
     des autres » en demande 273. Ni une taille de police plus petite
     ni une pastille plus étroite ne rattrapent quarante pixels. Ces
     libellés passent donc à la ligne, et la rangée ne bouge pas.

     88 était le calcul, 92 est la mesure : la huitième rangée sortait
     à 89,4 px sur tout ce qui est plus étroit qu'un Pro Max, parce
     que le calcul oubliait le pixel d'écart entre titre et
     sous-titre et arrondissait les interlignes vers le bas. Un
     nombre calculé n'est pas un nombre mesuré ; c'est le rendu qui
     tranche. */
  min-height: 92px;
  cursor: pointer;
  list-style: none;
}

/* Safari dessine son propre triangle devant <summary> et ignore
   `list-style`. Sans cette ligne, la pastille arrive décalée de
   quinze pixels sur iPhone et sur rien d'autre. */
.fiche__tete::-webkit-details-marker { display: none; }

.fiche__marque {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: var(--r-pill);
  background: currentColor;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* La marque est blanche SUR la pastille : le fond prend la couleur
   de la fiche par `currentColor`, le tracé reprend l'encre claire. */
.fiche__marque svg {
  width: 21px;
  height: 21px;
  color: var(--paper-raised);
}

.fiche__mots {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.fiche__titre {
  font-weight: var(--w-semi);
  color: var(--ink);
  line-height: 1.25;
}

/* Deux lignes au maximum. Au-delà, la rangée de 80 px déborderait et
   la liste redeviendrait irrégulière — le défaut qu'on vient de
   corriger. Aucun libellé actuel n'en demande trois ; si l'un le
   demandait un jour, c'est le libellé qu'il faudrait revoir. */
.fiche__titre {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* UNE SEULE LIGNE, TOUJOURS.

   Rendu et mesuré : les huit têtes faisaient 64, 83, 81 et 101 px
   selon que leur sous-titre tenait sur une ou deux lignes. Une liste
   dont les rangées n'ont pas la même hauteur ne se parcourt plus, on
   la lit. Les sous-titres ont donc été raccourcis dans rules.js pour
   tenir sur une ligne à 393 px.

   La troncature ci-dessous est un garde-fou, pas la solution : si
   elle se déclenche, c'est qu'un sous-titre est trop long et qu'il
   faut le réécrire, pas l'afficher coupé. */
/* DEUX LIGNES ICI AUSSI, ET SURTOUT PAS DE TRONCATURE.

   Le sous-titre a d'abord été coupé aux points de suspension. Rendu
   sur quatre appareils, le résultat parlait de lui-même :
   « Sécurité, rythme de jeu et respect des autres » devenait
   « Sécurité, rythme de jeu et respect des… » sur tout ce qui est
   plus étroit qu'un Pro Max. Une phrase amputée en fin de ligne est
   pire qu'une phrase sur deux lignes.

   Elle passe donc à la ligne, dans une rangée dimensionnée pour ça. */
.fiche__lede {
  font-size: var(--t-xs);
  color: var(--ink-soft);
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.fiche__chevron {
  flex: 0 0 auto;
  color: var(--ink-faint);
  display: flex;
  transition: transform var(--dur-base) var(--ease);
}

.fiche__chevron svg { width: 20px; height: 20px; }

.fiche[open] .fiche__chevron { transform: rotate(180deg); }

.fiche__corps {
  margin: 0 var(--s-3) var(--s-3);
  border: var(--border);
  border-radius: var(--r-md);
  background: var(--paper-raised);
}

.fiche__liste {
  display: flex;
  flex-direction: column;
}

/* Un filet entre les lignes, pas un cadre autour de chacune : les
   points se suivent dans une même réponse. Même parti que
   .playercard, où trois cadres empilés se lisaient comme trois
   choses sans rapport. */
.fiche__ligne {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-3);
}

.fiche__ligne + .fiche__ligne { border-top: var(--border); }

.fiche__ligne--nue { padding-left: var(--s-4); }

.fiche__puce {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: currentColor;
  display: flex;
  /* Alignée sur la PREMIÈRE ligne du texte, pas sur le bloc : sur un
     point de trois lignes, un centrage vertical posait la marque au
     milieu du paragraphe, loin de son début. */
  margin-top: 1px;
}

.fiche__puce svg { width: 22px; height: 22px; }

.fiche__texte {
  flex: 1;
  min-width: 0;
  font-size: var(--t-sm);
  line-height: 1.45;
  color: var(--ink);
}

.fiche__texte strong { font-weight: var(--w-semi); }

/* La source ferme la fiche, sur le fond creux : elle se distingue
   des points sans les concurrencer. */
.fiche__source {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-1);
  padding: var(--s-3);
  border-top: var(--border);
  background: var(--paper-sunk);
  font-size: var(--t-xs);
  color: var(--ink-soft);
  border-radius: 0 0 var(--r-md) var(--r-md);
}

/* ---------- Les huit teintes -------------------------------

   Une par fiche. La classe ne fixe que `color` : la pastille s'en
   sert comme fond, le contour de la fiche ouverte comme bordure, et
   les marques de ligne comme encre. Une seule déclaration commande
   les trois — c'est ce qui garantit qu'une fiche ne peut pas avoir
   une pastille d'une couleur et un contour d'une autre.

   Les valeurs vivent dans tokens.css, avec l'explication de
   l'exception qu'elles constituent.
   ------------------------------------------------------------ */

/* Repli : une fiche sans tonalité déclarée retombe sur le vert. */
.fiche { color: var(--aide-compter); }

.fiche--compter   { color: var(--aide-compter); }
.fiche--penalite  { color: var(--aide-penalite); }
.fiche--perdue    { color: var(--aide-perdue); }
.fiche--ramasse   { color: var(--aide-ramasse); }
.fiche--par       { color: var(--aide-par); }
.fiche--marqueur  { color: var(--aide-marqueur); }
.fiche--carte     { color: var(--aide-carte); }
.fiche--reflexes  { color: var(--aide-reflexes); }

/* ------------------------------------------------------------
   LE BAS DU PANNEAU

   Il ne remplace pas les sources posées dans les fiches. Celles-ci
   disent d'où vient une procédure précise ; celui-ci dit ce que
   l'app n'est pas. Les deux ne se substituent pas l'un à l'autre.
   ------------------------------------------------------------ */

.aide__pied {
  margin: 0 var(--s-4) calc(var(--s-4) + env(safe-area-inset-bottom));
  padding: var(--s-3);
  border: var(--border);
  border-radius: var(--r-lg);
  background: var(--action-soft);
}

.aide__avis {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
}

.aide__avismarque {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  color: var(--action-deep);
  display: flex;
}

.aide__avismarque svg { width: 26px; height: 26px; }

.aide__avistexte {
  font-size: var(--t-xs);
  line-height: 1.5;
  color: var(--ink-soft);
}

/* Une mention de service : lisible si on la cherche, invisible si on
   ne la cherche pas. */
.aide__version {
  margin-top: var(--s-2);
  font-size: var(--t-xs);
  color: var(--ink-faint);
}

.aide__liens {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1.5px solid var(--action-deep);
}

.aide__lien {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 34px;
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  color: var(--action-deep);
  text-decoration: none;
}

/* Le lien d'une source prend la couleur de sa fiche, pas le vert du
   bas de page : il appartient à la réponse qu'il justifie. */
.fiche__lien {
  color: currentColor;
  margin-top: var(--s-1);
}

.aide__lienmarque { display: flex; }
.aide__lienmarque svg { width: 15px; height: 15px; }


/* ============================================================
   LA BARRE DE DÉFILEMENT

   Voir indiquerDefilement() dans dom.js pour le mécanisme. Ici, elle
   doit répondre à une seule question : « y a-t-il autre chose plus
   bas ? » — et y répondre AVANT qu'on ait touché l'écran.

   Elle est donc franchement visible : 6 px de large, un curseur à
   l'encre du texte secondaire sur un filet de la couleur des règles
   de la carte. Une barre discrète n'aurait rien réglé, puisque le
   défaut était précisément qu'on ne la voyait pas.
   ============================================================ */

/* ------------------------------------------------------------
   CELLE DU NAVIGATEUR S'EFFACE, LA NÔTRE RESTE

   Deux barres parallèles à droite de l'écran : la nôtre, posée dans
   la colonne, et celle du navigateur, collée au bord de la fenêtre.

   On ne peut pas garder les deux. Et c'est la nôtre qui doit rester,
   parce qu'elle est la seule à répondre à la question posée : celle
   du navigateur n'apparaît que PENDANT le geste sur mobile, donc
   uniquement à qui sait déjà qu'il peut faire ce geste.

   `scrollbar-width: none` traite Firefox et les Chrome récents,
   `::-webkit-scrollbar` couvre Safari et les WebKit plus anciens. Il
   faut les deux : aucun des deux n'est universel.

   ATTENTION — CE N'EST PAS `overflow: hidden`.

   La barre disparaît, le défilement reste entier : au doigt, à la
   molette, au clavier, et pour le lecteur d'écran. Masquer la barre
   et supprimer le défilement se ressemblent dans le code et n'ont
   rien à voir dans les faits — le second enfermerait l'utilisateur
   en bas de page.

   Portée volontairement étroite : les corps d'écran, les feuilles du
   bas, le panneau d'aide. Pas le document entier, pour ne pas priver
   d'ascenseur une page qu'on n'aurait pas regardée.
   ------------------------------------------------------------ */
.screen__body,
.sheet,
.sheet--aide {
  scrollbar-width: none;          /* Firefox, Chrome récents */
  -ms-overflow-style: none;       /* anciens Edge            */
}

.screen__body::-webkit-scrollbar,
.sheet::-webkit-scrollbar,
.sheet--aide::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;                  /* Safari, WebKit          */
}

/* La barre se cale sur .screen, qui devient donc son repère.
   Sans cette ligne elle se positionnerait par rapport à #app et
   passerait sous la barre du bas. */
.screen { position: relative; }

.defil {
  position: absolute;
  right: 5px;
  width: 6px;
  border-radius: var(--r-pill);
  background: var(--rule);

  /* Elle ne prend jamais le doigt : le geste appartient au contenu.
     C'est un indicateur, pas une poignée — on ne tire pas une barre
     de défilement au pouce sur un téléphone. */
  pointer-events: none;
  z-index: 5;
}

/* L'ENCRE DU CURSEUR EST CELLE DU TEXTE SECONDAIRE, PAS UN GRIS PÂLE.

   Premier essai avec --ink-faint, la teinte des placeholders : rendu
   et regardé, on ne la distinguait pas du fond. Une barre qu'on ne
   voit pas ne règle pas un problème qui est précisément qu'on ne
   voit pas la barre.

   --ink-soft est la même encre que « Que voulez-vous faire
   aujourd'hui ? ». Si ce texte se lit, la barre se voit. */
.defil__curseur {
  width: 100%;
  border-radius: var(--r-pill);
  background: var(--ink-soft);

  /* AUCUNE TRANSITION, ET C'EST UN REVIREMENT.

     Elle valait 80 ms, pour lisser un déplacement supposé saccadé.
     Mauvais calcul sur iOS : pendant l'inertie, les événements de
     défilement n'arrivent pas à chaque image. Une transition
     par-dessus un signal déjà irrégulier ne lisse rien — elle fait
     traîner le curseur derrière le contenu, ce qui se voit comme une
     traînée sur le côté.

     Sans transition, le curseur est exactement là où le contenu se
     trouve, à l'image près. Le déplacement paraît moins doux sur le
     papier, et plus juste à l'œil. */
  will-change: transform;
}




/* ============================================================
   LE PIED DE L'ÉCRAN DU PARCOURS VIT DANS LE CONTENU

   Terminer et Annuler ne servent qu'une fois dans une partie de
   dix-huit trous, et ils occupaient 117 px fixes — la moitié de ce
   qui restait au compteur sur un iPhone 13.

   Marges négatives pour toucher les deux bords malgré le
   rembourrage du corps, et marge basse annulée : c'est le dernier
   bloc de la page, rien ne le suit.
   ============================================================ */
.screen__foot--dansCorps {
  margin: var(--s-4) calc(var(--s-4) * -1) calc(var(--s-4) * -1);
  border-top: var(--border);
  border-bottom: none;

  /* TERMINER ET ANNULER S'ALIGNENT SUR VALIDER ET RAMASSÉ.

     Mesuré : 13 px d'écart de chaque côté, vers l'extérieur. Le
     décalage se voyait d'autant mieux que les quatre boutons ont
     désormais le même gabarit — l'œil compare ce qui se ressemble.

     La cause est une différence de profondeur. Les boutons de la
     carte sont enfouis de trois niveaux : rembourrage du corps,
     rembourrage de la carte, épaisseur de son contour. Ceux du pied
     n'en traversent qu'un. Ils partaient donc à 16 px du bord quand
     les autres partaient à 29.

     Le calcul reprend ces trois termes plutôt qu'un 29 posé à la
     main : si le rembourrage de la carte change un jour, le pied
     suivra. Un nombre magique se serait décorrélé au premier
     ajustement. */
  padding-left: calc(var(--s-4) + var(--s-3) + 1.5px);
  padding-right: calc(var(--s-4) + var(--s-3) + 1.5px);
}
