/* ── HIC SUNT — core: tokens, chrome, overlays, primitives ── */
/* ── Les polices sont DANS l'app ─────────────────────────────────────────
   Elles arrivaient par deux @import Google — un ici, un en tête de
   da.css — c'est-à-dire deux requêtes réseau bloquantes, en série, après
   la feuille elle-même. Sur une WebView iOS en réseau lent, ou en avion,
   l'app peignait en Helvetica : une app de VOYAGE perdait son identité
   typographique exactement là où on l'ouvre le plus.
   Ce sont les deux fichiers variables (Sora 400–800, Hanken 100–900),
   couverture latine complète, accents français compris. Plus aucun appel
   à fonts.googleapis.com — ce qui retire du même coup un tiers destinataire
   de la politique de confidentialité.
   Spline Sans Mono n'est plus chargé : --mono pointe sur Sora depuis la
   refonte (da.css § jetons). */
@font-face{
  font-family:'Sora';
  src:url('fonts/sora.woff2') format('woff2-variations'),
      url('fonts/sora.woff2') format('woff2');
  font-weight:400 800;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'Hanken Grotesk';
  src:url('fonts/hanken-grotesk.woff2') format('woff2-variations'),
      url('fonts/hanken-grotesk.woff2') format('woff2');
  font-weight:100 900;font-style:normal;font-display:swap;
}

