/* Wander — ce qui est propre à cette app.
   Tout le reste vient de workbench.css, chargé avant celle-ci.
   Ne rien ajouter ici qui aurait sa place dans Workbench : les corrections du
   socle remontent à ~/projects/perso/workbench. */

/* --- L'accent : bleu « tpg », repris tel quel de css/accents/tpg.css ----- */
/* Paire prête et déjà vérifiée au contraste dans les deux thèmes (voir
   l'en-tête de la source) : pas de nouvelle vérification à faire ici tant
   que ces valeurs ne bougent pas.

     clair   blanc sur bleu   5,69:1   bleu sur fond    5,31:1
     sombre  encre sur bleu   6,60:1   bleu sur fond    6,78:1 */
:root {
  --accent: #0a66c2;
  --accent-tx: #ffffff;
  --accent-soft: #e8f0fd;
  --accent-line: #c5d9f5;
  --ring: rgba(10, 102, 194, .30);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --accent: #3d9bff;
    --accent-tx: #04121f;
    --accent-soft: #101f33;
    --accent-line: #1e3a5c;
    --ring: rgba(61, 155, 255, .32);
  }
}
:root[data-theme="dark"] {
  --accent: #3d9bff;
  --accent-tx: #04121f;
  --accent-soft: #101f33;
  --accent-line: #1e3a5c;
  --ring: rgba(61, 155, 255, .32);
}

/* Jalons numérotés du parcours. Cliquer amène à la fiche de l'étape : le
   curseur et l'agrandissement au survol le disent, faute de quoi rien ne
   distingue une pastille décorative d'une pastille active. */
.jalon span {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--accent); color: var(--accent-tx);
  font-weight: 600; font-size: 0.85rem;
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.35);
  cursor: pointer;
  transition: transform .12s, box-shadow .12s;
}
.jalon:hover span, .jalon:focus-visible span {
  transform: scale(1.18);
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.45);
}

/* --- Ma position ----------------------------------------------------------
   Le bleu est FIXE, il ne suit ni le thème ni l'accent : c'est la convention
   que toutes les cartes du monde utilisent pour « moi », et la teindre en
   couleur d'accent la ferait passer pour un jalon de plus. */
.ma-position span {
  display: block; width: 18px; height: 18px; border-radius: 50%;
  background: #1a73e8;
  border: 3px solid #fff;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.25), 0 1px 4px rgb(0 0 0 / 0.4);
}
/* Le halo d'incertitude. Assez pâle pour qu'on lise les rues au travers : il
   informe, il ne cache pas le plan. */
.halo-position {
  fill: #1a73e8; fill-opacity: 0.12;
  stroke: #1a73e8; stroke-opacity: 0.35; stroke-width: 1;
}

.boite-geoloc { background: none; border: none; }
.bouton-geoloc {
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  background: var(--surface-hi); color: var(--tx);
  border: none; border-radius: var(--r-s); cursor: pointer;
  font-size: 1.15rem; line-height: 1;
}
.bouton-geoloc:hover { background: var(--surface); }
/* Le seul retour visible pendant qu'on attend le capteur : sans lui, un
   premier point qui met dix secondes à venir donne un bouton mort. */
.bouton-geoloc.cherche span { animation: pulse-geoloc 1s ease-in-out infinite; }
.bouton-geoloc.en-echec { color: var(--danger); }
@keyframes pulse-geoloc {
  50% { opacity: 0.3; }
}
/* Une animation qui clignote est exactement ce que ce réglage système demande
   d'éviter ; l'état reste lisible par le curseur d'attente du bouton. */
@media (prefers-reduced-motion: reduce) {
  .bouton-geoloc.cherche span { animation: none; }
}

/* --- En-tête de la visite -------------------------------------------------
   Titre à gauche, actions secondaires à droite et SUR UNE LIGNE. Empilées en
   blocs pleine largeur, elles pesaient autant que le contenu de la page alors
   qu'on y touche deux fois par visite. */
.entete-visite {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  justify-content: space-between; gap: var(--e-3);
}
.entete-visite h1 { margin-bottom: var(--e-1); }
.entete-visite .meta { margin: 0; }
.actions-visite { display: flex; flex-wrap: wrap; gap: var(--e-2); }
/* Sous 640px, les actions passent sous le titre et s'étalent : viser un
   bouton étroit au pouce est le premier confort qu'on perd sur téléphone. */
@media (max-width: 640px) {
  .actions-visite { width: 100%; }
  .actions-visite form { flex: 1 1 auto; }
  .actions-visite .bouton { width: 100%; }
}

