/* ============================================================
   Cairn — back-office.
   Même palette que la maquette : glace de glacier sur basalte,
   gris froids à biais cyan, chasse fixe pour toute donnée
   d'instrument (dates, heures, montants, références).
   ============================================================ */

:root {
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Consolas, monospace;

  /* ⚠ LES MÊMES RAYONS QUE L'APPLICATION, ET ILS MANQUAIENT ICI. Une dizaine
     de règles du carnet et du planning les demandaient déjà — `var(--r-sm)`
     sans définition ne rend RIEN, pas même une erreur : les vignettes et les
     boutons avaient simplement des coins droits, sur le seul écran où on ne
     les regarde pas côte à côte avec le téléphone. */
  --r-sm: 8px; --r-md: 14px; --r-lg: 20px;

  --page:#E9EDEE; --bg:#DFE5E6; --surface:#FFFFFF; --surface-2:#F3F7F7;
  --line:#CFD9DB; --line-soft:#E3EAEB;
  /* text-3 assombri : à #7B8E95 sur fond clair, les petits textes (dates,
     kickers) tombaient sous le contraste AA de 4,5:1. */
  --text:#101A1E; --text-2:#52646A; --text-3:#64777E;
  --accent:#1B6B82; --accent-ink:#FFFFFF; --accent-soft:#D9EBF1;
  --critical:#A63C31; --critical-soft:#F7E1DD;
  --warn:#8E6210;   --warn-soft:#F8ECD3;
  --ok:#3A6849;     --ok-soft:#DDEAE0;
  --shadow: 0 1px 2px rgba(16,26,30,.06), 0 6px 18px rgba(16,26,30,.07);
  --r: 12px;
  --tap: 44px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --page:#0B1216; --bg:#070C0F; --surface:#131E23; --surface-2:#19262C;
    --line:#27373E; --line-soft:#1D2C32;
    --text:#E7EEF0; --text-2:#9CAFB6; --text-3:#7E959D;
    --accent:#6FBDD4; --accent-ink:#06171D; --accent-soft:#113039;
    --critical:#E08375; --critical-soft:#3A201C;
    --warn:#DCAE58;   --warn-soft:#372913;
    --ok:#82B993;     --ok-soft:#1B3325;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 6px 18px rgba(0,0,0,.35);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }

/* ---------- en-tête ---------- */
.top {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 20;
}
.top-in {
  max-width: 1080px; margin: 0 auto; padding: 12px 20px;
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
}
.brand {
  font-weight: 800; letter-spacing: -.02em; font-size: 1.15rem;
  text-decoration: none; color: var(--text);
  display: inline-flex; align-items: center; gap: 9px;
}
.brand span { color: var(--accent); }
.brand .brand-mot { color: var(--text); }   /* le mot, pas le point */
/* Le coin arrondi de l'icône, repris ici : c'est ainsi qu'elle apparaît sur le
   téléphone, et c'est la même application. */
.brand-logo {
  width: 30px; height: 30px; border-radius: 8px; display: block;
  box-shadow: 0 1px 2px rgba(16, 26, 30, .18);
}
.top nav { display: flex; gap: 4px; flex-wrap: wrap; }
.top nav a {
  padding: 8px 12px; border-radius: 8px; text-decoration: none;
  color: var(--text-2); font-weight: 600; font-size: .9rem;
  min-height: var(--tap); display: inline-flex; align-items: center;
}
.top nav a:hover { background: var(--surface-2); color: var(--text); }
.top nav a.on { background: var(--accent-soft); color: var(--accent); }
/* La barre d'un voyage type. Même dessin que celle d'un voyage — c'est la même
   application —, mais elle reste visible sous 900 px : aucune tabbar ne vient
   la remplacer en bas, et sans elle on n'aurait plus aucun chemin de retour
   vers l'administration sur téléphone. Le retour vient EN PREMIER et se
   détache : c'est ce qu'on cherche quand on ne reconnaît pas l'écran. */
.nav-cat a.nav-cat-retour {
  color: var(--accent); border: 1px solid var(--line);
}
.nav-cat a.nav-cat-retour:hover { background: var(--accent-soft); color: var(--accent); }
.top .right { margin-left: auto; display: flex; align-items: center; gap: 12px; font-size: .85rem; color: var(--text-3); }

/* ---------- structure ---------- */
main { max-width: 1080px; margin: 0 auto; padding: 26px 20px 80px; }
main.large { max-width: 1500px; }
/* L'en-tête suit la largeur de la page, sinon la marque et le contenu ne
   partent plus du même bord. Sans `:has()`, il reste à 1080 : décalé, mais
   jamais cassé. */
body:has(main.large) .top-in { max-width: 1500px; }

.head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 22px; }
.head h1 { margin: 0 0 2px; font-size: 1.75rem; letter-spacing: -.025em; line-height: 1.15; text-wrap: balance; }
.head .sub { color: var(--text-2); font-size: .92rem; }
.head .kicker {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 4px;
}
.head .actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

h2.sect {
  font-size: 1.05rem; letter-spacing: -.01em; margin: 30px 0 12px;
  padding-bottom: 7px; border-bottom: 1px solid var(--line);
}

.card {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r); box-shadow: var(--shadow); padding: 16px;
}
.grid { display: grid; gap: 12px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.row { display: flex; align-items: center; gap: 10px; }
.between { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.stack { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.muted { color: var(--text-2); }
.small { font-size: .85rem; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.right { text-align: right; }

/* ---------- boutons ---------- */
.btn {
  min-height: var(--tap); padding: 0 16px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface-2); color: var(--text);
  font: inherit; font-weight: 600; font-size: .9rem;
  cursor: pointer; text-decoration: none; white-space: nowrap;
}
.btn:hover { background: var(--bg); }
.btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-danger { color: var(--critical); border-color: color-mix(in srgb, var(--critical) 40%, transparent); }
.btn-danger:hover { background: var(--critical-soft); }
.btn-sm { min-height: 36px; padding: 0 11px; font-size: .82rem; }
.btn-ghost { background: none; border-color: transparent; }
.btn-ghost:hover { background: var(--surface-2); }

/* ---------- pastilles ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px;
  font-size: .72rem; font-weight: 700; white-space: nowrap;
}
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill-critical { background: var(--critical-soft); color: var(--critical); }
.pill-warn     { background: var(--warn-soft);     color: var(--warn); }
.pill-ok       { background: var(--ok-soft);       color: var(--ok); }
.pill-accent   { background: var(--accent-soft);   color: var(--accent); }
.pill-mute     { background: var(--surface-2);     color: var(--text-3); }

/* La recommandation : mention discrète, jamais une pastille pleine. */
.reco {
  font-family: var(--font-mono); font-size: .72rem; color: var(--text-2);
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
}
.reco::before { content: ""; width: 6px; height: 6px; border-radius: 50%; }
.reco-obligatoire::before { background: var(--critical); }
.reco-conseille::before   { background: var(--warn); }
.reco-autonome::before    { background: var(--ok); }

/* ---------- itinéraire ---------- */
.etape {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r); box-shadow: var(--shadow); margin-bottom: 12px; overflow: hidden;
}
/* Photo emblématique de l'étape. Embarquée dans le dépôt : elle doit
   s'afficher sans réseau. Le crédit est obligatoire — c'est la licence. */
.etape-photo { margin: 0; position: relative; background: var(--surface-2); }
.etape-photo img {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;
  object-fit: cover;
}
.etape-photo figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 26px 16px 10px;
  color: #fff;
  background: linear-gradient(transparent, rgba(6, 14, 18, .78));
  font-size: 1.15rem; font-weight: 700; letter-spacing: -.015em;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.etape-photo figcaption span {
  font-family: var(--font-mono); font-size: .66rem; font-weight: 400;
  opacity: .82; letter-spacing: 0;
}

.etape-head {
  display: flex; align-items: center; gap: 12px; padding: 13px 16px;
  background: var(--surface-2); border-bottom: 1px solid var(--line-soft); flex-wrap: wrap;
}
.etape-num {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: var(--accent); color: var(--accent-ink);
  font-family: var(--font-mono); font-size: .78rem; font-weight: 700;
  display: grid; place-items: center;
}
.etape-head h3 { margin: 0; font-size: 1.02rem; letter-spacing: -.01em; }
.etape-head .dates { font-family: var(--font-mono); font-size: .78rem; color: var(--text-2); }
.etape-head .tools { margin-left: auto; display: flex; gap: 5px; }
.etape.transit .etape-num { background: var(--text-3); }

.jour {
  display: grid; grid-template-columns: 104px 1fr; gap: 14px;
  padding: 11px 16px; border-top: 1px solid var(--line-soft);
}
.jour:first-child { border-top: 0; }
.jour-date {
  font-family: var(--font-mono); font-size: .76rem; color: var(--text-3);
  padding-top: 3px; line-height: 1.35;
}
.jour-date b { display: block; color: var(--accent); font-size: .8rem; }
.jour-corps { display: flex; flex-direction: column; gap: 7px; min-width: 0; }

.item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 9px 11px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--line-soft);
  /* Lien étiré : le titre couvre toute la ligne via ::after. */
  position: relative;
}
.item.seg { border-left: 3px solid var(--accent); }
.item .stack { flex: 1; }
.item .titre { font-weight: 600; font-size: .92rem; text-decoration: none; color: inherit; }
.item a.titre::after { content: ""; position: absolute; inset: 0; border-radius: 8px; }
.item:has(a.titre:hover) { border-color: var(--accent); background: var(--accent-soft); }
.item a.titre:focus-visible::after { outline: 3px solid var(--accent); outline-offset: 1px; }
/* Les outils restent cliquables au-dessus du lien étiré. */
.item .tools { display: flex; gap: 6px; align-items: center; position: relative; z-index: 1; }
.item .tools .chev { color: var(--text-3); font-size: 1.1rem; line-height: 1; }
.item:has(a.titre:hover) .tools .chev { color: var(--accent); }

.vide { color: var(--text-3); font-size: .85rem; font-style: italic; padding: 2px 0; }

/* ---------- barre d'étapes collante ----------
   Treize étapes font une longue page ; cette rangée de puces suit le
   défilement et saute à l'ancre de chacune. */
.etapes-nav {
  /* Sous l'en-tête, lui-même collant (~56 px) : à top:0, elle glisserait
     derrière lui et resterait invisible une fois collée. */
  position: sticky; top: 56px; z-index: 15;
  display: flex; gap: 6px; overflow-x: auto;
  padding: 10px 0; margin: 0 0 14px;
  background: var(--page);
  border-bottom: 1px solid var(--line-soft);
  -webkit-overflow-scrolling: touch; scrollbar-width: thin;
}
.etapes-nav a {
  flex: none; display: inline-flex; align-items: center; gap: 7px;
  min-height: 34px; padding: 0 12px 0 5px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  color: var(--text-2); text-decoration: none;
  font-size: .82rem; font-weight: 600; white-space: nowrap;
}
.etapes-nav a b {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  background: var(--accent-soft); color: var(--accent);
  font-family: var(--font-mono); font-size: .7rem; font-weight: 700;
  display: grid; place-items: center;
}
.etapes-nav a:hover { border-color: var(--accent); color: var(--text); }
.etapes-nav a:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* Un élément d'itinéraire mène à sa réservation : c'est le geste naturel
   quand on tombe sur une ligne et qu'on veut savoir où on en est. */
a.item { text-decoration: none; color: inherit; cursor: pointer; }
a.item:hover { border-color: var(--accent); background: var(--accent-soft); }
a.item:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.item .chev { color: var(--text-3); align-self: center; flex: none; font-size: 1.1rem; }
a.item:hover .chev { color: var(--accent); }