/* ── cartes réelles (Leaflet) — fond clair et froid, pas de vieux papier ── */
.leaflet-container{background:#EEF0EB;font-family:'Spline Sans Mono',monospace}
.leaflet-tile{filter:saturate(.9) brightness(1.02) contrast(.97)}
.leaflet-marker-icon{background:none;border:none}
.leaflet-control-container{display:none}

:root{
  /* ── L'encoche ────────────────────────────────────────────────────────
     env(safe-area-inset-top) était écrit en toutes lettres à quatorze
     endroits. Deux inconvénients, et le second est celui qui a coûté :

       · un écran qui oublie de la reprendre laisse une bande crème sous
         l'heure — c'est arrivé au Monde, dont le globe démarrait SOUS la
         barre d'état au lieu de passer dessous (retour de Charlotte, le
         6 septembre : « le bandeau blanc en haut à corriger ») ;
       · et rien ne pouvait le vérifier : le navigateur du harnais rend
         env(safe-area-inset-top) à zéro, sans moyen de lui en donner une
         autre. Un banc mesurait donc un iPhone sans encoche, c'est-à-dire
         aucun iPhone.

     Le passage par une variable règle les deux : un banc pose
     --encoche:59px sur la racine et mesure ce que voit vraiment quelqu'un
     avec une Dynamic Island. Les écrans convertis sont ceux qui touchent
     au haut de l'écran — .tabview, le héros de l'Accueil, le globe du
     Monde ; le reste utilise encore env() en direct et pourra suivre. */
  --encoche:env(safe-area-inset-top, 0px);
  /* Aucun mode sombre n'existe encore dans cette DA — sans cette ligne,
     un iPhone en mode sombre système laissait WebKit essayer d'assombrir
     certains éléments natifs (champs, défilement) tout seul, en
     désaccord avec le reste de l'interface qui restait clair. Déclare
     explicitement "cette page est claire, ne touche à rien" plutôt que
     de laisser un mode sombre à moitié auto-appliqué. */
  color-scheme:light;
  /* Surfaces — blanc et gris neutres, zéro teinte parchemin/sable */
  --bg:#FFFFFF; --surface:#FAFAF8; --surface2:#F0F0EE; --surface-raised:#FAFAF8;
  /* Encre — brun-noir profond, jamais pur noir */
  --ink:#221D16; --ink-soft:#5C5345; --sub:#756B58;
  /* Lignes */
  --line:#E8E8E6; --line2:#DFDFDC;
  /* Or — patiné, signature de la marque, réservé aux accents ponctuels */
  --gold:#A6824A; --gold-soft:#C9A96E; --gold-deep:#8A6526; --gold-bright:#E8C98C;
  /* Divers */
  /* --ph assombri de #8F8F89 (~3.25:1 sur blanc) à #7A7062 (~4.86:1) : sous
     le minimum WCAG AA (4.5:1) pour un placeholder, texte pourtant lu comme
     un vrai libellé tant qu'aucune saisie n'a eu lieu (ex: champ vide dans
     un formulaire). Reste plus clair que --sub pour garder la distinction
     visuelle "indice" vs contenu réel. */
  --onink:#F6F6F3; --ph:#7A7062; --ok:#5d7a4e;
  /* --warn/--danger : jusqu'ici des hex répétés en dur à quelques endroits
     (badge "non confirmé", alerte pluie, message d'erreur), jamais posés en
     variable — repris tels quels ici, juste nommés, pour rester cohérent
     si un jour on passe en mode sombre (un seul endroit à redéfinir). */
  --warn:#C9822B; --warn-deep:#9C7C2E;
  /* Rouge système iOS. Trois briques différentes cohabitaient (#B3452E,
     #B23B2E, #C0503C), toutes un peu sales à côté de la menthe et
     étrangères à la plateforme. Le rouge destructeur d'iOS est celui que
     tout le monde reconnaît sans avoir à lire le mot. */
  --danger:#FF3B30; --danger-deep:#D70015;
  /* Typographie — Sora (titres, labels, UI) / Hanken Grotesk (texte courant) / Spline Sans Mono */
  --serif:'Sora',-apple-system,'Helvetica Neue',sans-serif;
  --serif-text:'Sora',-apple-system,sans-serif;
  --sf:'Hanken Grotesk',-apple-system,'Helvetica Neue',sans-serif;
  --sans:'Hanken Grotesk',-apple-system,sans-serif;
  --mono:'Spline Sans Mono','SF Mono',monospace;
  /* Géométrie — radius généreux et cohérent. --card-radius-sm : cartes
     compactes en liste (repère réservation, pépite, hébergement…) — un
     radius plus petit que --card-radius pour rester proportionné à leur
     taille, mais un SEUL chiffre entre elles plutôt que 14px ici, 16px là
     au hasard des écrans (audit DA globale, retour de Charlotte). */
  --card-radius:var(--r-lg); --card-radius-sm:var(--r-md); --btn-radius:var(--r-pill);
  /* Ombres — neutres, plates, aucune teinte sépia */
  --shadow-card:0 1px 2px rgba(20,18,14,0.04),0 4px 16px rgba(20,18,14,0.05),0 20px 44px -26px rgba(20,18,14,0.28);
  --shadow-float:0 24px 64px -28px rgba(20,18,14,0.32);
  --shadow-raised:0 12px 28px -18px rgba(20,18,14,0.32);
  --shadow-postcard:0 12px 28px -18px rgba(20,18,14,0.5);
  --tile-bg:linear-gradient(160deg,#F4F4F2,#EDEDEA);
  --tap-min:44px; --tap-comfortable:52px;
  --spring:cubic-bezier(0.34,1.2,0.4,1);
  --ease-out:cubic-bezier(0.22,1,0.36,1);
  --ease-in-out:cubic-bezier(0.4,0,0.2,1);
}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
button,a{color:inherit;font:inherit;text-decoration:none}
button{background:none;border:none}
html,body{margin:0;padding:0;background:#FFFFFF}
body{
  font-family:var(--sf);color:var(--ink);
  background:#FFFFFF;
  min-height:100%;
  /* Rien n'est sélectionnable par défaut. Une coquille native reste une
     page web pour iOS : un appui long y déclenche la sélection de texte et
     la bulle « Copy · Look Up · Translate », par-dessus tout ce que l'app
     essaie de faire du même geste — y compris le menu contextuel des
     cartes de voyage, qui se retrouvait recouvert par elle (retour de
     Charlotte, capture à l'appui : « le clic sélectionne le texte, pas
     l'endroit à cliquer »). Aucune app iOS native ne laisse sélectionner
     le texte de son interface ; seuls les champs de saisie le permettent,
     et c'est exactement ce que rétablit la règle suivante.
     -webkit-touch-callout coupe en plus la bulle des liens et des images
     sur appui long, qui vient du même geste. */
  -webkit-user-select:none; user-select:none;
  -webkit-touch-callout:none;
}
/* Là où saisir et sélectionner est le sujet même de l'élément. Sans cette
   exception, le curseur et la sélection deviennent inutilisables dans les
   champs sur iOS — le remède serait pire que le mal. */
input, textarea, select, [contenteditable="true"]{
  -webkit-user-select:text; user-select:text;
  -webkit-touch-callout:default;
}
::selection{background:rgba(20,17,14,0.14)}

/* ── studio page chrome (desktop presentation) ── */
.studio-head{max-width:560px;margin:0 auto;padding:54px 24px 8px;text-align:center}
.studio-eyebrow{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:2.4px;text-transform:uppercase;color:var(--gold)}
.studio-title{font-family:var(--serif);font-weight:600;font-size:34px;margin-top:10px;letter-spacing:-0.3px}
.studio-title em{color:var(--gold);font-style:italic}
.studio-sub{font-size:13.5px;font-weight:300;color:var(--sub);line-height:1.6;margin-top:10px}
.stage{display:flex;justify-content:center;padding:26px 16px 70px}
.phone{width:393px;height:852px;background:#0d0b08;border-radius:56px;padding:11px;box-shadow:var(--shadow-float),0 0 0 1px rgba(31,26,20,0.25);position:relative;flex:none}
.phone::after{content:'';position:absolute;top:21px;left:50%;transform:translateX(-50%);width:118px;height:32px;background:#0d0b08;border-radius:var(--r-md);z-index:200;pointer-events:none}
.screen{width:100%;height:100%;background:var(--bg);border-radius:46px;overflow:hidden;position:relative;isolation:isolate}
@media (max-width:500px){
  /* Mobile : verrouiller le body en plein écran, le scroll se fait dans .tabview */
  html,body{overflow:hidden;height:100%}
  body{position:fixed;inset:0}
  /* Cacher le contenu studio sans toucher au stage */
  .studio-head{display:none}
  /* Stage invisible mais toujours dans le flux */
  .stage{
    position:fixed;inset:0;
    padding:0;margin:0;
    display:flex;
    background:transparent;
    pointer-events:none;
  }
  /* Phone : prend tout l'écran.
     inset:0 seul n'a pas suffi sur certains iPhone en PWA "Sur l'écran
     d'accueil" (bande vide persistante sous la barre d'onglets, invariante
     au scroll). On mesure donc la hauteur réelle en JS (--app-vh, posé dans
     index.html) et on l'utilise en priorité, avec 100dvh/inset en repli si
     le script n'a pas encore tourné. */
  html{ --app-vh: 1vh; }
  .phone{
    position:fixed !important;
    inset:0 !important;
    width:100vw !important;
    height:calc(var(--app-vh) * 100) !important;
    border-radius:0 !important;
    padding:0 !important;
    box-shadow:none !important;
    background:var(--bg) !important;
    pointer-events:auto;
    z-index:0;
  }
  .phone::after{display:none !important}
  .screen{
    position:absolute !important;
    top:0 !important;left:0 !important;
    right:0 !important;bottom:0 !important;
    width:100% !important;
    height:100% !important;
    border-radius:0 !important;
    overflow:hidden;
  }
}
/* App native Capacitor (iPhone ET iPad) : mêmes règles plein écran que
   ci-dessus, mais sans dépendre de la largeur d'écran — un iPad est bien
   plus large que 500px et ne déclencherait jamais le bloc mobile. */
html.native-app,
html.native-app body{overflow:hidden;height:100%}
html.native-app body{position:fixed;inset:0}
html.native-app .studio-head{display:none}
html.native-app .stage{
  position:fixed;inset:0;
  padding:0;margin:0;
  display:flex;
  background:transparent;
  pointer-events:none;
}
html.native-app{ --app-vh: 1vh; }
html.native-app .phone{
  position:fixed !important;
  inset:0 !important;
  width:100vw !important;
  height:calc(var(--app-vh) * 100) !important;
  border-radius:0 !important;
  padding:0 !important;
  box-shadow:none !important;
  background:var(--bg) !important;
  pointer-events:auto;
  z-index:0;
}
html.native-app .phone::after{display:none !important}
html.native-app .screen{
  position:absolute !important;
  top:0 !important;left:0 !important;
  right:0 !important;bottom:0 !important;
  width:100% !important;
  height:100% !important;
  border-radius:0 !important;
  overflow:hidden;
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important}
}

/* ── iOS status bar ── */
/* La barre d'état iOS réelle est toujours visible (Safari ou PWA) :
   on masque systématiquement la barre simulée pour éviter le doublon. */
.statusbar{display:none !important}
.sb-time{font-size:14.5px;font-weight:600;letter-spacing:0.2px}
.sb-right{display:flex;align-items:center;gap:6px}
.statusbar.on-dark{color:var(--onink)}

/* ── navbar — iOS Large Title style ── */
.navbar{
  height:52px;display:flex;align-items:center;justify-content:space-between;
  padding:0 16px;flex:none;position:relative;z-index:5;
}
.nav-title{
  font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:2.4px;
  text-transform:uppercase;color:var(--ink-soft);
  position:absolute;left:50%;transform:translateX(-50%);white-space:nowrap;
}
/* Le bouton retour de .navbar est maintenant .ihx-btn (overlays.css) —
   même cercle blanc partout dans l'app, plus de style .nav-btn à part. */
.nav-spacer{width:36px;height:36px}

/* ── overlays — iOS slide + spring ── */
.ov{
  position:absolute;inset:0;background:var(--bg);z-index:100;
  display:flex;flex-direction:column;
  padding-top:env(safe-area-inset-top,0px);
  transform:translateX(100%);
  /* iOS spring: snappier in, smooth out */
  transition:transform 0.38s var(--ease-out);
  will-change:transform;
}
.ov.in{transform:translateX(0)}
/* Tant qu'un overlay n'est pas (ou plus) affiché à l'écran (avant l'ouverture,
   ou pendant les ~0.4s de la sortie en glissement), il ne doit plus intercepter
   les taps — sinon un appui juste après avoir fermé un écran (retour, chat…)
   peut retomber sur l'overlay encore présent (bien qu'invisible) au lieu de la
   carte/tuile en dessous : c'est la cause des taps « qui ne marchent pas
   à chaque fois » sur les tuiles de l'accueil. */
.ov:not(.in){pointer-events:none}
/* closing: slightly faster, no spring overshoot */
.ov.closing{transform:translateX(100%);transition:transform 0.28s var(--ease-in-out)}
.ov.modal{transform:translateY(100%)}
.ov.modal.in{transform:translateY(0)}
.ov.modal.closing{transform:translateY(100%);transition:transform 0.28s var(--ease-in-out)}
.ov.carto{background:var(--ink)}
.ov-scroll{flex:1;overflow-y:auto;overscroll-behavior:contain;padding-bottom:36px;scrollbar-width:none;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;touch-action:pan-y}
.ov-scroll::-webkit-scrollbar{display:none}
/* La réserve du pied collant, en un seul endroit : la marge basse du
   corps ET la hauteur que le dégradé doit sauter s'en déduisent toutes
   les deux. Deux nombres séparés se seraient désynchronisés au premier
   ajustement de bouton. */
/* 108 px n'est plus qu'un REPLI, le temps que le pied soit mesuré
   (_marquerDefilement, app.js, pose --pied depuis sa hauteur réelle). La
   marge basse et le masque lisent la même variable : c'est la condition
   pour qu'ils ne se désynchronisent pas — ils l'ont fait une fois, à
   108 px d'un côté et 112 de l'autre, et trente pixels de contenu
   disparaissaient au-dessus de la barre. */
.ov-scroll.has-foot{--pied:108px;padding-bottom:calc(var(--pied) + 14px)}

/* Le dégradé n'apparaît que du côté où il reste quelque chose à voir
   (data-defile posé par _marquerDefilement, app.js). Même mécanique que
   les cartes du questionnaire : un écran qui continue sous un bouton
   collant doit le dire, sinon la coupure se lit comme un défaut
   d'affichage — vu sur les Préférences, « Transport préféré » tranché net
   par « Enregistrer ».

   Le fondu se pose JUSTE AU-DESSUS du bouton, pas au bord du cadre : la
   zone de défilement s'étend derrière lui, et un dégradé placé tout en
   bas tombait dans une région que personne ne voit. */
.ov-scroll[data-defile="bas"],
.ov-scroll[data-defile="deux"]{
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 28px),transparent 100%);
          mask-image:linear-gradient(180deg,#000 calc(100% - 28px),transparent 100%);
}
.ov-scroll.has-foot[data-defile="bas"],
.ov-scroll.has-foot[data-defile="deux"]{
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - var(--pied) - 28px),transparent calc(100% - var(--pied)));
          mask-image:linear-gradient(180deg,#000 calc(100% - var(--pied) - 28px),transparent calc(100% - var(--pied)));
}
/* Fondu doux plutôt qu'une ombre franche : le contenu se dissout sous la
   barre au lieu d'être tranché net — moins de sensation de "coupure". */
.ov-foot{
  position:absolute;bottom:0;left:0;right:0;
  padding:22px 24px calc(12px + env(safe-area-inset-bottom,0px)) 24px;
  background:linear-gradient(to bottom, transparent 0, var(--bg) 26px, var(--bg) 100%);
  z-index:10;
}

/* ── layout primitives ── */
.px{padding-left:20px;padding-right:20px}
.section-h{display:flex;align-items:baseline;justify-content:space-between;margin-top:28px;margin-bottom:14px}
/* « facultatif » à côté d'un libellé : un champ qu'on peut sauter doit le
   dire, sinon il se lit comme une condition d'entrée. */
.w-fac{font-family:var(--mono);font-size:8.5px;font-weight:700;letter-spacing:1px;
  text-transform:uppercase;color:var(--sub);margin-left:7px}
/* iOS-style Large Title for section headers */
.section-h h2{font-family:var(--serif);font-weight:var(--t-section-g);font-size:var(--t-section);letter-spacing:-0.3px}
.section-h .meta{font-family:var(--mono);font-size:9px;letter-spacing:1px;text-transform:uppercase;color:var(--sub)}
/* --gold-deep plutôt que --gold : ce libellé apparaît sur la quasi-totalité
   des écrans (en-tête de section) à une taille (9.5px) bien en dessous du
   seuil "grand texte" — --gold sur blanc n'atteint que ~3.55:1, sous le
   minimum WCAG AA de 4.5:1 pour du texte de cette taille ; --gold-deep
   atteint ~5.3:1. */
.eyebrow{font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:2.4px;text-transform:uppercase;color:var(--gold-deep)}
.eyebrow-row{display:flex;align-items:center;justify-content:space-between;gap:12px}
.eyebrow-now{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.08em;color:var(--gold-deep);white-space:nowrap}
.hairline{height:1px;background:var(--line);border:none;position:relative}
.hairline.gold::before{content:'';position:absolute;left:0;top:0;width:30px;height:1px;background:var(--gold)}

/* ── buttons — iOS native sizing ── */
.btn{
  display:flex;align-items:center;justify-content:center;gap:9px;
  width:100%;height:var(--tap-comfortable);
  border:1.5px solid var(--ink);border-radius:var(--btn-radius);
  background:transparent;color:var(--ink);
  font-family:var(--sf);font-size:16px;font-weight:700;letter-spacing:-0.1px;
  cursor:pointer;
  transition:transform 0.12s var(--spring),opacity 0.12s,background 0.12s;
  -webkit-user-select:none;user-select:none;
}
.btn em{font-family:var(--serif);font-style:italic;font-weight:500}
/* iOS tap feedback: fast spring + slight opacity, pas de remplissage */
.btn:active{transform:scale(0.96);opacity:0.6}
.btn.gold{border-color:var(--gold-deep);color:var(--gold-deep)}
.btn.gold:active{background:rgba(184,146,66,0.08)}
.btn-ghost{
  display:flex;align-items:center;justify-content:center;gap:9px;
  width:100%;height:var(--tap-comfortable);
  border:1px solid var(--line);border-radius:var(--btn-radius);
  background:transparent;color:var(--ink);
  font-family:var(--sf);font-size:16px;font-weight:500;
  cursor:pointer;
  transition:transform 0.12s var(--spring),opacity 0.12s;
}
.btn-ghost:active{transform:scale(0.96);opacity:0.8}
.btn.sm,.btn-ghost.sm{height:var(--tap-min);font-size:14px}
/* .btn et .btn-ghost sont larges à 100 % : ce sont des boutons de bas de
   carte, pleine largeur. Posés DANS une rangée flex à côté d'un texte,
   ce 100 % les fait réclamer toute la place et écrase le texte à côté —
   « Suivre / ce / voyage » sur trois lignes, un mot par ligne, avec un
   « Démarrer » démesuré (capture de Charlotte, carte de suivi du voyage).
   .btn-inline est la version qui prend la largeur de son libellé et rien
   de plus, à utiliser dès qu'un bouton partage sa ligne avec autre chose. */
.btn.btn-inline,.btn-ghost.btn-inline{
  width:auto;flex:none;padding:0 18px;white-space:nowrap;
}
button:focus-visible,.chip:focus-visible,a:focus-visible,.input:focus-visible,textarea:focus-visible{outline:2px solid var(--gold);outline-offset:2px}

/* ── skeleton loading — remplace les "Chargement…" statiques par un balayage
   lumineux, même technique que .muse-line (voir @keyframes shimmer) ── */
.skel{position:relative;overflow:hidden;background:var(--surface2);border-radius:var(--r-sm)}
.skel::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,0.6),transparent);
  transform:translateX(-100%);
  animation:skelSweep 1.5s ease-in-out infinite;
}
@keyframes skelSweep{100%{transform:translateX(100%)}}
.skel.on-dark{background:rgba(246,246,243,0.1)}
.skel.on-dark::after{background:linear-gradient(90deg,transparent,rgba(246,246,243,0.22),transparent)}