/* La carte a besoin d'une hauteur explicite : sans elle, Leaflet s'initialise
   dans un conteneur de zéro pixel et n'affiche rien du tout. */
/* `isolation: isolate` n'est PAS cosmétique : Leaflet empile ses couches à
   z-index 400 et ses contrôles à 800, bien au-dessus du panneau d'assistant
   du socle (150). Sans contexte d'empilement propre, la carte passe DEVANT le
   panneau — vu à l'écran : l'assistant s'ouvrait derrière les tuiles. Isolé,
   tous ces 400 restent relatifs à la carte, qui vaut 0 face au panneau. */
#carte {
  height: 55vh; min-height: 320px;
  isolation: isolate;
}

/* Marque une visite publiée dans la liste. Même forme que `.nature` — deux
   pastilles au même endroit qui ne se ressemblent pas se liraient comme deux
   concepts sans rapport. */
.etiquette {
  display: inline-block; margin-left: var(--e-2);
  padding: 0.1rem var(--e-2); border-radius: 999px;
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em;
  border: 1px solid var(--accent-line); color: var(--accent);
  vertical-align: middle;
}

/* --- La proposition en attente -------------------------------------------- */
.proposition { border-color: var(--accent-line); }
.proposition h2 { display: flex; align-items: center; gap: var(--e-2); }
.apercu-proposition { list-style: none; padding: 0; margin: var(--e-3) 0; }
.apercu-proposition li {
  display: flex; align-items: baseline; gap: var(--e-2);
  padding: var(--e-1) 0;
}
.apercu-proposition .nom { font-weight: 600; }

/* --- Les fiches d'étape ---------------------------------------------------
   Le rang à gauche, le corps au milieu, la nature à droite — le patron de
   `restos`, adapté à un parcours ordonné où le numéro remplace la photo. */
.etapes {
  list-style: none; padding: 0;
  /* Les fiches étaient COLLÉES : `.carte` ne porte pas de marge, et sept
     cartes bord à bord se lisent comme un seul bloc où l'on ne distingue plus
     où finit une étape. */
  display: flex; flex-direction: column; gap: var(--e-3);
}
.fiche-etape {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  gap: var(--e-3);
  align-items: start;
  scroll-margin-top: var(--e-5);
}
/* Cible du clic sur un jalon de la carte. L'animation attire l'œil une fois,
   puis s'efface : un surlignage permanent obligerait à le retirer à la main. */