/* ---------- formulaires ---------- */
form.stackform { display: flex; flex-direction: column; gap: 14px; max-width: 640px; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field label, .lab {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-3);
}
.field input, .field select, .field textarea {
  min-height: var(--tap); width: 100%;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface); color: var(--text);
  font: inherit; font-size: .95rem; padding: 9px 12px;
}
.field textarea { min-height: 96px; resize: vertical; line-height: 1.5; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 3px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}
.field .aide { font-size: .8rem; color: var(--text-3); }
.duo { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* Case à cocher : cible large, la case seule se rate. */
.case {
  display: flex; align-items: center; gap: 8px;
  font-size: .92rem; font-weight: 400; cursor: pointer; padding: 3px 0;
}
.case input { width: 18px; height: 18px; margin: 0; accent-color: var(--accent); }

/* ---------- messages ---------- */
.flash {
  padding: 12px 15px; border-radius: 10px; margin-bottom: 18px;
  border: 1px solid; font-size: .92rem;
}
.flash-ok  { background: var(--ok-soft);       color: var(--ok);       border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
.flash-err { background: var(--critical-soft); color: var(--critical); border-color: color-mix(in srgb, var(--critical) 30%, transparent); }
/* Un état, pas un événement : le bandeau « voyage archivé » reste affiché à
   chaque page tant que l'archivage dure. Ni vert ni rouge — rien n'a réussi
   ni échoué. */
.flash-info { background: var(--fond-2, #f2f5f6); color: var(--encre-2, #52646a);
              border-color: color-mix(in srgb, currentColor 22%, transparent); }
.flash-info a { color: inherit; }

/* ⚠ UNE SUGGESTION NE DOIT PAS SE LIRE COMME UNE SAISIE. Aucune règle ne
   couvrait `::placeholder` : le navigateur appliquait son gris par défaut,
   assez soutenu pour qu'un champ vide et un champ rempli se ressemblent — on
   croyait avoir déjà saisi l'adresse de l'hôtel, ou on hésitait à écrire
   par-dessus « Passeport Didier ». Trois marques les séparent maintenant : la
   couleur la plus pâle de la palette, l'italique, et une graisse normale là où
   la valeur réelle est plus sombre. Elles s'effacent au premier caractère tapé,
   par construction. */
/* ⚠ L'OPACITÉ EST MESURÉE, PAS CHOISIE À L'ŒIL. Sur fond blanc, ce gris donne
   3,2:1 de contraste à 0,8 — cinq fois et demie moins qu'une valeur réelle
   (17,7:1), donc impossible à confondre avec elle, et pourtant lisible. À 0,55,
   que j'avais posé d'abord, il tombait à 2,1 : la suggestion cessait d'être une
   aide pour devenir un texte qu'on plisse les yeux pour déchiffrer. Corriger un
   excès par l'excès inverse ne corrige rien. */
input::placeholder, textarea::placeholder {
  color: var(--text-3); opacity: .6; font-style: italic; font-weight: 400;
}
/* Au focus, elle s'efface : on est en train d'écrire, elle a fini son travail
   et ne doit plus concurrencer le curseur. */
input:focus::placeholder, textarea:focus::placeholder { opacity: .4; }

/* Le `<fieldset disabled>` de la lecture seule ne doit RIEN changer à la mise
   en page : sans cette remise à zéro, il ajoute une bordure, une gouttière et
   une largeur minimale qui font déborder les tableaux larges. Il ne sert qu'à
   rendre les contrôles inertes — le navigateur s'occupe de les griser. */
fieldset.inerte { border: 0; margin: 0; padding: 0; min-width: 0; }
fieldset.inerte :disabled { cursor: not-allowed; }

.alerte {
  border: 1px solid color-mix(in srgb, var(--critical) 45%, transparent);
  background: var(--critical-soft);
  border-radius: var(--r); padding: 16px; margin-bottom: 18px;
}
.alerte h3 { margin: 0 0 8px; font-size: 1rem; color: var(--critical); }
.alerte ul { margin: 8px 0 0; padding-left: 20px; }
.alerte li { margin-bottom: 5px; font-size: .9rem; }

.note {
  font-size: .88rem; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--line-soft);
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0; padding: 10px 13px;
}

/* ---------- tableaux ---------- */
.tablewrap { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: .9rem; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
th {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-3); font-weight: 700;
  border-bottom: 1px solid var(--line);
}
tbody tr:hover { background: var(--surface-2); }
td.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }

/* ---------- connexion ---------- */
.login {
  max-width: 380px; margin: 12vh auto; padding: 0 20px;
}
.login .card { padding: 26px; }
.login h1 { margin: 0 0 4px; font-size: 1.6rem; letter-spacing: -.02em; }
.login p.sub { margin: 0 0 22px; color: var(--text-2); font-size: .9rem; }

/* ============================================================
   BARRE D'ONGLETS BASSE
   Même grammaire que l'application sur le téléphone : navigation
   au pouce, en bas, jamais en haut. Elle apparaît dès que la
   fenêtre est étroite, sur PC comme sur mobile — une seule
   ergonomie à apprendre.
   ============================================================ */
.tabbar { display: none; }

@media (max-width: 900px) {
  .nav-large { display: none !important; }

  main.avec-tabbar { padding-bottom: 96px; }

  .tabbar-5 { grid-template-columns: repeat(5, 1fr) !important; }
  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    display: grid; grid-template-columns: repeat(3, 1fr);
    background: var(--surface);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom, 0);
    box-shadow: 0 -2px 12px rgba(0,0,0,.06);
  }
  .tab {
    min-height: 58px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    text-decoration: none; color: var(--text-3);
    font-size: .7rem; font-weight: 600; padding: 8px 4px;
    position: relative;
  }
  .tab svg { width: 22px; height: 22px; }
  .tab.is-active { color: var(--accent); }
  .tab.is-active::before {
    content: ""; position: absolute; top: 0; left: 24%; right: 24%; height: 2px;
    background: var(--accent); border-radius: 0 0 2px 2px;
  }
  .tab:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
  .tab .badge {
    position: absolute; top: 6px; right: 50%; translate: 18px 0;
    background: var(--critical); color: #fff;
    font-family: var(--font-mono); font-size: 10px; font-weight: 700;
    min-width: 17px; height: 17px; border-radius: 9px;
    display: grid; place-items: center; padding: 0 4px;
  }

  /* « Plus » : un pli natif qui ouvre les écrans secondaires au-dessus de la
     barre. Sans lui, Repérés, Bagages, Réglages et Comptes n'avaient aucun
     chemin sous 900 px — la navigation large est masquée. */
  .tab-plus { position: relative; }
  .tab-plus > summary { list-style: none; cursor: pointer; height: 100%; }
  .tab-plus > summary::-webkit-details-marker { display: none; }
  .tab-plus .tab-menu {
    position: absolute; bottom: calc(100% + 8px); right: 6px; z-index: 40;
    min-width: 170px; padding: 6px;
    display: flex; flex-direction: column;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: 12px; box-shadow: var(--shadow);
  }
  .tab-plus .tab-menu a {
    display: flex; align-items: center; min-height: var(--tap);
    padding: 0 14px; border-radius: 8px;
    text-decoration: none; color: var(--text); font-weight: 600; font-size: .9rem;
  }
  .tab-plus .tab-menu a:hover { background: var(--surface-2); }
  .tab-plus .tab-menu a.on { background: var(--accent-soft); color: var(--accent); }
  .tab-plus .tab-menu a:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
}

/* bouton d'ouverture d'une réservation : sortie vers l'extérieur */
.btn-lien { gap: 10px; }

@media (max-width: 640px) {
  .jour { grid-template-columns: 1fr; gap: 6px; }
  .jour-date { display: flex; gap: 8px; align-items: baseline; padding-top: 0; }
  .jour-date b { display: inline; }
  .duo { grid-template-columns: 1fr; }
  .head .actions { margin-left: 0; width: 100%; }
  .etape-head .tools { margin-left: 0; width: 100%; flex-wrap: wrap; }
  .top-in { padding: 10px 16px; gap: 10px; }
  main { padding: 18px 16px 80px; }
  .resa-statut { flex-wrap: wrap; justify-content: flex-end; }
}


/* ============================================================
   DOCUMENTS
   Billets, confirmations, passeports. Les fichiers vivent hors
   de la racine web : chaque ouverture passe par document.php.
   ============================================================ */
.doc {
  display: grid; grid-template-columns: 52px 1fr auto; gap: 12px; align-items: center;
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r); box-shadow: var(--shadow);
  margin-bottom: 8px; padding: 10px 14px;
}
.doc:hover { border-color: var(--line); }
.doc-vignette {
  width: 52px; height: 52px; border-radius: 8px;
  display: grid; place-items: center; text-decoration: none;
  background: var(--accent-soft); color: var(--accent);
  font-family: var(--font-mono); font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
}
.doc-vignette:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.doc-corps {
  text-decoration: none; color: inherit; min-width: 0;
  display: flex; flex-direction: column; gap: 2px; min-height: 44px; justify-content: center;
}
.doc-corps .titre { font-weight: 650; font-size: .95rem; }
.doc-corps:hover .titre { color: var(--accent); }
.doc-vignette:focus-visible, .doc-corps:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 6px;
}
.doc-tools { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }

input[type="file"] { padding: 10px 12px; background: var(--surface-2); cursor: pointer; }

@media (max-width: 640px) {
  .doc { grid-template-columns: 44px 1fr; }
  .doc-vignette { width: 44px; height: 44px; }
  .doc-tools { grid-column: 1 / -1; justify-content: flex-start; }
}

/* ============================================================
   FICHE D'UN ÉLÉMENT
   On lit d'abord, on édite ensuite. Tout formulaire vit dans un
   volet replié — sinon l'écran devient un empilement de champs
   et l'information disparaît sous la saisie.
   ============================================================ */
.fiche-tete { display: flex; flex-direction: column; gap: 12px; }
.fiche-etat { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.fiche-prix {
  font-size: 1.4rem; font-weight: 700; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.fiche-ref {
  display: flex; flex-direction: column; gap: 3px;
  padding: 10px 13px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--line-soft);
}
.fiche-ref .mono { font-size: 1.15rem; font-weight: 700; letter-spacing: .03em; }
.fiche-tete .btn-lien { align-self: flex-start; }

/* ---------- volet repliable ---------- */
/* ⚠ UN `summary` N'A PAS LE CURSEUR MAIN PAR DÉFAUT, contrairement à un lien.
   Les navigateurs lui laissent la flèche : rien ne dit alors qu'un volet
   s'ouvre, et l'on ne clique pas. Chaque famille de volets se le posait dans
   son coin — `.volet`, `.tab-plus`, `.c-apercu` — et tout `<details>` écrit
   ailleurs repartait sans. La règle est générale parce que le fait l'est : un
   résumé est toujours cliquable. */
summary { cursor: pointer; }

.volet {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r); box-shadow: var(--shadow);
  margin-bottom: 10px; overflow: hidden;
}
.volet > summary {
  cursor: pointer; list-style: none;
  min-height: var(--tap); padding: 0 16px;
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: .72rem;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-2); font-weight: 700;
  user-select: none;
}
.volet > summary::-webkit-details-marker { display: none; }
.volet > summary::before {
  content: "›"; font-family: var(--font-sans); font-size: 1.15rem;
  color: var(--text-3); transition: rotate .15s ease; line-height: 1;
}
.volet[open] > summary::before { rotate: 90deg; }
.volet > summary:hover { background: var(--surface-2); color: var(--text); }
.volet > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
.volet[open] > summary { border-bottom: 1px solid var(--line-soft); }
.volet .compte {
  margin-left: auto;
  font-size: .72rem; color: var(--text-3); letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.volet .compte-vide { color: var(--warn); text-transform: none; letter-spacing: .02em; }
.volet-corps { padding: 14px 16px 16px; }
/* `pre-wrap` : les fiches d'activite ont des paragraphes et des intertitres.
   Sans cela le HTML les ecrase en un pave unique. `nl2br` ne suffisait pas —
   il ne restitue pas les lignes vides entre paragraphes. */
/* Même règle que pour le texte d'un conseil : le paragraphe remplit sa boîte.
   Il portait `max-width: 68ch`, et laissait le même vide à droite. Deux blocs
   de texte voisins qui ne se cadrent pas pareil se remarquent tout de suite —
   et l'on cherche ce qui les distingue alors que rien ne les distingue. */
.volet-texte {
  margin: 0; font-size: .92rem; color: var(--text-2); line-height: 1.62;
  max-width: 100%; white-space: pre-wrap;
  /* `pre-wrap` respecte les retours à la ligne, mais ne coupe pas un mot trop
     long : une adresse ou un lien collé déborderait encore. */
  overflow-wrap: anywhere;
}

/* une ligne de saisie compacte : champ + bouton, sans habillage */
.ligne-form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ligne-form .field, .ligne-form input[type="text"], .ligne-form input[type="url"] {
  flex: 1; min-width: 200px;
  min-height: var(--tap);
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface); color: var(--text);
  font: inherit; font-size: .95rem; padding: 9px 12px;
}
.ligne-form input[type="file"] { flex: 1 1 240px; }
.ligne-form .btn { flex: none; }