/* ── inputs, chips — définitions complètes dans screens.css (chargé après
   ce fichier, sur les mêmes sélecteurs non scopés : cette version-ci était
   silencieusement fusionnée propriété par propriété par la cascade plutôt
   que jamais vraiment appliquée telle quelle — une seule source désormais). */
.chip.on{background:var(--surface);border-color:var(--ink);border-width:1.5px;color:var(--ink);font-weight:700}

/* ── status badges ── */
.status{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:8.5px;font-weight:700;letter-spacing:0.8px;text-transform:uppercase;padding:5px 9px;border-radius:var(--r-sm)}
.status.ok{background:rgba(93,122,78,0.12);color:var(--ok)}
.status.prep{background:rgba(20,17,14,0.08);color:var(--gold-deep)}
.status.draft{background:var(--surface2);color:var(--sub)}

/* ── list rows — iOS minimum 44px tap target ── */
.row{
  display:flex;align-items:center;gap:14px;
  min-height:var(--tap-comfortable);padding:14px 0;
  border-bottom:1px solid var(--line2);cursor:pointer;
  transition:opacity 0.1s;
}
.row:active{opacity:0.6}
.row:last-child{border-bottom:none}
.row .r-ico{color:var(--gold);flex:none;width:22px;display:flex;justify-content:center}
.row .r-main{flex:1;min-width:0}
/* iOS: primary text 17px, secondary 13px — clear hierarchy */
.row .r-t{font-family:var(--serif);font-size:17px;font-weight:500;letter-spacing:-0.1px}
.row .r-s{font-family:var(--mono);font-size:9px;letter-spacing:0.6px;text-transform:uppercase;color:var(--sub);margin-top:4px}
.row .r-chev{color:var(--sub);flex:none}