.fiche-etape:target, .fiche-etape.visee {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* `:focus-visible` seulement sur la fiche elle-même : elle porte
   `tabindex="-1"` pour être focalisable par le script, pas au clavier — sans
   cette règle, le focus poserait un contour permanent après chaque clic. */
.fiche-etape:focus { outline: none; }
/* `min-width: 0` : sans lui, une cellule de grille refuse de descendre sous la
   largeur de son plus long mot, et une URL ou un nom composé fait déborder
   toute la fiche horizontalement. */
.fiche-etape .corps { min-width: 0; }
.fiche-etape .nom { margin: 0; font-size: 1.05rem; }
.fiche-etape .meta { margin: var(--e-1) 0 0; }
.fiche-etape .description { margin: var(--e-2) 0 0; }
.rang {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none;
  width: 2rem; height: 2rem; border-radius: 50%;
  background: var(--accent); color: var(--accent-tx);
  font-weight: 600; font-size: 0.9rem;
}
/* La nature d'une étape se lit en un mot. Pas d'icône : le jeu du socle n'a ni
   couvert ni tasse, et en inventer une serait pire que le mot lui-même. */
.nature {
  flex: none;
  padding: 0.15rem var(--e-2); border-radius: 999px;
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em;
  border: 1px solid var(--line); color: var(--tx-2);
}
/* Les trois natures se distinguent, sinon la pastille ne sert qu'à répéter un
   mot qu'on lit déjà. Le repas porte l'accent — c'est le point fixe autour
   duquel une journée s'organise ; la pause s'efface ; la visite est le cas
   courant et garde le trait neutre. */
.nature-visite { /* cas courant : l'allure de base de `.nature` suffit */ }
.nature-repas { border-color: var(--accent-line); color: var(--accent); }
.nature-pause { opacity: 0.7; }
@media (max-width: 640px) {
  /* Sur téléphone, la pastille de nature passe sous le titre : gardée en
     troisième colonne, elle écrase le nom du lieu à deux mots par ligne. */
  .fiche-etape { grid-template-columns: auto 1fr; }
  .fiche-etape .nature { grid-column: 2; justify-self: start; }
}

/* --- Ce que Google Places sait, et qu'OSM ignore ------------------------- */
.qualite { margin: var(--e-2) 0 0; display: flex; align-items: baseline;
           gap: 0.3rem; flex-wrap: wrap; }
.qualite .note { font-weight: 600; color: var(--accent); }
/* Les horaires sont repliés : sept lignes déployées noieraient la fiche, et on
   ne les consulte qu'au moment de décider d'y aller. */
.horaires summary { cursor: pointer; }
.horaires ul { margin: var(--e-1) 0 0; padding-left: var(--e-4);
               font-size: 0.85rem; color: var(--tx-2); }

/* --- Le fil de l'assistant ------------------------------------------------
   Le socle n'a aucun composant de conversation : c'est propre à cette app, ça
   vit donc ici. Ces règles achètent UNE chose — distinguer d'un coup d'œil ce
   qu'on a demandé de ce que l'assistant a répondu. Sans elles, les deux
   étaient des <p> rigoureusement identiques empilés.

   Variables vérifiées avant d'écrire : --e-2/--e-3 et --line viennent de
   workbench.css, --accent-soft et --accent-line de la paire d'accent recopiée
   plus haut dans ce fichier. --fond-2 n'existe pas dans le socle, c'est
   --surface. */
#conversation { display: flex; flex-direction: column; gap: var(--e-2); }
#conversation p { margin: 0; padding: var(--e-2) var(--e-3); border-radius: 8px; }

/* La demande s'aligne à droite et porte l'accent : la convention se lit sans
   qu'on ait à l'expliquer. */
.msg-user {
  align-self: flex-end;
  max-width: 85%;
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
}

/* Le rendu du Markdown est fait par assistant.js — le modèle répond en
   Markdown, et l'afficher brut mettait des `**` et des `##` à l'écran. Ces
   règles habillent ce qu'il produit ; sans JavaScript, le texte reste lisible,
   simplement avec ses marques. */
.markdown > *:first-child { margin-top: 0; }
.markdown > *:last-child { margin-bottom: 0; }
.markdown h3, .markdown h4, .markdown h5 {
  margin: var(--e-3) 0 var(--e-1); font-size: 1rem;
}
.markdown ul, .markdown ol { margin: var(--e-2) 0; padding-left: var(--e-4); }
.markdown li { margin: var(--e-1) 0; }
.markdown p { margin: var(--e-2) 0; }
/* Le modèle s'en sert pour ses mises en garde — « je ne peux pas garantir les
   horaires ». C'est exactement ce qu'il ne faut pas noyer dans le texte. */
.markdown blockquote {
  margin: var(--e-3) 0; padding: var(--e-2) var(--e-3);
  border-left: 3px solid var(--accent-line);
  background: var(--accent-soft);
  border-radius: 0 6px 6px 0;
}
.markdown blockquote p:first-child { margin-top: 0; }
.markdown blockquote p:last-child { margin-bottom: 0; }
.markdown code {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 4px; padding: 0.05em 0.35em; font-size: 0.9em;
}

/* La réponse reste à gauche et prend toute la largeur : c'est elle qu'on lit
   vraiment, elle ne doit pas être à l'étroit. */
.msg-assistant {
  align-self: stretch;
  background: var(--surface);
  border: 1px solid var(--line);
}

/* --- Les cartes de visite, sur l'accueil ----------------------------------
   Le patron de `recipes` : `.card` porte le lien entier, `.ph` le visuel,
   `.body` le titre et la méta, `.foot` les pastilles. La grille elle-même est
   celle du socle (`.collection[data-view="grid"]`) — on n'en réécrit pas une.

   `.card-enveloppe` existe parce que le bouton de copie ne peut PAS vivre dans
   la carte : un <button> dans un <a> n'est pas du HTML valide, et cliquer l'un
   déclencherait l'autre. Il se pose donc en absolu par-dessus. */
.card-enveloppe { position: relative; display: flex; }
.card {
  display: flex; flex-direction: column;
  flex: 1 1 auto;
  background: var(--surface-hi);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  overflow: hidden;
  text-decoration: none; color: inherit;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.card:hover, .card:focus-visible {
  border-color: var(--accent-line);
  box-shadow: var(--shadow-2);
  transform: translateY(-2px);
}
/* Le visuel : pas de photo pour une visite — ce serait la photo de quelle
   étape ? — donc un aplat qui porte le glyphe de la marque. Il donne à la
   grille son rythme, sans prétendre illustrer quoi que ce soit. */
.card .ph {
  display: flex; align-items: center; justify-content: center;
  /* `position: relative` sert d'ancre à la photo. Sans elle, l'image reste un
     élément flex : `height: 100%` s'y résout en `auto`, l'image impose sa
     hauteur intrinsèque et le cadre s'étire — l'`aspect-ratio` ne tient plus,
     et deux cartes voisines n'ont plus la même hauteur d'image. */
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--accent-soft);
  color: var(--accent);
  border-bottom: 1px solid var(--line);
}
.card .ph .ico { width: 30px; height: 30px; opacity: .75; }
.card .body { padding: var(--e-3); display: flex; flex-direction: column;
              gap: var(--e-1); flex: 1 1 auto; }
.card .body h3 { margin: 0; font-size: 1.02rem; line-height: 1.3; }
.card .body .meta { margin: 0; }
.card .foot {
  margin-top: auto; padding-top: var(--e-2);
  display: flex; flex-wrap: wrap; gap: var(--e-1);
}

/* La visibilité se lit d'un coup d'œil sur la grille, et UNE pastille suffit.
   `privee` est le cas courant et reste neutre ; les deux autres disent que
   quelque chose est sorti — c'est ce qu'on veut repérer en balayant la
   grille, pas l'état d'avancement. */
.visibilite-privee { /* neutre : l'allure de base de `.badge` suffit */ }
.visibilite-partagee { border-color: var(--accent-line); color: var(--accent); }
.visibilite-publique { background: var(--accent); color: var(--accent-tx);
                       border-color: var(--accent); }

/* Le choix de visibilité : trois boutons côte à côte plutôt qu'une bascule.
   « Partagée » n'a pas de contraire évident, et une bascule à trois états
   n'existe pas. `aria-pressed` porte l'actif — le socle en fait autant pour
   le thème. */
.visibilite form { display: contents; }
.visibilite [aria-pressed="true"] {
  background: var(--accent); color: var(--accent-tx);
  border-color: var(--accent);
}

/* La liste des personnes nommées. Une ligne par compte, l'action de retrait
   au bout — même idiome que les listes du socle. */
.invites .liste > li {
  display: flex; align-items: baseline; gap: var(--e-2); flex-wrap: wrap;
}
.invites .liste > li form { margin-left: auto; }
.invites .ligne {
  display: flex; align-items: flex-end; gap: var(--e-2); flex-wrap: wrap;
  margin-top: var(--e-3);
}
.invites .ligne .champ { flex: 1 1 16rem; margin: 0; }

/* La carte de création, à la place de la première visite. Le trait discontinu
   dit qu'elle n'est pas un contenu mais un emplacement à remplir — la même
   convention que partout ailleurs, et elle se lit sans un mot. */
.card.carte-vide {
  border-style: dashed;
  border-color: var(--line-strong);
  background: none;
}
.card.carte-vide:hover, .card.carte-vide:focus-visible {
  border-style: solid;
  background: var(--surface-hi);
}
.card.carte-vide .ph { background: none; border-bottom: 0; }
.card.carte-vide .ph .ico { width: 34px; height: 34px; opacity: 1; }
.card.carte-vide .body { padding-top: 0; }
.card.carte-vide h3 { color: var(--accent); }

/* Le bouton de copie : discret au repos, franc au survol de la carte. Il reste
   toujours atteignable au clavier — `opacity` seule le cacherait à l'œil sans
   le retirer du parcours de tabulation, ce qui est exactement ce qu'on veut. */
.copier-lien {
  position: absolute; top: var(--e-2); right: var(--e-2);
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; padding: 0;
  border: 1px solid var(--line); border-radius: var(--r-m);
  background: var(--surface-hi); color: var(--tx-2);
  cursor: pointer; opacity: 0;
  transition: opacity .15s, color .15s, border-color .15s;
}
.card-enveloppe:hover .copier-lien,
.copier-lien:focus-visible { opacity: 1; }
.copier-lien:hover { color: var(--accent); border-color: var(--accent-line); }
.copier-lien .ico { width: 16px; height: 16px; }
/* La confirmation passe par la couleur ET par `aria-label`, que le script
   réécrit : une pastille verte seule ne dit rien à qui n'y voit pas. */
.copier-lien.copie-faite { opacity: 1; color: var(--ok-tx);
                           border-color: var(--ok-line); }
/* Sur un écran tactile il n'y a pas de survol : le bouton reste visible. */
@media (hover: none) {
  .copier-lien { opacity: 1; }
}

/* --- La vignette d'étape --------------------------------------------------
   Elle existe TOUJOURS : photo Google Places quand il y en a une, pictogramme
   de catégorie sinon. Sans elle, une fiche sur deux serait décalée et la
   colonne perdrait son alignement — c'est pour ça que le repli n'est pas un
   détail mais la moitié du sujet. */
.vignette {
  flex: none;
  width: 84px; height: 84px;
  border-radius: var(--r-m);
  overflow: hidden;
  background: var(--accent-soft);
  display: flex; align-items: center; justify-content: center;
}
.vignette img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vignette-vide { color: var(--accent); }
.vignette-vide .ico { width: 26px; height: 26px; opacity: .7; }

/* Le résumé : la première phrase, toujours visible. Le reste est replié. */
.resume { margin: var(--e-2) 0 0; }

/* Le détail. `summary` porte son propre chevron — celui du navigateur diffère
   d'un moteur à l'autre et ne suit pas la couleur du texte. */
.detail-etape { margin: var(--e-2) 0 0; }
.detail-etape > summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 0.35rem;
  color: var(--accent);
}
.detail-etape > summary::-webkit-details-marker { display: none; }
.detail-etape > summary::before {
  content: "›";
  display: inline-block;
  transition: transform .15s;
  font-size: 1.1em; line-height: 1;
}
.detail-etape[open] > summary::before { transform: rotate(90deg); }
.detail-etape > summary:hover { text-decoration: underline; }
.detail-etape[open] > summary { margin-bottom: var(--e-2); }