@media (prefers-reduced-motion: reduce) {
  .volet > summary::before { transition: none; }
}

/* Dès que l'écran est étroit, on est au doigt : les contrôles denses
   acceptables à la souris repassent à la taille tactile. */
@media (max-width: 900px) {
  .btn-sm { min-height: var(--tap); }
}

@media (max-width: 640px) {
  .ligne-form { flex-direction: column; align-items: stretch; }
  .ligne-form .btn { width: 100%; }
}

/* Disclosure imbriquée : « Modifier ce texte » sous une fiche en lecture.
   Discrète, pour ne pas concurrencer le volet qui la contient. */
.sous-volet { margin-top: 12px; border-top: 1px solid var(--line-soft); padding-top: 4px; }
.sous-volet > summary {
  cursor: pointer; list-style: none;
  min-height: var(--tap); display: flex; align-items: center; gap: 7px;
  font-size: .84rem; font-weight: 650; color: var(--accent);
}
.sous-volet > summary::-webkit-details-marker { display: none; }
.sous-volet > summary::before { content: "✎"; font-size: .9rem; }
.sous-volet > summary:hover { text-decoration: underline; text-underline-offset: 3px; }
.sous-volet > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.sous-volet textarea { min-height: 150px; }

/* ============================================================
   CONSEIL VOITURE
   « Ai-je besoin d'une voiture ici ? » est une décision d'étape,
   pas une note en bas de page. Le niveau porte la couleur ; ce
   n'est pas un statut de réservation, il n'y a rien à réserver.
   ============================================================ */
.conseil-voiture {
  border: 1px solid var(--line);
  border-left: 4px solid var(--text-3);
  border-radius: 0 var(--r) var(--r) 0;
  background: var(--surface-2);
  padding: 11px 14px;
  display: flex; flex-direction: column; gap: 5px;
}
.cv-titre {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-weight: 700; font-size: .95rem; letter-spacing: -.01em;
}
.cv-icone { font-size: 1rem; line-height: 1; }
.cv-marque {
  font-family: var(--font-mono); font-size: .62rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-3); font-weight: 400;
  border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px;
}
/* ⚠ LE TEXTE REMPLIT SA BOÎTE, ET NE S'ARRÊTE PLUS AU MILIEU. Il portait
   `max-width: 72ch` — environ 570 px —, ce qui est la longueur de ligne la
   plus confortable à lire. Mais la boîte, elle, fait toute la largeur de la
   colonne : on voyait donc un pavé de texte cadré à gauche et près de la
   moitié de la boîte vide à droite, ce qui se lit comme un défaut d'affichage
   plutôt que comme une intention. Entre une règle typographique juste et un
   écran qui a l'air cassé, c'est l'écran qui gagne. */
.cv-texte {
  margin: 0; font-size: .89rem; color: var(--text-2); line-height: 1.55;
  max-width: 100%;
  /* Une adresse ou un lien sans espace ne doit pas déborder du cadre. */
  overflow-wrap: anywhere;
}

.conseil-voiture.niv-recommandee  { border-left-color: var(--accent);   background: var(--accent-soft); }
.conseil-voiture.niv-recommandee  .cv-titre { color: var(--accent); }
.conseil-voiture.niv-deconseillee { border-left-color: var(--critical); background: var(--critical-soft); }
.conseil-voiture.niv-deconseillee .cv-titre { color: var(--critical); }
.conseil-voiture.niv-optionnelle  { border-left-color: var(--warn); }
.conseil-voiture.niv-inutile      { border-left-color: var(--line); }
.conseil-voiture.niv-inutile .cv-titre, .conseil-voiture.niv-optionnelle .cv-titre { color: var(--text); }

/* ⚠ DEUX VOCABULAIRES DE NIVEAUX, ET ILS NE S'ÉCRIVENT PAS PAREIL. Les quatre
   ci-dessus sont ceux de la VOITURE (`recommandee`, `optionnelle`…), accordés au
   féminin ; ceux d'un CONSEIL sont `recommande`, `optionnel`, `deconseille`,
   `attention`, `info` — sans accord, parce que la pastille est séparée du titre
   et qu'« Transports recommandés » demanderait de réaccorder à chaque genre.
   Sans ces règles, un conseil non-voiture s'affichait sans aucune couleur. */
.conseil-voiture.niv-recommande  { border-left-color: var(--accent);   background: var(--accent-soft); }
.conseil-voiture.niv-recommande  .cv-titre { color: var(--accent); }
.conseil-voiture.niv-deconseille { border-left-color: var(--critical); background: var(--critical-soft); }
.conseil-voiture.niv-deconseille .cv-titre { color: var(--critical); }
.conseil-voiture.niv-attention   { border-left-color: var(--warn);     background: var(--warn-soft); }
.conseil-voiture.niv-attention   .cv-titre { color: var(--warn); }
.conseil-voiture.niv-optionnel   { border-left-color: var(--warn); }
.conseil-voiture.niv-info        { border-left-color: var(--line); }
.conseil-voiture.niv-optionnel .cv-titre, .conseil-voiture.niv-info .cv-titre { color: var(--text); }

/* synthèse : la même question, mais pour le voyage entier */
.volet-synthese { margin-bottom: 16px; }
.cv-liste { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 6px; }
.cv-ligne {
  display: flex; align-items: baseline; gap: 10px; justify-content: space-between;
  padding: 8px 12px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--line-soft);
  border-left: 3px solid var(--text-3);
}
.cv-ligne .cv-ville  { font-weight: 650; font-size: .92rem; }
.cv-ligne .cv-niveau { font-family: var(--font-mono); font-size: .7rem; color: var(--text-2); white-space: nowrap; }
.cv-ligne.niv-recommandee  { border-left-color: var(--accent); }
.cv-ligne.niv-recommandee  .cv-niveau { color: var(--accent); font-weight: 700; }
.cv-ligne.niv-deconseillee { border-left-color: var(--critical); }
.cv-ligne.niv-deconseillee .cv-niveau { color: var(--critical); font-weight: 700; }
.cv-ligne.niv-optionnelle  { border-left-color: var(--warn); }
.cv-ligne.niv-inutile      { border-left-color: var(--line); }

/* ---------- galerie de photos d'étape (back-office) ---------- */
/* La photo à la une porte un ruban : on doit voir d'un coup d'œil laquelle
   s'affichera sur le téléphone, sans lire les boutons. */
.galerie {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.vignette {
  margin: 0; position: relative; border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; background: var(--surface);
}
.vignette.est-une { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent); }
.vignette img { display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.vignette figcaption { padding: 8px 10px; display: grid; gap: 8px; }
.vignette .ruban {
  position: absolute; top: 8px; left: 8px;
  background: var(--accent); color: #fff; border-radius: 999px;
  font-size: .7rem; font-weight: 700; padding: 3px 10px;
}
.vignette-outils { display: flex; gap: 6px; flex-wrap: wrap; }
.vignette-outils form { display: inline; }

/* Un objet daté hors de son étape : signalé, pas caché. */
.item.est-egare { box-shadow: inset 3px 0 0 var(--warn); }

/* ---------- budget ---------- */
/* Trois nombres qu'on confond volontiers : prévu, payé, dépensé. Les mettre
   côte à côte, à la même échelle, est la moitié de l'explication. */
.chiffres {
  display: grid; gap: 12px; margin-bottom: 14px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.chiffre {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r); box-shadow: var(--shadow); padding: 14px 16px;
  display: flex; flex-direction: column; gap: 3px;
}
.chiffre-fort { border-color: var(--accent); background: var(--accent-soft); }
.chiffre .lab {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-3);
}
.chiffre .val { font-size: 1.5rem; font-weight: 700; letter-spacing: -.02em; }
.chiffre .val-ok   { color: var(--ok); }
.chiffre .val-warn { color: var(--warn); }
.chiffre .note { font-size: .78rem; color: var(--text-2); }

.tableau { width: 100%; border-collapse: collapse; font-size: .9rem; }
.tableau th {
  text-align: left; font-size: .72rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-3); font-weight: 700; padding: 6px 8px; border-bottom: 1px solid var(--line);
}
.tableau td { padding: 8px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.tableau tr:last-child td { border-bottom: 0; }
.tableau .right { text-align: right; }
.tableau .separateur {
  font-size: .72rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-3); padding-top: 14px; border-bottom: 1px solid var(--line);
}

/* ---------- tableau trié et filtré (réservations) ---------- */
.table-outils {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 10px;
}
.champ-filtre {
  flex: 1 1 260px; min-width: 200px; height: 34px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
  color: var(--text); font: inherit; font-size: .88rem;
}
.champ-filtre:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.table-compte { margin-left: auto; font-size: .8rem; color: var(--text-2); white-space: nowrap; }

/* Onze colonnes ne tiennent pas sur un écran étroit : le tableau défile de
   lui-même, plutôt que de replier ses champs sur une deuxième ligne. */
.table-scroll { overflow-x: auto; }
/* Onze colonnes valent mieux serrées : à la taille du reste du site, la moitié
   passait sous l'horizon et le tableau perdait sa raison d'être — tout voir
   d'un coup d'œil. */
.tableau-resa { min-width: 1120px; font-size: .84rem; }
.tableau-resa th, .tableau-resa td { padding: 7px 9px; }
.tableau-resa td { vertical-align: middle; }
.tableau-resa .reco { font-size: .76rem; }
.tableau-resa .nowrap { white-space: nowrap; }
.tableau-resa .col-titre { min-width: 20ch; font-weight: 600; }
.tableau-resa .col-titre a { color: var(--text); text-decoration: none; }
.tableau-resa .col-titre a:hover { text-decoration: underline; color: var(--accent); }
.tableau-resa tbody tr[data-url] { cursor: pointer; }
.tableau-resa tr:hover td { background: var(--surface-2); }
.tableau-resa .est { color: var(--text-3); }
/* L'échéance : ambre quand elle approche, rouge quand elle est passée — et
   seulement sur ce qui n'est pas déjà payé. */
.tableau-resa .ech-proche { color: var(--warn); font-weight: 700; }
.tableau-resa .ech-passee { color: var(--critical); font-weight: 700; }
.tableau-resa .ech-deduite { opacity: .55; }   /* déduite de l'annulation */
.alerte-douce { color: var(--warn); font-weight: 700; }