/* ── segmented control ── */
.seg{display:flex;background:var(--surface2);border-radius:var(--r-sm);padding:3px;gap:3px}
.seg button{flex:1;height:36px;border:none;border-radius:var(--r-sm);background:transparent;font-family:var(--sf);font-size:12.5px;font-weight:500;color:var(--sub);cursor:pointer;transition:all 0.2s}
.seg button.on{background:var(--surface);color:var(--ink);box-shadow:var(--sh-1);font-weight:600}
.seg button:active{transform:scale(0.94);opacity:0.7}

/* ── avatar — plat, sans reflet ni bevel, couleur de la destination ── */
.avatar{border-radius:50%;background:var(--accent,var(--gold-deep));color:var(--onink);display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-weight:600;flex:none}

/* ── cartographic decor ── */
.grat{position:absolute;inset:0;width:100%;height:100%;opacity:0.6;pointer-events:none}
.contour{position:absolute;inset:0;width:100%;height:100%;stroke:var(--gold);opacity:0.14;pointer-events:none}
.wx-chip{display:inline-flex;align-items:center;gap:5px;font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:0.4px;background:var(--surface);border:1px solid var(--line);color:var(--ink-soft);padding:6px 10px;border-radius:var(--r-lg)}

/* ── toast ── */
.toast{position:absolute;bottom:104px;left:50%;transform:translate(-50%,12px);background:var(--ink);color:var(--onink);font-size:13px;font-weight:500;padding:12px 18px;border-radius:var(--r-sm);box-shadow:var(--shadow-float);opacity:0;transition:opacity 0.25s,transform 0.25s;z-index:400;pointer-events:none;white-space:normal;max-width:86%;line-height:1.4;text-align:center;text-wrap:balance}
.toast.show{opacity:1;transform:translate(-50%,0)}
/* Le toast tenait sur UNE ligne, coupée aux ciseaux : white-space:nowrap
   plus text-overflow:ellipsis. Toute phrase un peu longue arrivait donc
   tronquée — « Votre session a expiré — reconnectez-vous pour … », vu à
   l'écran. Une phrase à moitié lue ne vaut guère mieux que pas de phrase,
   et c'est précisément quand le message est long qu'il est important.
   Il passe donc à la ligne, centré et équilibré. */