@media (max-width: 640px) {
  /* Sur téléphone, le rang et la vignette tiennent la première colonne, le
     corps la seconde : à quatre colonnes, le nom du lieu sortait à deux mots
     par ligne. */
  .fiche-etape { grid-template-columns: auto 1fr; }
  .fiche-etape .vignette { width: 56px; height: 56px; }
}

/* --- Le panneau de l'assistant -------------------------------------------
   L'ALLURE VIENT DU SOCLE : `.pastille-assistant`, `.panneau` et ses deux
   tailles `[data-size]`, `.entete`, `.fil`, `.pied`. La version précédente
   réécrivait tout dans un `<dialog>` maison — exactement le contournement que
   le contrat du socle demande de ne pas faire. Il a coûté un centrage à
   retrouver, un fond à redessiner, et une modale restée visible fermée.

   Ne restent ici que les réglages propres à wander. */

/* La liste des fils, dans l'en-tête du panneau. `disabled` marque le fil
   courant plutôt qu'un style à part : il n'est pas seulement signalé, il est
   inactivable — cliquer dessus ne ferait qu'un aller-retour serveur pour
   revenir au même endroit. */
.menu-fils .panneau-menu { min-width: 240px; }
.menu-fils .panneau-menu button {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  width: 100%; text-align: left;
}
.menu-fils .panneau-menu button[disabled] { opacity: .55; cursor: default; }