.tableau th[data-tri] { cursor: pointer; user-select: none; }
.tableau th[data-tri]:hover { color: var(--text); }
.tableau th[data-tri]::after { content: " ↕"; opacity: .3; }
.tableau th.tri-asc::after  { content: " ↑"; opacity: 1; color: var(--accent); }
.tableau th.tri-desc::after { content: " ↓"; opacity: 1; color: var(--accent); }
.tableau th[data-tri]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Le statut se change dans la cellule ; sa couleur le dit sans le lire. */
.f-statut { margin: 0; }
.sel-statut {
  font: inherit; font-size: .78rem; font-weight: 600; padding: 3px 6px;
  border-radius: 7px; border: 1px solid var(--line); background: var(--surface);
  color: var(--text-2);
}
.sel-statut.st-non_reserve { background: var(--warn-soft);   color: var(--warn);   border-color: transparent; }
.sel-statut.st-reserve     { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.sel-statut.st-paye        { background: var(--ok-soft);     color: var(--ok);     border-color: transparent; }

/* ---------- consolidations dépliables (budget) ---------- */
/* Le total reste la ligne principale ; son détail s'ouvre dessous, en
   retrait et plus discret, pour qu'on ne confonde jamais une composante
   avec une somme. */
.deplier {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  font: inherit; color: inherit; text-align: left;
}
.deplier:hover { color: var(--accent); }
.deplier:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
.deplier .chevron {
  width: 0; height: 0; flex: none;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform .15s; opacity: .55;
}
.deplier[aria-expanded="true"] .chevron { transform: rotate(90deg); opacity: 1; }
.deplier .cpt {
  font-size: .72rem; color: var(--text-3); font-variant-numeric: tabular-nums;
}

.tableau .ligne-detail > td {
  background: var(--surface-2); border-bottom: 1px solid var(--line-soft);
  padding-top: 6px; padding-bottom: 6px; font-size: .85rem;
}
.tableau .ligne-detail .cell-detail { padding-left: 24px; }
.tableau .ligne-detail a { color: var(--text); text-decoration: none; }
.tableau .ligne-detail a:hover { text-decoration: underline; }
.tableau .ligne-detail .sous {
  display: block; font-size: .74rem; color: var(--text-3); margin-top: 2px;
}
.tableau .ligne-detail .pill { font-size: .68rem; padding: 1px 7px; vertical-align: 1px; }
/* La colonne des références ne prend que ce qu'il lui faut : elle est vide
   sur les lignes de total, et une référence ne se coupe pas en deux. */
.tableau .col-ref { width: 1%; white-space: nowrap; font-size: .78rem; color: var(--text-2); }

/* ---------- bagages ---------- */
.jauge {
  height: 8px; border-radius: 999px; background: var(--surface-2);
  overflow: hidden; margin-bottom: 18px; border: 1px solid var(--line-soft);
}
.jauge span { display: block; height: 100%; background: var(--ok); transition: width .25s; }

.ligne-bagage {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid var(--line-soft);
}
.ligne-bagage:last-child { border-bottom: 0; }
.ligne-bagage.est-coche { opacity: .55; }
.ligne-bagage.est-coche .truncate { text-decoration: line-through; }
/* Cible large : on coche à une main, debout devant une valise ouverte. */
.case-bouton {
  width: 30px; height: 30px; flex: none; border-radius: 8px;
  border: 2px solid var(--line); background: var(--surface);
  color: var(--ok); font-size: 1.1rem; font-weight: 800; line-height: 1;
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.case-bouton:hover { border-color: var(--accent); }
.est-coche .case-bouton { border-color: var(--ok); background: var(--ok-soft); }

/* Le lien d'aide : un rond discret, pas un second bouton d'action. */
.aide-lien {
  min-width: var(--tap); padding: 0; flex: none;
  font-weight: 700; border-radius: 50%;
}

/* ---------- porte vers l'application ---------- */
/* Le lien vivait dans la barre de navigation large, masquée sous 900 px :
   sur téléphone, il n'existait aucun chemin vers /app/. Il est désormais
   dans l'en-tête, toujours visible, et rappelé sur la page d'accueil. */
.lien-app { flex: none; }

.vers-appli {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px; margin-bottom: 18px;
  background: var(--accent-soft); color: var(--text);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: var(--r); text-decoration: none;
}
.vers-appli:hover { background: color-mix(in srgb, var(--accent) 18%, var(--surface)); }
.vers-appli .va-icone { font-size: 1.6rem; flex: none; }
.vers-appli strong { color: var(--accent); }
.vers-appli .small { color: var(--text-2); }
.vers-appli .chev { margin-left: auto; color: var(--accent); font-size: 1.4rem; flex: none; }

/* Sur grand écran, l'application n'est pas le sujet : on la rappelle sans
   occuper le haut de la page. */
@media (min-width: 901px) {
  .vers-appli { display: inline-flex; margin-bottom: 22px; }
}

/* ============================================================
   CARTE (carte.php) — même moteur que le téléphone (app/carte.js),
   conteneur redimensionné pour un écran de PC. Ce que ces classes
   stylent, MapLibre les crée lui-même (carte.js) : les noms sont
   partagés avec app.css, mais les deux feuilles ne se chargent
   jamais sur la même page.
   ============================================================ */
.carte-boite {
  position: relative;
  height: min(64vh, 620px);
  border-radius: var(--r); overflow: hidden;
  border: 1px solid var(--line); box-shadow: var(--shadow);
  background: var(--surface-2);
  margin-bottom: 18px;
}
/* ⚠️ Sélecteur à DEUX classes, et ce n'est pas décoratif.
   MapLibre pose sa propre classe sur ce même élément, et sa feuille déclare
   `.maplibregl-map { position: relative }`. À spécificité égale, la feuille
   chargée en dernier l'emporte : `.carte-toile` perdait son `absolute`, et
   sans lui `inset: 0` ne dimensionne plus rien — la toile tombait à ZÉRO
   pixel de haut. La carte se chargeait alors parfaitement, tuiles comprises,
   dans un conteneur invisible : aucune erreur, aucun message, un cadre vide.
   Deux classes suffisent à ne plus jamais dépendre de l'ordre des feuilles. */
.carte-boite > .carte-toile { position: absolute; inset: 0; }
.carte-attente {
  position: absolute; inset: 0; margin: 0;
  display: grid; place-items: center; text-align: center; padding: 20px;
  color: var(--text-3); font-size: .9rem;
}
.carte-erreur { color: var(--critical); }
/* Ligne d'état sous le cadre : elle explique une attente ou une absence,
   sans jamais recouvrir la carte qui finit par arriver. */
.carte-etat { margin: -10px 0 16px; }

/* Zone non couverte par le fichier hors ligne. Une note, pas une alerte : le
   fond change de provenance, ce n'est pas une panne. Elle devient orange quand
   il n'y a PAS de réseau pour y suppléer — là, il manque vraiment quelque
   chose. */
.carte-note {
  margin: 10px 0 0; padding: 9px 12px;
  border-left: 3px solid var(--line);
  background: var(--surface-2); color: var(--text-2);
  font-size: .85rem; border-radius: 0 8px 8px 0;
}
.carte-note.est-alerte {
  border-left-color: var(--warn); background: var(--warn-soft); color: var(--warn);
}

/* Diagnostic : du texte brut, fait pour être lu, copié et envoyé. */
.diag-sortie {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: 16px; margin: 0 0 16px;
  font-family: var(--font-mono); font-size: .78rem; line-height: 1.65;
  white-space: pre-wrap; word-break: break-word;
  max-height: 60vh; overflow: auto; user-select: all;
}
/* La carte d'essai doit exister et avoir une taille — MapLibre refuse de
   travailler dans un conteneur invisible — sans occuper l'écran. */
.diag-carte {
  width: 300px; height: 200px; opacity: .35;
  border: 1px solid var(--line-soft); border-radius: 8px; overflow: hidden;
}
/* La vraie page, ouverte dans un cadre pour être mesurée de l'intérieur.
   Visible — un cadre masqué ne dessinerait pas, et c'est précisément le
   rendu qu'on vient observer. */
.diag-cadre {
  width: 100%; max-width: 900px; height: 420px; margin-top: 14px;
  border: 1px solid var(--line); border-radius: var(--r);
}

.maplibregl-ctrl-group { border-radius: 8px !important; box-shadow: 0 1px 4px rgba(6,20,26,.25) !important; }
.maplibregl-ctrl-group button { width: 34px !important; height: 34px !important; }
.maplibregl-ctrl-attrib {
  font-size: 10px !important;
  background: color-mix(in srgb, var(--surface) 85%, transparent) !important;
}
.maplibregl-ctrl-attrib a { color: var(--text-2) !important; }
.maplibregl-ctrl-scale {
  font-family: var(--font-mono) !important; font-size: 10px !important;
  border-color: var(--text-3) !important;
  background: color-mix(in srgb, var(--surface) 80%, transparent) !important;
  color: var(--text-2) !important;
}

/* Étape choisie, sur la barre de sélection de carte.php. */
.etapes-nav a.on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.etapes-nav a.on b { background: var(--accent); color: var(--accent-ink); }

.legende-carte {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  padding: 2px 2px 16px; font-size: .85rem; color: var(--text-2);
}
.legi { display: inline-flex; align-items: center; gap: 7px; }
.legt { display: inline-block; width: 26px; height: 0; flex: none; }
.legt-avion { border-top: 2px dashed #1B6B82; }
.legt-train { border-top: 2px dashed #7A4E9B; }
.legt-route { border-top: 2px solid #C2703D; }
.legt-ferry { border-top: 2px dotted #2E8B77; }

/* ⚠ CHAQUE CARTE SA LÉGENDE. Celle des traits prévus donne une couleur par
     moyen de transport ; sur la carte réelle la couleur désigne le VOYAGEUR, et
     le transport est porté par le pictogramme. Afficher la première sur la
     seconde annonçait « bus, voiture » en ocre devant un tracé bleu-gris.
     `app/carte.js` pose `data-carte-mode` sur la racine du document ; tant
     qu'il ne l'a pas fait — la carte n'est pas encore ouverte — c'est la
     légende du prévu qui vaut, puisque c'est le mode par défaut. */
.legende-reelle { display: none; }
[data-carte-mode="reelle"] .legende-prevue { display: none; }
[data-carte-mode="reelle"] .legende-reelle { display: flex; }
.legt-releve { border-top: 3px solid var(--text-2); }
.legt-deduit { border-top: 3px dashed var(--text-2); }
.legi-note { color: var(--text-3, var(--text-2)); font-style: italic; }

/* ---------- statut d'un voyage ----------
   Deux choix qui ne se valent pas : chacun porte sa conséquence en clair,
   parce que « validé » déclenche un téléchargement de dizaines de mégaoctets
   sur le téléphone. Une case cochée sans savoir cela serait une surprise. */
.statut-choix { border: 0; padding: 0; margin: 0 0 14px; }
.statut-choix legend { font-weight: 600; margin-bottom: 6px; }
.statut-ligne {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 12px; margin-bottom: 6px;
  border: 1px solid var(--line-soft); border-radius: 10px;
  cursor: pointer;
}
.statut-ligne:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.statut-ligne input { margin-top: 3px; }
.statut-ligne span { font-size: .88rem; line-height: 1.45; }

/* ---------- un texte fait pour être copié ----------
   ⚠ CES ZONES FAISAIENT 180 px DE LARGE, taille par défaut d'un <textarea>.
     On y lisait « {"type":"MultiPolygo n","coordinates": [[[[1.9348 » et la
     commande s'arrêtait sur « https://build.protom ». Un texte qu'on demande
     de copier à la main doit d'abord se lire en entier : sans cela, impossible
     de savoir si l'on copie la bonne chose, ni de repérer une erreur. */
.champ-copie {
  display: block; width: 100%; box-sizing: border-box;
  margin: 6px 0 14px; padding: 10px 12px;
  font-size: .78rem; line-height: 1.5;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line-soft); border-radius: 8px;
  resize: vertical; white-space: pre-wrap; word-break: break-all;
}
.champ-copie:focus { outline: 3px solid var(--accent); outline-offset: 1px; }

/* Le mode d'emploi de l'extraction : replié par défaut. Il ne concerne qu'un
   voyage sur quatre, et déplié il noyait l'information qui compte — « ce
   voyage n'a pas de carte ». */
.extraction { margin-top: 12px; }
.extraction > summary {
  cursor: pointer; font-weight: 600; padding: 8px 0;
  color: var(--accent);
}
.extraction[open] > summary { margin-bottom: 8px; }

/* ---------- fabrication d'un fond de carte ----------
   Elle se déclenche seule à la validation. L'écran ne fait que la pousser et
   rendre compte : c'est le seul endroit où l'on voit qu'un travail long est
   en cours, et le silence y serait pris pour une panne. */
.fabrique {
  margin: 12px 0; padding: 12px 14px;
  background: var(--accent-soft); border: 1px solid var(--line-soft);
  border-radius: 10px;
}
.fabrique.est-fini  { background: var(--ok-soft); }
.fabrique.est-echec { background: var(--critical-soft); }
.jauge-pc {
  height: 8px; margin-top: 10px; border-radius: 999px;
  background: var(--surface); overflow: hidden; border: 1px solid var(--line-soft);
}
.jauge-pc span {
  display: block; height: 100%; width: 0; background: var(--accent);
  transition: width .3s;
}
.fabrique.est-fini .jauge-pc span  { background: var(--ok); }
.fabrique.est-echec .jauge-pc span { background: var(--critical); }

/* Les deux étiquettes d'un voyage : statut, puis réservations. */
.etiquettes { display: inline-flex; gap: 6px; flex-wrap: wrap; }

/* ---------- poser un repère depuis la carte (PC) ----------
   Le bandeau et les résultats reprennent la forme du téléphone : c'est le même
   geste, il doit se présenter pareil. Un vocabulaire qui diverge d'un écran à
   l'autre est une source de doute à lui seul. */
.carte-outils-pc {
  display: flex; align-items: center; gap: 12px; margin: 10px 0;
}
.bandeau-choix {
  position: absolute; left: 10px; right: 10px; top: 10px; z-index: 3;
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px 14px; border-radius: 10px;
  background: color-mix(in srgb, var(--surface) 95%, transparent);
  border: 1px solid var(--accent); box-shadow: 0 2px 14px rgba(6, 20, 26, .2);
}
.bc-titre { font-weight: 600; }
.bc-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.panneau-recherche { max-width: 460px; right: auto; }
.panneau-recherche input[type="search"] { width: 100%; }
.panneau-recherche .mode {
  margin: 0; padding: 7px 9px; font-size: .82rem; line-height: 1.4;
  color: var(--text-2); background: var(--surface-2);
  border-left: 3px solid var(--accent); border-radius: 6px;
}
.panneau-recherche .resultats {
  display: flex; flex-direction: column; gap: 5px;
  max-height: 40vh; overflow-y: auto;
}
.panneau-recherche .resultat {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 8px 10px; background: var(--surface);
  border: 1px solid var(--line-soft); border-radius: 8px;
}
.panneau-recherche .resultat:hover { background: var(--surface-2); }
.panneau-recherche .resultat .titre { display: block; font-weight: 600; }
.panneau-recherche .resultat .kicker {
  display: block; font-size: .74rem; color: var(--text-3);
}

/* Le formulaire du repère : sous la carte, pas par-dessus. On vient de
   désigner un point ; le masquer sous une fenêtre serait perdre de vue ce
   qu'on est en train de nommer. */
.carte-form-repere {
  margin: 14px 0; padding: 14px 16px;
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: 12px; max-width: 620px;
}
.carte-form-repere h3 { margin: 0 0 4px; }
.carte-form-repere .deux { display: flex; gap: 12px; }
.carte-form-repere .deux > div { flex: 1 1 0; }
.carte-form-actions { display: flex; gap: 10px; margin-top: 12px; }

/* ============================================================
   LE PLANNING — l'agenda, côté PC.

   Mêmes règles de lecture que sur le téléphone, mêmes couleurs de famille.
   La seule divergence assumée : ici la semaine est une GRILLE, parce qu'un
   écran de PC a la largeur que sept colonnes exigent.
   ============================================================ */
:root {
  --fam-hebergement: #B4453C;
  --fam-activite:    #1B6B82;
  --fam-segment:     #8E6210;
  --fam-reservation: #6B4C82;
}
/* ---------- le calendrier mensuel ----------
   Le PC ne fait jamais moins que le téléphone — règle du projet. Rejoindre le
   16 novembre depuis le 1ᵉʳ demandait quinze clics sur la flèche. Ici, un
   `<details>` plutôt qu'une fenêtre : sans JavaScript, cela s'ouvre quand
   même, et le mois peut rester sous les yeux pendant qu'on lit l'agenda. */
.pl-mois > summary {
  cursor: pointer; font-weight: 600; list-style: none;
  padding: 2px 4px; border-bottom: 1px dashed var(--line);
}
.pl-mois > summary::-webkit-details-marker { display: none; }
.pl-mois > summary::after { content: " ▾"; color: var(--text-3); }
.pl-mois[open] > summary::after { content: " ▴"; }
.pl-cal {
  position: absolute; z-index: 20; margin-top: 8px;
  max-height: 70vh; overflow-y: auto;
  padding: 10px 14px; width: min(420px, 90vw);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--shadow);
}
.pl-cal-mois {
  position: sticky; top: 0; z-index: 1;
  margin: 10px 0 6px; padding: 4px 0;
  background: var(--surface); color: var(--text);
  font-size: 1rem; text-transform: capitalize;
}
.pl-cal-grille { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.pl-cal-jour { text-align: center; font-size: 11px; color: var(--text-3); }
.pl-cal-case {
  position: relative; aspect-ratio: 1; padding: 0 0 8px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  background: var(--surface-2); color: inherit;
  font-size: .85rem; text-decoration: none;
}
.pl-cal-case:hover { border-color: var(--accent); }
/* Visibles mais éteints : les retirer déformerait la grille du mois. */
.pl-cal-case.est-hors {
  background: none; border-color: transparent;
  color: var(--text-3); opacity: .35;
}
.pl-cal-case.est-auj { outline: 2px solid var(--accent); outline-offset: -2px; }
.pl-cal-barre {
  position: absolute; left: 3px; right: 3px; bottom: 3px;
  height: 4px; border-radius: 2px; overflow: hidden;
  display: flex; gap: 1px;
}
.pl-cal-seg { flex: 1; }
/* La légende nomme ce que la couleur ne peut pas dire. */
.pl-cal-legende { margin-top: 16px; }
.pl-cal-titre { margin: 0 0 6px; font-size: 1rem; color: var(--text); }
.pl-cal-etape {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 4px; border-bottom: 1px solid var(--line-soft);
  color: inherit; text-decoration: none;
}
.pl-cal-etape:hover { background: var(--surface-2); }
.pl-cal-pastille { flex: 0 0 auto; width: 14px; height: 14px; border-radius: 3px; }
.pl-cal-nom { flex: 1; min-width: 0; font-size: .9rem; }
.pl-cal-quand { font-size: .78rem; color: var(--text-3); white-space: nowrap; }

.pl-cadre { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; background: var(--surface); }
.pl-entetes { display: grid; background: var(--surface-2); border-bottom: 1px solid var(--line); }
.pl-entete { padding: 8px 6px; text-align: center; min-width: 0; }
.pl-entete .j { font-weight: 700; font-size: .9rem; }
.pl-entete .v { font-size: .78rem; color: var(--text-3); }
.pl-entete.est-auj { background: var(--accent-soft, var(--surface)); }

.pl-bande { display: grid; border-bottom: 1px solid var(--line); }
.pl-bande-col { padding: 4px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.pl-jour-item {
  display: block; text-decoration: none; color: inherit;
  border-left: 3px solid var(--fam-ville, #7B8E95);
  background: var(--surface-2); border-radius: 3px;
  padding: 4px 7px; font-size: .8rem; line-height: 1.25; overflow: hidden;
}
.pl-jour-item:hover { filter: brightness(.97); }
.pl-jour-item .t { display: block; font-weight: 650; }
.pl-jour-item .h { display: block; color: var(--text-3); font-family: var(--font-mono, monospace); font-size: .74rem; }
.pl-jour-item.fam-hebergement { border-left-color: var(--fam-hebergement); }
.pl-jour-item.fam-activite    { border-left-color: var(--fam-activite); }
.pl-jour-item.fam-segment     { border-left-color: var(--fam-segment); }
.pl-jour-item.fam-reservation { border-left-color: var(--fam-reservation); }
.pl-rappel { border-left-color: var(--text-3); }
.pl-rappel.est-tard { border-left-color: #B4453C; }

.pl-grille { display: grid; position: relative; }
.pl-heures { position: relative; }
.pl-heure {
  position: absolute; right: 6px; transform: translateY(-50%);
  font-family: var(--font-mono, monospace); font-size: .72rem; color: var(--text-3);
}
.pl-col { position: relative; border-left: 1px solid var(--line-soft, var(--line)); min-width: 0; }
.pl-trait { position: absolute; left: 0; right: 0; border-top: 1px solid var(--line-soft, var(--line)); }

.pl-bloc {
  position: absolute; overflow: hidden; text-decoration: none;
  border-radius: 4px; padding: 3px 6px;
  font-size: .8rem; line-height: 1.2; color: #fff;
  box-shadow: inset 2px 0 0 rgba(255,255,255,.45);
}
.pl-bloc:hover { filter: brightness(1.08); }
.pl-bloc .t { font-weight: 650; display: block; }
.pl-bloc .h { display: block; opacity: .85; font-family: var(--font-mono, monospace); font-size: .72rem; }
.pl-bloc.fam-hebergement { background: var(--fam-hebergement); }
.pl-bloc.fam-activite    { background: var(--fam-activite); }
.pl-bloc.fam-segment     { background: var(--fam-segment); }
.pl-bloc.fam-reservation { background: var(--fam-reservation); }

/* Un bouton de navigation qui ne mène nulle part : visible, mais éteint. */
.btn.est-inerte { opacity: .35; pointer-events: none; }

/* Les photos d'une journée de carnet : une bande de vignettes carrées, assez
   grandes pour reconnaître la scène, assez petites pour qu'une journée bien
   fournie ne pousse pas la suivante hors de l'écran. */
.carnet-photos {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 8px; margin: 10px 0 4px;
}
.carnet-photo { margin: 0; position: relative; }
.carnet-photo img {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  border-radius: var(--r-sm); display: block; background: var(--surface-2);
}
/* La barre de mise en forme du carnet. Meme balisage que le telephone :
   **gras** et _italique_. Au-dessus du champ, comme la-bas -- dessous, elle
   s eloigne du regard a mesure que le texte s allonge. */
.carnet-outils { display: flex; gap: 6px; flex-wrap: wrap; margin: 6px 0 4px; }
.carnet-outil {
  min-width: 36px; height: 32px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-2); color: inherit;
  font-size: .9rem; line-height: 1; cursor: pointer;
}
.carnet-outil:hover { border-color: var(--accent); }
/* Repliee par defaut : depliee d office, elle poussait le champ hors de
   l ecran sur un portable, avant meme d avoir ecrit un mot. */
.carnet-palette {
  display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 6px;
  max-height: 120px; overflow-y: auto;
}
.carnet-emo {
  width: 32px; height: 32px; padding: 0;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); font-size: 1rem; line-height: 1; cursor: pointer;
}

.carnet-photo video {
  width: 100%; aspect-ratio: 1; object-fit: contain; display: block;
  border-radius: var(--r-sm); background: #000;
}
/* La duree, en HAUT a gauche : le seul coin libre. L etoile occupe le
   bas-gauche, la case "retirer" le haut-droit. */
.photo-duree {
  position: absolute; left: 4px; top: 4px;
  padding: 1px 5px; border-radius: 3px;
  background: rgba(0,0,0,.62); color: #fff;
  font-size: .68rem; font-variant-numeric: tabular-nums; pointer-events: none;
}
.carnet-photo figcaption {
  font-size: .72rem; color: var(--text-3); padding-top: 2px;
}
/* La case « retirer » se pose SUR la vignette : à côté, elle aurait doublé la
   hauteur de la bande pour un geste qu'on fait rarement. */
.carnet-retirer {
  position: absolute; top: 4px; right: 4px;
  display: flex; align-items: center; gap: 4px;
  background: rgba(11, 18, 22, .72); color: #fff;
  border-radius: var(--r-sm); padding: 3px 6px;
  font-size: .7rem; cursor: pointer;
}
/* L'etoile choisit la vignette du marqueur sur la carte reelle. En bas a
   gauche : les deux autres coins sont pris par « retirer » et par la legende,
   et trois commandes au meme endroit se touchent l'une pour l'autre. */
.carnet-etoile {
  position: absolute; bottom: 4px; left: 4px;
  display: flex; align-items: center; gap: 4px;
  background: rgba(11, 18, 22, .72); color: #fff;
  border-radius: var(--r-sm); padding: 3px 6px;
  font-size: .8rem; line-height: 1; cursor: pointer;
}
/* La photo retenue se reconnait sans lire l'etoile : un lisere suffit, et il
   reste visible quand la vignette est sombre. */
.carnet-photo.est-couverture img { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Le basculeur « prevue / reelle », juste au-dessus de la carte : c'est la
   qu'on se demande laquelle on regarde. */
.carte-bascule { display: flex; gap: 6px; margin: 0 0 8px; }

/* Le marqueur d'une entree de carnet sur la carte reelle : la photo elle-meme,
   assez grande pour reconnaitre la scene sans ouvrir. Le lisere blanc la
   detache d'un fond de neige comme d'une foret, et la pointe sous le carre dit
   a quel endroit exactement l'entree est posee.
   ⚠ MEME REGLE DES DEUX COTES : carte.js est partage entre le telephone et le
     PC, et un marqueur non style y sortirait en bouton gris. */
.carnet-pion {
  /* ⚠ AUCUNE DÉCLARATION `position` ICI, ET C'EST VITAL. MapLibre pose ses
       marqueurs avec `.maplibregl-marker { position: absolute }` et les place
       par un `transform`. Notre feuille se charge APRÈS la sienne, à
       spécificité égale : un `position: relative` écrit ici l'emportait et
       renvoyait le marqueur dans le flux normal. Chacun était alors poussé vers
       le bas par la hauteur des précédents, puis décalé depuis cette mauvaise
       origine — les vignettes dérivaient verticalement, celle de Houdan
       atterrissait au milieu de la France, et la carte semblait ignorer les
       coordonnées qu'on lui donnait.
     ⚠ LA CORRECTION AVAIT ÉTÉ FAITE DANS `app/app.css` ET PAS ICI. Le même
       `carte.js` sert le téléphone et le PC, mais chacun charge SA feuille :
       l'écran du PC gardait donc le défaut, tel quel, pendant que celui du
       téléphone était juste. Signalé le 02/09/2026. Ne pas rétablir cette
       ligne, d'aucun des deux côtés.
     Le `position: absolute` de MapLibre sert de repère à `::after`, qui n'a
     donc rien perdu. */
  width: 46px; height: 46px; padding: 0; border: 0;
  background: var(--surface-2); cursor: pointer;
  border-radius: var(--r-sm);
  box-shadow: 0 0 0 2px #fff, 0 2px 6px rgba(0, 0, 0, .45);
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; line-height: 1;
}
/* ⚠ PAS D `overflow: hidden` SUR LE MARQUEUR : il rognerait la pastille de
   comptage, posee en debord du coin. C est l image qui porte ses coins. */
.carnet-pion img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  border-radius: var(--r-sm);
}
/* ⚠ CE QUI EST REGROUPE DOIT LE DIRE. Quatre photos du meme belvedere tiennent
   dans dix metres : sans ce compte, on croit n en avoir pris qu une et l on
   cherche les autres. */
.pion-compte {
  position: absolute; top: -5px; right: -5px;
  min-width: 17px; height: 17px; padding: 0 3px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 9px; background: var(--accent); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1;
  box-shadow: 0 0 0 1.5px #fff;
}
.carnet-pion.est-video::before {
  content: "▶"; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 18px; height: 18px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .5); color: #fff; font-size: 9px; z-index: 1;
}
/* ⚠ POSEE SUR UNE ETAPE, DONC ANNONCEE ET NON ATTESTEE. Aucun trait ne la relie
   aux autres, et c est voulu : en tracer un inventerait un trajet sur la carte
   meme dont l objet est de montrer ce qui s est passe. Le contour en pointille
   le dit sans un mot -- sinon l absence de trait passe pour un defaut. */
.carnet-pion.est-prevue {
  box-shadow: 0 2px 6px rgba(0, 0, 0, .45);
  outline: 2px dashed #fff; outline-offset: -1px;
}
.carnet-pion.est-prevue::after { border-top-color: rgba(255, 255, 255, .55); }

.carnet-pion::after {
  content: ''; position: absolute; left: 50%; bottom: -6px;
  transform: translateX(-50%);
  border-left: 5px solid transparent; border-right: 5px solid transparent;
  border-top: 6px solid #fff;
}

/* ---------- écrire sa journée ----------
   ⚠ LE MÊME PIÈGE DES 180 px QUE `.champ-copie` PLUS HAUT. Sans largeur
     imposée, un <textarea> prend la taille par défaut du navigateur : on
     écrivait le récit d'une journée dans une fenêtre de deux lignes et demie,
     en devinant le début de sa phrase. Un carnet qu'on n'a pas envie d'ouvrir
     reste vide, et un carnet vide ne se rattrape pas au retour. */
.carnet-texte {
  display: block; width: 100%; box-sizing: border-box;
  min-height: 160px; margin: 8px 0 4px; padding: 10px 12px;
  font: inherit; font-size: .92rem; line-height: 1.6;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  resize: vertical;
}
.carnet-texte:focus { outline: 3px solid var(--accent); outline-offset: 1px; }
.carnet-texte[readonly] { background: var(--surface-2); color: var(--text-2); }

/* Les boutons d'une journée : à portée du champ qu'on vient de remplir et du
   fichier qu'on vient de choisir. Voir le commentaire de journal.php — un
   bouton unique en pied d'un carnet de trente journées ne s'atteint jamais,
   et on repart en croyant avoir enregistré. */
.carnet-actions {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line-soft);
}
/* La journée qu'on vient d'enregistrer, brièvement soulignée : après le
   retour à l'ancre, elle dit « c'est bien celle-ci qui est partie ». */
.card:target, form:target .card { outline: 2px solid var(--accent); outline-offset: 2px; }


/* ---------- les deux colonnes d'heures du planning ----------
   Elles decrivent LE MEME INSTANT, pas deux horaires : la maison a gauche,
   le lieu visite a droite. Aucune n'est secondaire -- celui qui est reste en
   France et celui qui est parti doivent lire la meme rangee aussi
   facilement. */
.pl-heures.est-double .pl-heure {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  width: 100%; right: 0; padding: 0 6px; box-sizing: border-box;
}
.pl-heures.est-double .pl-heure > i,
.pl-heures.est-double .pl-heure > b {
  font-style: normal; font-weight: 600; text-align: right;
  font-family: var(--font-mono, monospace); font-size: .7rem; color: var(--text-2);
}
/* L'angle de l'en-tete : il nomme les deux graduations. Sans lui, deux
   colonnes de chiffres sont une enigme. */
.pl-coin { display: grid; align-items: end; justify-items: center; padding-bottom: 4px; }
.pl-coin.est-double { grid-template-columns: 1fr 1fr; gap: 4px; }
.pl-entete .v { font-size: .72rem; color: var(--text-3); }
/* A la verticale : "Buenos Aires" tient alors dans un caractere de large,
   entier, au-dessus de sa propre graduation. */
.pl-vert {
  writing-mode: vertical-rl;
  font-size: .58rem; line-height: 1;
  max-height: 62px; overflow: hidden;
  justify-self: center; align-self: end;
}

/* L'ecart d'une journee par rapport a la graduation. Une troisieme colonne
   d'heures ne passerait pas a l'echelle -- une semaine peut traverser quatre
   pays -- alors qu'une annotation par journee tient dans n'importe quelle
   largeur et reste lisible. */
.pl-decal {
  display: inline-block; margin-left: 4px; padding: 0 4px;
  border-radius: 3px; background: var(--surface-2); color: var(--text-3);
  font-family: var(--font-mono, monospace); font-size: .62rem;
}
/* Un changement d'heure dans la periode affichee : la colonne de la maison ne
   vaut alors que pour une partie des journees. On le dit. */
.pl-alerte { color: #B4453C; font-weight: 700; margin-left: 2px; cursor: help; }

/* ---------- la bande : des barres qui s'etendent ----------
   Un hotel de trois nuits redessine dans trois colonnes se lit comme trois
   reservations. Une barre d'un bord a l'autre dit la duree d'un coup d'oeil. */
.pl-bande { display: grid; gap: 3px; padding: 4px 0; }
.pl-jour-item.est-barre {
  border-left-width: 4px;
  background: linear-gradient(to right,
    var(--surface-2) 0%, var(--surface-2) 96%, transparent 100%);
}
/* Un bord coupe n'est pas une heure : le vol de nuit s'arrete a minuit et
   reprend au matin. Sans marque, on lirait "atterrissage a minuit". */
.pl-bloc.est-continue { border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  border-bottom: 2px dashed rgba(255,255,255,.55); }
.pl-bloc.est-suite { border-top-left-radius: 0; border-top-right-radius: 0;
  border-top: 2px dashed rgba(255,255,255,.55); }


/* =========================================================================
   LE LIVRE DU VOYAGE

   ⚠ LA PAGE EST UN CONTENEUR, ET TOUT S Y MESURE EN PART DE PAGE. Le premier
     jet fixait les tailles en rem : a l ecran une page fait 1000 px de large,
     a l impression 297 mm, et le meme texte passait de lisible a minuscule.
     Avec `container-type: size` et des `cqw`, la composition est la MEME a
     toute echelle -- c est ce que promettaient deja les cadres en pourcentage.

   ⚠ CE QU ON VOIT EST CE QUI S IMPRIME, a un @media print pres. Deux mises en
     page separees se repondent de moins en moins : on compose a l ecran et
     l on decouvre le decalage au tirage, quand il a coute quarante euros.
   ========================================================================= */
.alb-livre { display: flex; flex-direction: column; gap: 20px; align-items: center; }
.alb-page {
  container-type: size;
  position: relative; width: 100%; max-width: 1000px;
  aspect-ratio: 297 / 210;           /* A4 paysage */
  background: var(--surface); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  overflow: hidden;
}
.alb-bloc { position: absolute; margin: 0; }
.alb-photo { overflow: hidden; background: var(--surface-2); }
.alb-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ⚠ LE TEXTE NE DOIT JAMAIS DEBORDER SUR LES PHOTOS. Un recit plus long que
   son cadre coulait par-dessus les images du dessous : illisible, et l on ne
   s en apercevait qu au tirage. Il est donc borne, et l on verra qu il manque
   de la place plutot que de le voir mordre ailleurs. */
/* ⚠ LE CORPS VIT SUR LE CADRE, PAS SUR LE PARAGRAPHE. C est le cadre que
     l editeur regle -- en ligne, en cqw -- et les paragraphes en heritent : les
     deux niveaux se seraient contredits, et un corps choisi a la main aurait ete
     ignore sans qu on sache pourquoi.
   ⚠ DEUX COLONNES PAR DEFAUT, ET LE RECIT CESSE D ETRE ROGNE. Une colonne
     unique laissait la moitie de la page vide ET tronquait les journees
     bavardes, la page etant a hauteur fixe. Le nombre de colonnes arrive en
     ligne : il se regle cadre par cadre. */
.alb-texte {
  padding: 0 .6cqw; overflow: hidden;
  font-size: 1.7cqw; line-height: 1.72;
  column-gap: 3.2cqw; orphans: 2; widows: 2;
}
.alb-texte h3 { margin: 0 0 .4em; font-size: 1.3em; line-height: 1.2; }
.alb-texte p  { margin: 0 0 .85em; font-size: inherit; line-height: inherit; }
.alb-texte p:last-child { margin-bottom: 0; }
/* Les paliers de corps : ils ne servent que quand aucun corps n a ete choisi a
   la main, et c est ce qui evite qu un recit bavard se fasse rogner. */
.alb-texte.est-aere  { font-size: 2cqw; }
.alb-texte.est-dense { font-size: 1.45cqw; }
.alb-texte.est-serre { font-size: 1.25cqw; }

/* ⚠ DU TEXTE POSE SUR UNE PHOTO A BESOIN D UN FOND. En pleine page, le recit
   se lit sur l image : sans voile, il devient illisible des que la photo est
   claire -- et c est justement la mise en page qu on veut pour une belle
   image. Le voile est sombre et le texte blanc, quelle que soit la photo. */
.alb-texte.est-sur-photo {
  padding: 1.4cqw 1.8cqw; border-radius: .8cqw;
  background: linear-gradient(180deg, rgba(8,14,17,.62), rgba(8,14,17,.78));
  color: #fff;
}
.alb-texte.est-sur-photo h3 { color: #fff; }

/* La couverture : le titre respire, le reste s efface. */
.alb-couv {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1.2cqw; text-align: center;
  padding: 0 12%;
}




/* ---------- la couverture en pleine image ----------
   ⚠ UNE PHOTO PLEIN CADRE, ET LE TITRE PAR-DESSUS. Un titre sur du blanc,
     c est une page de garde ; une image plein cadre, c est une couverture.
   ⚠ LE VOILE EST UN APLAT, PAS UN DEGRADE, ET C EST DELIBERE. Le generateur
     de PDF sait porter une couleur de fond ; il ne sait pas lire un
     `linear-gradient`. Un degrade aurait donne, a l impression, un titre blanc
     pose sur une photo nue -- donc illisible, exactement le defaut qu on veut
     eviter. Un aplat sort identique a l ecran et sur le papier.
   ⚠ ET IL EST ASSEZ DENSE POUR N IMPORTE QUELLE PHOTO. On ne sait pas ce que
     l editeur y mettra : une plage en plein soleil doit porter du texte blanc
     aussi surement qu une foret sombre. 52 %, c est ce qu il faut pour le
     pire des cas. */
.alb-couv-fond {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
}
.alb-couv-voile { position: absolute; inset: 0; background: rgba(12, 18, 22, .52); }
.alb-couv.est-sur-photo h2,
.alb-couv.est-sur-photo p,




.alb-titre { margin: 6% 0 4%; text-align: center; font-size: 3cqw; }
.alb-chiffres { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.2cqw; padding: 0 8%; }
.alb-chiffre { text-align: center; }
.alb-chiffre strong { display: block; font-size: 5cqw; color: var(--accent); line-height: 1; }
.alb-chiffre span {
  font-size: 1.3cqw; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .1em;
}
.alb-pays {
  text-align: center; margin: 5% 0 0; color: var(--text-2); font-size: 2cqw;
  /* Le drapeau et son nom ne se séparent jamais en bout de ligne, et les
     couples se répartissent d'eux-mêmes sur deux rangs si le voyage a traversé
     beaucoup de pays. */
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: center; gap: .35em 0.7em;
}
.alb-pays-un { display: inline-flex; align-items: center; gap: .45em; }
.alb-pays-sep { opacity: .5; }

/* Le point le plus eloigne : le chiffre qui dit le mieux ce qu on a fait. */
.alb-loin {
  position: absolute; left: 8%; right: 8%; bottom: 8%;
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: .8cqw 1.6cqw; text-align: center; font-size: 1.7cqw;
}
.alb-loin-de { text-align: right; font-weight: 600; }
.alb-loin-a  { text-align: left;  font-weight: 600; }
.alb-loin-km {
  padding: .5cqw 1.4cqw; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink); font-weight: 700;
}
.alb-loin-lab {
  grid-column: 1 / -1; font-size: 1.1cqw; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .1em;
}

/* ⚠ `alb-trace` ET NON `alb-carte` : la SECTION de la page du parcours porte
   deja `alb-carte` (la classe du genre). Les deux se confondaient, et la regle
   destinee au dessin -- 84 % de large, centre -- ecrasait la page entiere. */
.alb-trace { display: block; width: 84%; margin: 0 auto; color: var(--accent); }
.alb-legende {
  position: absolute; left: 8%; right: 8%; bottom: 6%;
  text-align: center; font-size: 1.4cqw; color: var(--text-3);
}

/* Les reperes pratiques : la date et le lieu se perdent en trois ans, et c est
   precisement ce qu on cherche en rouvrant un livre. */
.alb-reperes {
  position: absolute; left: 4%; right: 4%; bottom: 1.5%;
  display: flex; align-items: center; gap: 1.4cqw;
  font-size: 1.15cqw; color: var(--text-3);
}
.alb-reperes .alb-trace { width: 7cqw; margin: 0; flex: 0 0 auto; opacity: .8; }
.alb-ou { display: flex; flex-direction: column; line-height: 1.35; }
.alb-ou strong { color: var(--text-2); font-size: 1.35cqw; }
.alb-quand { margin-left: auto; }
.alb-folio { position: absolute; right: 2%; bottom: 1.5%; font-size: 1.1cqw; color: var(--text-3); }

/* ⚠ A L IMPRESSION, LA PAGE EST LA FEUILLE -- ET IL FAUT VISER LES VRAIES
     CLASSES. La premiere version masquait `.barre-haute`, `.tabs` et
     `footer.site`, qui n existent pas dans cette mise en page : l en-tete, la
     barre d onglets et la boite des originaux s imprimaient, et sept pages de
     livre en donnaient trente-sept.
   ⚠ ET LA HAUTEUR EN MILLIMETRES, PAS EN `vh` : combinee a `aspect-ratio`,
     `100vh` donnait une page plus haute que la feuille, qui debordait sur la
     suivante. */
@media print {
  @page { size: A4 landscape; margin: 0; }
  html, body { background: #fff; margin: 0; padding: 0; }
  .top, .tabbar, .tab-menu, .flash, .orig-boite, h1, .alb-outils, .alb-edit,
  .alb-versions,
  #alb-moteur { display: none !important; }
  main, main.avec-tabbar { margin: 0 !important; padding: 0 !important; max-width: none !important; }
  .alb-livre { display: block; gap: 0; }
  .alb-page {
    width: 297mm; height: 210mm; max-width: none; aspect-ratio: auto;
    border: 0; border-radius: 0; box-shadow: none;
    break-inside: avoid; break-after: page; page-break-after: always;
  }
  .alb-page:last-child { break-after: auto; page-break-after: auto; }
  /* ⚠ SANS CECI, LES APLATS ET LE TRACE DE LA CARTE NE S IMPRIMENT PAS : les
     navigateurs suppriment les fonds par defaut, pour economiser l encre. Sur
     un livre, c est tout le sujet qui disparait. */
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ---------- le chapitre d une etape ----------
   ⚠ CHAQUE ETAPE OUVRE UN CHAPITRE, ET LE CHAPITRE PORTE LE RECIT. Le premier
     jet melait texte et photos sur une meme page : le recit s y trouvait
     reduit a une legende, et l on ne savait plus ou une journee commencait. Un
     livre se feuillette -- il faut qu une page annonce « ici commence Hanoi »,
     avec de quoi situer le lieu, et que les images viennent ENSUITE.
   ⚠ LE TITRE EST GRAND, ET C EST TOUT LE PROPOS. A 3 cqw il se confondait avec
     un intertitre ; a 9 il devient l evenement de la page, comme dans les
     carnets imprimes. */


/* Le liseré sombre du bord gauche : il marque l ouverture d un chapitre quand
   on feuillette la tranche du livre. */




/* ⚠ LE PAYS AVEC SON DRAPEAU. « Houdan » n apprend rien a qui n y etait pas,
     et « France » en petites capitales se lit sans se voir ; un drapeau se
     reconnait avant d etre lu, et c est ce que font les carnets imprimes. Le
     filet gris tient les drapeaux tres clairs -- le japonais, l argentin --
     qui se fondraient sinon dans la page. */




/* ⚠ UNE MESURE ETROITE, ET C EST DE LA LISIBILITE, PAS DU GOUT. Une ligne de
   texte qui court sur 26 cm se relit mal : l oeil perd son retour a la ligne.
   Soixante-dix signes environ, comme un livre. */
/* ⚠ DEUX COLONNES, ET LE RECIT CESSE D ETRE ROGNE. La colonne unique a 46 cqw
     laissait la moitie de la page vide ET tronquait les journees bavardes : la
     page du chapitre est a hauteur fixe (inset: 0), ce qui depassait
     disparaissait sans un mot. Deux colonnes gardent la mesure d un livre --
     une quarantaine de signes -- et doublent la capacite.
   ⚠ LE CORPS DESCEND PAR PALIERS, choisis cote PHP (album_densite) d apres la
     longueur du texte, comme le fait un carnet imprime quand une journee a
     beaucoup a dire. Le plancher est 1,25 cqw : en dessous on ne lit plus, et
     le recit prend alors une page de suite plutot que de retrecir encore. */







/* Les reperes que le temps efface, et qu on cherche justement en rouvrant un
   livre : quel jour, quelle etape, combien d images. */






/* ---------- la suite d un recit trop long pour sa page ----------
   Pleine page, deux colonnes, et surtout PAS de second grand titre : on vient
   d en lire le debut, une nouvelle enseigne couperait la lecture au lieu de la
   porter. Un simple rappel du lieu suffit a se reperer. */
.alb-recit { background: var(--surface); }










/* ---------- la carte du parcours, pleine page ----------
   ⚠ RELEGUEE SOUS UN TITRE, DANS 84 % DE LA LARGEUR, elle ressemblait a une
     illustration. C est le parcours entier du voyage, et la page qu on regarde
     le plus longtemps : elle prend donc toute la feuille, et les noms sont
     poses SUR le dessin, comme sur une carte veritable -- une liste de treize
     villes sous l image obligeait a faire l aller-retour entre les deux. */
.alb-planche { position: absolute; inset: 0; display: flex; }
.alb-planche .alb-trace { width: 100%; height: 100%; margin: 0; }
.alb-trace-nom {
  font-size: 13px; fill: var(--text-2);
  font-family: var(--font-sans); letter-spacing: .02em;
  paint-order: stroke; stroke: #fff; stroke-width: 3px; stroke-linejoin: round;
}
.alb-planche-titre {
  position: absolute; left: 6cqw; top: 6cqh; margin: 0;
  font-size: 3.4cqw; text-transform: uppercase; letter-spacing: .1em;
}

/* ---------- le fond de carte du livre ----------
   ⚠ LE CREDIT DES TUILES EST DU, et sa place est SUR la carte : un livre
     imprime n a pas de bandeau d attribution ailleurs. Discret, mais present.
   Le trace, lui, reste vectoriel par-dessus le fond -- c est ce qui le garde
   net a l impression, la ou une capture d ecran serait floue. */
.alb-trace-credit {
  font-size: 9px; fill: #333; opacity: .72;
  font-family: var(--font-sans);
  paint-order: stroke; stroke: #fff; stroke-width: 2.5px; stroke-linejoin: round;
}
#alb-moteur:empty { display: none; }
#alb-moteur { margin: 6px 0 0; }

/* ---------- retoucher le livre ----------
   ⚠ TOUT CE QUI APPARTIENT A L EDITEUR PORTE `alb-edit`, et c est ce qui le
     tient hors du livre : `@media print` le cache, et album-pdf.js saute la
     classe. Sans cela, les boutons de retouche s imprimeraient -- et on ne s en
     apercevrait qu au tirage, quand il a deja coute quarante euros.
   ⚠ ET LA BARRE N APPARAIT QU AU SURVOL. Une rangee de boutons posee en
     permanence sur chaque page empecherait de JUGER la mise en page, qui est
     tout ce qu on vient faire ici. */
.alb-barre {
  position: absolute; top: 8px; right: 8px; z-index: 5;
  display: flex; gap: 4px; align-items: center; flex-wrap: wrap;
  max-width: 92%; padding: 5px 6px;
  background: rgba(255, 255, 255, .94);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .14);
  opacity: 0; transition: opacity .12s;
}
.alb-page:hover .alb-barre, .alb-barre:focus-within { opacity: 1; }
.alb-barre-nom {
  font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--text-3); margin-right: 2px;
}
.alb-b {
  font: inherit; font-size: 11px; line-height: 1.4;
  padding: 3px 7px; cursor: pointer;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--r-sm);
}
.alb-b:hover { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.alb-b.est-danger:hover { background: #b3261e; border-color: #b3261e; color: #fff; }

/* Le cadre saisi : un lisere, et le curseur qui dit ce qui va se passer. */
.alb-page:hover .alb-bloc[data-bloc] { outline: 1px dashed rgba(27, 107, 130, .55); }
.alb-bloc[data-bloc] { cursor: grab; }
.alb-bloc.est-saisi { cursor: grabbing; outline: 2px solid var(--accent) !important; }
.alb-poignee {
  position: absolute; right: -6px; bottom: -6px; width: 14px; height: 14px;
  background: var(--accent); border: 2px solid #fff; border-radius: 50%;
  cursor: nwse-resize; z-index: 6; opacity: 0; transition: opacity .12s;
}
.alb-bloc-outils {
  position: absolute; left: 4px; top: 4px; z-index: 6;
  display: flex; gap: 3px; opacity: 0; transition: opacity .12s;
}
.alb-bloc[data-bloc]:hover .alb-poignee,
.alb-bloc[data-bloc]:hover .alb-bloc-outils { opacity: 1; }

/* Les deux panneaux : choisir une photo, ecrire un texte. */
.alb-choix, .alb-saisie {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10, 16, 20, .55); padding: 24px;
}
.alb-choix[hidden], .alb-saisie[hidden] { display: none; }
.alb-choix-boite, .alb-saisie-boite {
  background: var(--surface); border-radius: var(--r-md);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .3);
  max-width: 900px; width: 100%; max-height: 82vh;
  display: flex; flex-direction: column; gap: 10px; padding: 14px;
}
.alb-choix-tete { display: flex; align-items: center; justify-content: space-between; }
.alb-choix-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 8px; overflow: auto; padding: 2px;
}
.alb-choix-item {
  padding: 0; border: 2px solid transparent; border-radius: var(--r-sm);
  background: none; cursor: pointer; aspect-ratio: 4 / 3; overflow: hidden;
}
.alb-choix-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.alb-choix-item:hover { border-color: var(--accent); }
.alb-saisie-boite label { display: flex; flex-direction: column; gap: 4px; }
.alb-saisie-boite textarea { resize: vertical; font: inherit; }

/* Le panneau des versions : il ne s imprime pas et ne s ouvre qu a la demande. */
.alb-versions { margin-bottom: 16px; }
.alb-versions .table td { padding: 6px 4px; vertical-align: middle; }

/* ---------- les cadres de structure : titre, carte, pays, reperes ----------
   ⚠ LE CHAPITRE ETAIT UNE MISE EN PAGE FIGEE EN DUR. Titre, mini-carte, pays,
     recit et reperes etaient poses par du HTML et du CSS : rien n y etait
     deplacable, redimensionnable ni meme ajoutable. Ce sont maintenant des
     CADRES, comme les photos -- meme allure qu avant, mais tout s y attrape.
   ⚠ LE CORPS ARRIVE EN LIGNE, EN CQW : c est un nombre libre, regle par
     l editeur, et il doit rester le meme sur un ecran de telephone comme sur
     une feuille A4. Ces regles ne fixent donc que ce qui ne se regle pas. */
.alb-cad-titre, .alb-cad-sur, .alb-cad-pays, .alb-cad-coord,
.alb-cad-jour, .alb-cad-dates {
  display: flex; align-items: center; overflow: hidden;
}
.alb-cad-titre { line-height: 1.02; letter-spacing: -.01em; }
.alb-cad-titre span { display: block; width: 100%; }
.alb-cad-sur span, .alb-cad-pays span, .alb-cad-coord span,
.alb-cad-jour span, .alb-cad-dates span { display: block; width: 100%; }
.alb-cad-sur { line-height: 1.3; }
.alb-cad-pays { gap: .9cqw; letter-spacing: .22em; }
.alb-cad-pays span { width: auto; }
/* Le filet gris tient les drapeaux tres clairs -- le japonais, l argentin --
   qui se fondraient sinon dans la page. */
.alb-cad-drapeau {
  width: 2.2em; height: auto; flex: none;
  border: 1px solid rgba(0, 0, 0, .18);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}
.alb-cad-coord { line-height: 1.5; letter-spacing: .04em; }
.alb-cad-dates { letter-spacing: .08em; }
.alb-cad-carte { display: flex; align-items: center; justify-content: center; }
.alb-cad-carte .alb-trace { width: 100%; height: 100%; margin: 0; }
.alb-cad-jour {
  justify-content: center;
  background: var(--accent); color: var(--accent-ink);
  letter-spacing: .16em;
}

/* Les reperes que le temps efface, et qu on cherche justement en rouvrant un
   livre : quel jour, quelle etape, combien d images. */
.alb-cad-faits {
  display: flex; gap: 6cqw; align-items: flex-end; justify-content: center;
  overflow: hidden;
}
.alb-cad-faits div { display: flex; flex-direction: column; gap: .3cqh; }
.alb-cad-faits span {
  font-size: .36em; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .16em;
}
.alb-cad-faits strong { line-height: 1; }

/* ---------- le style d un cadre, regle par l editeur ---------- */
.est-sans  { font-family: var(--font-sans); }
.est-serif { font-family: Georgia, "Times New Roman", Times, serif; }
.est-mono  { font-family: var(--font-mono); }
.est-gras     { font-weight: 700; }
.est-italique { font-style: italic; }
.align-left   { text-align: left; }
.align-center { text-align: center; }
.align-right  { text-align: right; }
.est-maj { text-transform: uppercase; }
.coul-texte  { color: var(--text); }
.coul-doux   { color: var(--text-2); }
.coul-faible { color: var(--text-3); }
.coul-accent { color: var(--accent); }
.coul-blanc  { color: #fff; }

/* Un cadre de texte vide est invisible, donc introuvable : on le dit -- et
   `alb-edit` tient ce repere hors du livre imprime. */
.alb-vide {
  font-size: 12px; color: var(--text-3); font-style: italic;
  border: 1px dashed var(--line); padding: 2px 6px; border-radius: var(--r-sm);
}

/* Le panneau de style d un cadre. */
.alb-style {
  position: fixed; inset: auto 0 0 0; z-index: 60;
  display: flex; justify-content: center; padding: 14px;
  background: rgba(10, 16, 20, .55);
}
.alb-style[hidden] { display: none; }
.alb-style-boite {
  background: var(--surface); border-radius: var(--r-md);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .3);
  padding: 14px; max-width: 1000px; width: 100%;
}
.alb-style-boite label { display: flex; flex-direction: column; gap: 3px; }
.alb-style-boite .row label.small { flex-direction: row; align-items: center; gap: 5px; }

/* Un cadre dont le texte deborde : on le SIGNALE plutot que de le rogner en
   silence. `alb-edit` le tient hors du livre imprime. */
.alb-trop {
  position: absolute; right: 2px; top: 2px; z-index: 4;
  font-size: 13px; line-height: 1; color: #b3261e;
  background: rgba(255, 255, 255, .9); border-radius: 50%;
  padding: 2px 3px; cursor: help;
}

/* ---------- le mini editeur de texte ----------
   ⚠ LA MISE EN FORME PORTE SUR LA SELECTION, pas sur la boite : c est la limite
     qu on atteint des qu on veut trois mots en gras ou un nom de lieu dans une
     autre couleur. Les classes sont un catalogue ferme -- la feuille de style
     reste seule maitresse de ce qu elles valent, a l ecran comme au tirage. */
.alb-zone {
  min-height: 200px; max-height: 44vh; overflow: auto;
  line-height: 1.6; white-space: normal;
}
.alb-zone p { margin: 0 0 .7em; }
.alb-zone p:last-child { margin-bottom: 0; }
.alb-mef-sep { width: 1px; align-self: stretch; background: var(--line); margin: 0 3px; }
.alb-pastille { font-weight: 700; width: 26px; text-align: center; }
.alb-pastille.coul-blanc { background: var(--text); }

/* Les tailles relatives d un passage : elles suivent le corps du cadre, donc
   elles restent justes quand on regle ce corps. */
.taille-petit { font-size: .78em; }
.taille-grand { font-size: 1.35em; }
.alb-mef-nom {
  font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--text-3); margin-right: 1px;
}
.alb-b[disabled] { opacity: .35; cursor: default; }
.alb-b[disabled]:hover { background: var(--surface-2); color: var(--text); border-color: var(--line); }
.alb-zone-titre { min-height: 0; max-height: none; font-size: 1.15rem; font-weight: 700; }

/* ---------- la palette d un passage de texte ----------
   ⚠ DES CLASSES, PAS DES COULEURS EN LIGNE. La feuille reste seule maitresse
     des teintes : le jour ou la palette du livre change, les mots colores
     suivent. Un `style="color:#f00"` range en base aurait fige la teinte et
     ouvert la porte a tout le reste des styles.
   ⚠ ET DES TEINTES QUI S IMPRIMENT. Elles sont choisies un peu sourdes : un
     rouge pur bave a l impression et fatigue a la lecture d une page entiere. */
.coul-noir      { color: #101a1e; }
.coul-rouge     { color: #b3261e; }
.coul-orange    { color: #c05621; }
.coul-ambre     { color: #a1740b; }
.coul-vert      { color: #3f7d20; }
.coul-sapin     { color: #1f5c3d; }
.coul-turquoise { color: #0f7c8a; }
.coul-bleu      { color: #1f5fa8; }
.coul-violet    { color: #6b3fa0; }
.coul-rose      { color: #a63a6b; }
.coul-brun      { color: #7a4a2b; }
.coul-ardoise   { color: #566a72; }

/* Les tailles relatives d un passage : elles suivent le corps du cadre, donc
   elles restent justes quand on regle ce corps. */
.taille-xs { font-size: .62em; }
.taille-xl { font-size: 1.8em; }

/* Le nuancier de la barre : des pastilles, pas une liste deroulante -- on
   choisit une couleur en la voyant. */
.alb-nuancier { display: flex; gap: 3px; flex-wrap: wrap; max-width: 210px; }
.alb-teinte {
  width: 18px; height: 18px; padding: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 3px;
  background: currentColor; font-size: 0;
}
.alb-teinte:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
.alb-teinte.coul-blanc { background: #fff; }
.alb-mef-taille { width: 66px; padding: 2px 4px; font-size: 12px; }