/* Variante avec action "Annuler" — pointer-events réactivé (le toast
   simple les désactive pour ne jamais gêner le contenu dessous), bouton
   au moins --tap-min pour rester tactile malgré le format compact. */
.toast-undo{display:flex;align-items:center;gap:14px;pointer-events:auto;white-space:normal}
.toast-undo button{flex:none;background:none;border:none;color:var(--gold-bright);font-family:var(--sans);font-size:13px;font-weight:700;cursor:pointer;padding:10px 2px;min-height:var(--tap-min);-webkit-tap-highlight-color:transparent}

.ico{display:block;flex:none}

/* ── cascade d'apparition des cartes de voyages ── */
.trip-in{opacity:0;transform:translateY(14px);animation:tripIn 0.5s cubic-bezier(.22,.68,.2,1) forwards}
@keyframes tripIn{to{opacity:1;transform:translateY(0)}}

/* ── apparition progressive des jours dans l'itinéraire ── */
.dayrow.reveal{opacity:0;transform:translateY(18px);transition:opacity 0.5s cubic-bezier(.22,.68,.2,1),transform 0.5s cubic-bezier(.22,.68,.2,1)}
.dayrow.reveal.in{opacity:1;transform:translateY(0)}

/* L'ancienne cascade des destinations suggérées (.tile-in) est retirée :
   elle se déclenchait au dessin de l'écran, donc onze des quinze tuiles
   finissaient leur animation sous la ligne de flottaison, invisibles.
   Remplacée par une révélation au défilement (.tile-scroll, da.css §48,
   pilotée par hsRevelerTuiles dans app.js). */


/* ── La bande de préhension d'une feuille sans poignée ───────────────────
   Posée par _enableSheetDragToDismiss (app.js) sur toute feuille modale
   qui n'affiche pas la poignée grise. Invisible : elle ne dessine rien,
   elle rend seulement le haut de la feuille saisissable — le geste
   attendu existe, il n'a simplement pas besoin d'être annoncé deux fois.

   touch-action:none, sinon le navigateur avale le mouvement vertical
   pour son propre défilement et le geste reste muet. z-index modéré :
   au-dessus du fond, sous tout ce qu'on peut toucher. */
.ov-prise{
  position:absolute; top:0; left:0; right:0; height:56px; z-index:4;
  touch-action:none; background:transparent; pointer-events:auto;
}