/* Le fil est une PILE de messages, pas un bloc de texte au fil de l'eau : le
   socle donne au `.fil` son défilement, pas son rythme interne. */
.panneau .fil { display: flex; flex-direction: column; gap: var(--e-3); }

/* Les boutons de l'en-tête ne portent qu'une icône. `.bouton.discret` est la
   variante DU SOCLE — inventer un `.bouton.icone` de plus donnerait au parc
   une septième façon de dessiner le même bouton — mais son rembourrage est
   calculé pour un libellé : sur un glyphe seul, il fait un rectangle. */
.panneau .entete .bouton { padding: 0.32rem 0.5rem; line-height: 1; }
.panneau .entete .bouton .ico { display: block; }

/* Le pied porte un `<textarea>` et non un `<input>` : sans hauteur bornée,
   trois phrases collées mangent la moitié du panneau. */
.panneau .pied textarea { max-height: 6rem; }

/* La commande de taille n'a aucun sens sous 640 px : le panneau y est déjà
   plein écran, et le socle n'y applique pas `[data-size]`. Encore faut-il ne
   pas la rendre — sinon elle bascule un cookie qui ne change rien à l'écran. */
@media (max-width: 640px) {
  .taille-panneau { display: none; }
}

/* La vignette empruntée remplit tout le cadre : c'est une photo de lieu, pas
   un logo. En absolu — hors du flux flex — pour que le cadre garde son ratio
   quelle que soit la forme de la photo. Le repli au glyphe, lui, reste centré
   par le flex. */
.card .ph img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
}

/* Le séparateur entre la connexion par un fournisseur et celle par mot de
   passe. Un trait qui traverse le mot : c'est ce qui dit « deux chemins vers
   la même porte » plutôt que « deux formulaires empilés ». */
.separateur-ou {
  display: flex; align-items: center; gap: var(--e-3);
  margin: var(--e-3) 0;
  color: var(--tx-2); font-size: .85rem;
}
.separateur-ou::before, .separateur-ou::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}
