@charset "UTF-8";
/*
 * Liseuse magazine interne — Smart City Mag
 * Feuille chargée uniquement sur menu_choice 210 (connexion) et 211 (lecture),
 * par includes/liseuse.php et includes/liseuse_login.php.
 * Le suffixe suit $version (ADMcoetv.php).
 *
 * Conventions du dépôt respectées ici :
 *  - toutes les classes sont préfixées liseuse_ en snake_case (il n'y a pas de
 *    BEM dans styles_<version>.css) ;
 *  - AUCUNE variable CSS n'est posée sur :root — la feuille de production n'en
 *    utilise aucune, et polluer :root exposerait ces jetons à tout le site.
 *    Ils sont portés par #liseuse, et par .liseuse_login pour la page de
 *    connexion qui n'a pas de #liseuse ;
 *  - le reset global du site applique margin/padding/border à zéro, font:inherit
 *    et outline:none à div, span, p, a, img, form, label… : les indicateurs de
 *    focus et les tailles de police sont donc redéclarés explicitement ici.
 *    input et button, eux, ne sont PAS dans la liste du reset : leurs styles UA
 *    sont neutralisés explicitement.
 *
 * ÉCHELLE DE Z-INDEX — cohabitation avec styles_<version>.css
 *   .mag_preview_content ... 2000
 *   .website_click ......... 2500
 *   .reg_form_container .... 3000
 *   en-tête mobile ......... 50000
 *
 *   En flux normal, #liseuse crée son PROPRE contexte d'empilement
 *   (isolation:isolate, z-index:1) : ses valeurs internes (10 à 45) ne peuvent
 *   pas concurrencer l'échelle ci-dessus, quelle que soit leur valeur.
 *
 *   En pseudo-plein-écran, le choix est ASSUMÉ : z-index 60000, donc AU-DESSUS
 *   de l'en-tête mobile (50000). Motif : le pseudo-plein-écran n'existe que
 *   parce que l'API Fullscreen est absente sur iPhone ; laisser l'en-tête
 *   mobile flotter par-dessus une page qu'on vient de passer en plein écran
 *   serait un défaut visible, pas une précaution. La classe n'est posée que sur
 *   action explicite de l'utilisateur, et html.liseuse_fs_open bloque pendant
 *   ce temps le défilement de la page.
 */

/* =========================================================================
 * 1. Racine et jetons
 * ====================================================================== */

#liseuse {
  --liseuse-bg:        #23262c;   /* fond du viewport */
  --liseuse-chrome:    #16181d;   /* barres */
  --liseuse-btn:       #2a2e36;   /* fond de bouton — blanc dessus : 13,6:1 */
  --liseuse-btn-hover: #3a404b;
  --liseuse-fg:        #ffffff;
  --liseuse-fg-soft:   #c9cdd6;   /* sur --liseuse-chrome : 11,4:1 */
  --liseuse-accent:    #4961a7;   /* bleu Smart City — blanc dessus : 5,8:1 */
  --liseuse-focus:     #8fa8e8;   /* sur fond sombre : 7,4:1 */
  --liseuse-bar-h:     48px;      /* barre haute */
  --liseuse-strip-h:   56px;      /* barre à vignettes basse */
  --liseuse-radius:    4px;

  position: relative;
  isolation: isolate;             /* contexte d'empilement local */
  z-index: 1;
  display: block;
  width: 100%;
  height: 82vh;
  height: 82dvh;                  /* dvh suit la barre d'URL iOS */
  min-height: 380px;
  max-height: 1200px;
  overflow: hidden;
  background: var(--liseuse-bg);
  color: var(--liseuse-fg);
  font-family: 'Open Sans', Arial, Helvetica, sans-serif;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

#liseuse:focus { outline: none; }
#liseuse:focus-visible { outline: 2px solid var(--liseuse-focus); outline-offset: -2px; }

/* Texte réservé aux technologies d'assistance. */
#liseuse .liseuse_sr,
.liseuse_login .liseuse_sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* =========================================================================
 * 2. Viewport, scène et calques
 * ====================================================================== */

#liseuse .liseuse_viewport {
  position: absolute;
  top: var(--liseuse-bar-h);
  left: 0;
  right: 0;
  bottom: var(--liseuse-strip-h);
  overflow: hidden;               /* JAMAIS sur un ancêtre porteur d'un contexte
                                     3D — il n'y en a pas ici, le feuilletage 3D
                                     a été écarté au profit du fondu */
  background: var(--liseuse-bg);
  touch-action: none;             /* sinon le navigateur défile au lieu de zoomer */
  cursor: default;
}

#liseuse .liseuse_stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform-origin: 0 0;
  transform: translate3d(0, 0, 0) scale(1);
}

#liseuse .liseuse_layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  opacity: 0;
  pointer-events: none;
  /* Fondu croisé : opacity SEULE, propriété compositée. Pas de rotateY, pas de
     clip-path. La durée est écrite par le JavaScript, à 0 ms lorsque
     prefers-reduced-motion est actif (RGAA / WCAG 2.3.3) : ne pas la figer ici. */
  transition-property: opacity;
  transition-timing-function: linear;
  transition-duration: 180ms;
  will-change: opacity;
}

#liseuse .liseuse_layer_on {
  opacity: 1;
  pointer-events: auto;
}

#liseuse .liseuse_page {
  position: relative;
  flex: 0 0 auto;
  overflow: hidden;
  background: #ffffff;
  box-shadow: 0 2px 14px rgba(0, 0, 0, .45);
}

#liseuse .liseuse_page:focus { outline: none; }
#liseuse .liseuse_page:focus-visible {
  outline: 2px solid var(--liseuse-focus);
  outline-offset: 3px;
}

#liseuse .liseuse_img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill;               /* le conteneur porte déjà le ratio exact */
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;           /* la sélection revient au calque texte */
}

/* Accès partiel : la vignette 240 agrandie et floutée remplace la page. */
#liseuse .liseuse_img_blur {
  filter: blur(8px);
  transform: scale(1.06);         /* masque le halo de bord du flou */
}

#liseuse .liseuse_page_error { background: #2f333b; }

#liseuse .liseuse_page_error::after {
  content: "Page indisponible";
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  transform: translateY(-50%);
  text-align: center;
  font-size: 13px;
  color: var(--liseuse-fg-soft);
}

/* =========================================================================
 * 3. Calque texte
 * ====================================================================== */

#liseuse .liseuse_text {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  overflow: hidden;
  pointer-events: none;           /* seuls les span reçoivent les pointeurs */
  transform-origin: 0 0;
}

/*
 * --scale-factor = pixels par point PDF, posé PAR PAGE par le JavaScript.
 * Il ne sert QU'À convertir les points PDF en pixels CSS : le zoom est une
 * transform posée sur #liseuse-stage, les calques enfants sont donc DÉJÀ mis à
 * l'échelle par le compositeur. Y réappliquer le facteur de zoom doublerait la
 * taille du texte — c'est l'erreur classique de ce montage.
 * --sx corrige la largeur du mot pour compenser l'écart entre la police du PDF
 * et celle du navigateur ; il est invariant au redimensionnement.
 */
#liseuse .liseuse_text span {
  position: absolute;
  white-space: pre;
  pointer-events: auto;
  cursor: text;
  user-select: text;
  -webkit-user-select: text;
  color: transparent;
  line-height: 1;
  font-family: sans-serif;
  font-weight: 400;
  transform-origin: 0 0;
  forced-color-adjust: none;      /* survit au mode contraste élevé Windows */
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
  left:      calc(var(--scale-factor) * var(--x));
  top:       calc(var(--scale-factor) * var(--y));
  font-size: calc(var(--scale-factor) * var(--fh));
  transform: scaleX(var(--sx, 1));
}

#liseuse .liseuse_text span::selection {
  background: rgba(73, 97, 167, .38);
  color: transparent;
}

#liseuse .liseuse_text span::-moz-selection {
  background: rgba(73, 97, 167, .38);
  color: transparent;
}

/* =========================================================================
 * 4. Aperçu par vignettes pendant le glissé de la barre
 * ====================================================================== */

#liseuse .liseuse_scrub {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  background: var(--liseuse-bg);
}

#liseuse .liseuse_scrub[hidden] { display: none; }

/* Vignettes 100 px agrandies : le flou est assumé, il n'est visible que
   pendant le glissé — c'est le prix d'un curseur utilisable. */
#liseuse .liseuse_scrub_img {
  display: block;
  max-height: 84%;
  max-width: 46%;
  background: #ffffff;
  box-shadow: 0 2px 14px rgba(0, 0, 0, .45);
}

#liseuse .liseuse_scrub_img[hidden] { display: none; }

/* =========================================================================
 * 5. Flèches de bord (#liseuse-prev / #liseuse-next)
 * ====================================================================== */

#liseuse .liseuse_nav {
  position: absolute;
  top: calc(var(--liseuse-bar-h) + (100% - var(--liseuse-bar-h) - var(--liseuse-strip-h)) / 2);
  transform: translateY(-50%);
  z-index: 20;
  width: 46px;
  height: 76px;
  padding: 0;
  border: 0;
  border-radius: var(--liseuse-radius);
  background: rgba(22, 24, 29, .74);
  color: var(--liseuse-fg);
  cursor: pointer;
  opacity: .55;
  transition: opacity 120ms linear, background-color 120ms linear;
}

/* Les boutons sont vides côté PHP : le chevron est dessiné ici. */
#liseuse .liseuse_nav::before {
  display: block;
  font-size: 30px;
  line-height: 1;
  text-align: center;
}

#liseuse .liseuse_nav_prev::before { content: "\2039"; }
#liseuse .liseuse_nav_next::before { content: "\203A"; }

#liseuse .liseuse_nav:hover { opacity: 1; background: rgba(22, 24, 29, .92); }
#liseuse .liseuse_nav:focus { outline: none; }
#liseuse .liseuse_nav:focus-visible {
  opacity: 1;
  outline: 2px solid var(--liseuse-focus);
  outline-offset: 2px;
}
#liseuse .liseuse_nav[disabled] { opacity: .12; cursor: default; }
#liseuse .liseuse_nav_prev { left: 8px; }
#liseuse .liseuse_nav_next { right: 8px; }

#liseuse.liseuse_zoomed .liseuse_nav { display: none; }

/* =========================================================================
 * 6. Barre haute (#liseuse-bar)
 * ====================================================================== */

#liseuse .liseuse_bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  height: var(--liseuse-bar-h);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 12px;
  background: var(--liseuse-chrome);
  transition: opacity 140ms linear, transform 140ms ease-out;
}

#liseuse .liseuse_bar_title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 14px;
  font-weight: 600;
  color: var(--liseuse-fg);
}

#liseuse .liseuse_bar_pager,
#liseuse .liseuse_bar_tools {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
}

#liseuse .liseuse_pager_input {
  width: 50px;
  height: 30px;
  padding: 0 6px;
  border: 1px solid #4a5060;
  border-radius: var(--liseuse-radius);
  background: #0f1116;
  color: var(--liseuse-fg);
  font-family: inherit;
  font-size: 13px;
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
}

#liseuse .liseuse_pager_input:focus { outline: none; border-color: var(--liseuse-focus); }
#liseuse .liseuse_pager_input:focus-visible {
  outline: 2px solid var(--liseuse-focus);
  outline-offset: 1px;
}

#liseuse .liseuse_pager_sep,
#liseuse .liseuse_pager_total {
  font-size: 13px;
  color: var(--liseuse-fg-soft);   /* 11,4:1 */
  font-variant-numeric: tabular-nums;
}

#liseuse .liseuse_btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 34px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--liseuse-radius);
  background: var(--liseuse-btn);
  color: var(--liseuse-fg);        /* 13,6:1 */
  font-family: inherit;
  font-size: 18px;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms linear;
}

#liseuse .liseuse_btn:hover { background: var(--liseuse-btn-hover); }
#liseuse .liseuse_btn:focus { outline: none; }
#liseuse .liseuse_btn:focus-visible {
  outline: 2px solid var(--liseuse-focus);
  outline-offset: 2px;
}
#liseuse .liseuse_btn[disabled] {
  opacity: .35;
  cursor: default;
  background: var(--liseuse-btn);
}

/* =========================================================================
 * 7. Barre à vignettes (#liseuse-strip)
 * ====================================================================== */

#liseuse .liseuse_strip {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  height: var(--liseuse-strip-h);
  display: flex;
  align-items: center;
  padding: 0 20px;
  background: var(--liseuse-chrome);
  transition: opacity 140ms linear, transform 140ms ease-out;
}

#liseuse .liseuse_strip_track {
  position: relative;
  flex: 1 1 auto;
  height: 26px;
  cursor: pointer;
  touch-action: none;              /* le glissé pilote le curseur, pas le défilement */
}

/* La piste elle-même, dessinée en ::before pour laisser le curseur seul enfant. */
#liseuse .liseuse_strip_track::before {
  content: "";
  position: absolute;
  top: 11px;
  left: 0;
  right: 0;
  height: 4px;
  border-radius: 2px;
  background: #454b57;
}

#liseuse .liseuse_strip_track:focus { outline: none; }
#liseuse .liseuse_strip_track:focus-visible {
  outline: 2px solid var(--liseuse-focus);
  outline-offset: 1px;
  border-radius: var(--liseuse-radius);
}

#liseuse .liseuse_strip_cursor {
  position: absolute;
  top: 5px;
  left: 0;
  width: 16px;
  height: 16px;
  margin-left: -8px;
  border-radius: 50%;
  background: var(--liseuse-fg);
  box-shadow: 0 0 0 3px var(--liseuse-accent);
  pointer-events: none;
}

/* Bulle flottante : vignette 100 px + numéro de page visé. */
#liseuse .liseuse_strip_peek {
  position: absolute;
  bottom: calc(var(--liseuse-strip-h) - 6px);
  left: 0;
  z-index: 35;
  transform: translateX(-50%);
  padding: 6px;
  border-radius: var(--liseuse-radius);
  background: var(--liseuse-chrome);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .5);
  text-align: center;
  pointer-events: none;
}

#liseuse .liseuse_strip_peek[hidden] { display: none; }

#liseuse .liseuse_strip_peek_img {
  display: block;
  width: auto;
  height: 100px;
  background: #ffffff;
}

#liseuse .liseuse_strip_peek_label {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  color: var(--liseuse-fg);
  font-variant-numeric: tabular-nums;
}

/* =========================================================================
 * 8. Zoom : curseurs et retrait des barres
 * ====================================================================== */

#liseuse.liseuse_zoomed .liseuse_viewport { cursor: grab; }
#liseuse.liseuse_zoomed .liseuse_viewport:active { cursor: grabbing; }

/* Au-delà de 1x le glissé déplace l'image : le calque texte ne doit plus
   capturer le geste, sinon on sélectionne du texte au lieu de se déplacer. */
#liseuse.liseuse_zoomed .liseuse_text,
#liseuse.liseuse_zoomed .liseuse_text span {
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

/* Zoom actif : les deux barres se retirent. Elles reviennent quand le pointeur
   approche du haut ou du bas (classe liseuse_bar_peek posée par le JavaScript)
   et, au clavier, dès qu'un de leurs contrôles reçoit le focus —
   pointer-events:none n'empêche pas la tabulation. */
#liseuse.liseuse_zoomed .liseuse_bar {
  opacity: 0;
  transform: translateY(-100%);
  pointer-events: none;
}

#liseuse.liseuse_zoomed .liseuse_strip {
  opacity: 0;
  transform: translateY(100%);
  pointer-events: none;
}

#liseuse.liseuse_zoomed .liseuse_bar:focus-within,
#liseuse.liseuse_zoomed .liseuse_strip:focus-within,
#liseuse.liseuse_zoomed.liseuse_bar_peek .liseuse_bar,
#liseuse.liseuse_zoomed.liseuse_bar_peek .liseuse_strip {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* =========================================================================
 * 9. Écran d'accroche (#liseuse-gate)
 * ====================================================================== */

#liseuse .liseuse_gate {
  position: absolute;
  top: var(--liseuse-bar-h);
  left: 0;
  right: 0;
  bottom: var(--liseuse-strip-h);
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(16, 18, 22, .62);
}

#liseuse .liseuse_gate[hidden] { display: none; }

#liseuse .liseuse_gate_inner {
  max-width: 460px;
  padding: 26px 28px;
  border-radius: 6px;
  background: #ffffff;
  color: #333333;
  text-align: center;
  box-shadow: 0 10px 40px rgba(0, 0, 0, .5);
}

#liseuse .liseuse_gate_title {
  margin-bottom: 10px;
  font-family: 'Roboto', 'Open Sans', Arial, sans-serif;
  font-size: 20px;
  font-weight: 700;
  color: #4961a7;                  /* 5,8:1 sur blanc */
}

#liseuse .liseuse_gate_text {
  margin-bottom: 18px;
  font-size: 14px;
  line-height: 1.55;
  color: #333333;                  /* 12,6:1 */
}

#liseuse .liseuse_gate_actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: center;
}

/* .readButton n'est stylé dans styles_<version>.css que sous .mag_listCalameo :
   sans cette règle, l'appel à l'abonnement serait un simple lien nu. */
#liseuse .liseuse_gate_cta {
  display: inline-block;
  padding: 11px 22px;
  border-radius: var(--liseuse-radius);
  background: var(--liseuse-accent);
  color: #ffffff;                  /* 5,8:1 */
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
}

#liseuse .liseuse_gate_cta:hover { background: #3d5292; }

#liseuse .liseuse_gate_login {
  font-size: 13px;
  color: #2c3a63;                  /* 10,9:1 sur blanc */
  text-decoration: underline;
}

#liseuse .liseuse_gate_cta:focus-visible,
#liseuse .liseuse_gate_login:focus-visible {
  outline: 2px solid #1d2b57;
  outline-offset: 2px;
}

/* =========================================================================
 * 10. Plein écran
 * ====================================================================== */

/* Plein écran natif : l'élément est déjà dans la couche supérieure du
   navigateur, il suffit d'occuper toute la surface. Les deux sélecteurs sont
   séparés : un sélecteur inconnu invaliderait toute la règle groupée. */
#liseuse:fullscreen {
  width: 100%;
  height: 100%;
  max-height: none;
  min-height: 0;
}

#liseuse:-webkit-full-screen {
  width: 100%;
  height: 100%;
  max-height: none;
  min-height: 0;
}

/*
 * Pseudo-plein-écran — OBLIGATOIRE, pas optionnel : l'API Fullscreen n'existe
 * pas sur iPhone (WebKit 212934 clos WONTFIX le 25/01/2026 ; 206854 toujours
 * ouvert). Elle fonctionne sur iPad, pas sur iPhone.
 * z-index 60000 : au-dessus de l'en-tête mobile (50000). Choix assumé, motivé
 * en tête de fichier.
 */
#liseuse.liseuse_pseudo_fs {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60000;
  width: 100vw;
  width: 100dvw;
  height: 100vh;
  height: 100dvh;
  max-height: none;
  min-height: 0;
  margin: 0;
}

html.liseuse_fs_open,
html.liseuse_fs_open body {
  overflow: hidden;
}

/* =========================================================================
 * 11. Repli sans JavaScript
 * ====================================================================== */

.liseuse_noscript {
  margin: 20px auto;
  padding: 16px 18px;
  max-width: 640px;
  border-radius: 6px;
  background: #fdecec;
  color: #97161f;                  /* 6,5:1 sur #fdecec */
  font-family: 'Open Sans', Arial, Helvetica, sans-serif;
  font-size: 14px;
  line-height: 1.55;
  text-align: center;
}

.liseuse_noscript a { color: #97161f; text-decoration: underline; }

/* =========================================================================
 * 12. Responsive
 *   >= 1024 : double page, barres complètes
 *   700-1023 : double page, barres condensées
 *   < 700    : page simple (bascule côté JavaScript), barres réduites
 * ====================================================================== */

@media (max-width: 1023px) {
  #liseuse {
    --liseuse-bar-h: 44px;
    --liseuse-strip-h: 50px;
  }
  #liseuse .liseuse_bar_title { font-size: 13px; }
  #liseuse .liseuse_nav { width: 40px; height: 64px; }
  #liseuse .liseuse_nav::before { font-size: 26px; }
}

@media (max-width: 699px) {
  #liseuse {
    --liseuse-bar-h: 42px;
    --liseuse-strip-h: 46px;
    height: 74vh;
    height: 74dvh;
    min-height: 320px;
  }
  /* Le feuilletage se fait au balayage horizontal : les flèches de bord
     mangeraient la largeur utile sur un écran étroit. */
  #liseuse .liseuse_nav { display: none; }
  /* Le titre du numéro est déjà dans le fil de la page : sur mobile il ne vaut
     pas la place qu'il prend dans la barre. */
  #liseuse .liseuse_bar_title { display: none; }
  #liseuse .liseuse_bar { justify-content: space-between; gap: 6px; padding: 0 8px; }
  #liseuse .liseuse_strip { padding: 0 16px; }
  #liseuse .liseuse_btn { min-width: 32px; height: 32px; font-size: 16px; }
  #liseuse .liseuse_pager_input { width: 44px; height: 28px; }
  #liseuse .liseuse_strip_peek_img { height: 78px; }
  #liseuse .liseuse_gate_inner { padding: 20px 18px; }
  #liseuse .liseuse_gate_title { font-size: 17px; }
}

/* Repli pour les navigateurs sans :focus-visible : on retombe sur :focus,
   le reset global du site ayant supprimé tous les contours. */
@supports not selector(:focus-visible) {
  #liseuse .liseuse_btn:focus,
  #liseuse .liseuse_nav:focus,
  #liseuse .liseuse_strip_track:focus,
  #liseuse .liseuse_pager_input:focus {
    outline: 2px solid var(--liseuse-focus);
    outline-offset: 2px;
  }
}

/* Mode contraste élevé (Windows) : les couleurs sont remplacées par celles du
   système, on rend donc les bordures des contrôles explicites. */
@media (forced-colors: active) {
  #liseuse .liseuse_btn,
  #liseuse .liseuse_nav,
  #liseuse .liseuse_pager_input {
    border: 1px solid ButtonText;
  }
  #liseuse .liseuse_strip_cursor { box-shadow: none; border: 2px solid Highlight; }
}

/* =========================================================================
 * 13. Page de connexion (menu_choice 210)
 *
 *   Rendue par includes/liseuse_login.php à l'intérieur de .generic_content :
 *   les styles restent volontairement légers, ils ne font qu'habiller le
 *   formulaire dans le gabarit existant du site.
 * ====================================================================== */

.liseuse_login {
  --liseuse-radius: 4px;
  max-width: 460px;
  font-family: 'Open Sans', Arial, Helvetica, sans-serif;
  color: #333333;
}

.liseuse_login p { margin-bottom: 14px; font-size: 14px; line-height: 1.6; }

.liseuse_login .liseuse_login_intro,
.liseuse_login .liseuse_login_already { color: #555555; }   /* 7,5:1 sur blanc */

.liseuse_login .liseuse_login_expired {
  padding: 10px 12px;
  border-radius: var(--liseuse-radius);
  background: #fdecec;
  color: #97161f;                  /* 6,5:1 */
  font-size: 13px;
}

.liseuse_login .liseuse_login_field { margin-bottom: 14px; }

.liseuse_login label {
  display: block;
  margin-bottom: 5px;
  font-size: 13px;
  font-weight: 600;
  color: #333333;
}

.liseuse_login input[type="email"],
.liseuse_login input[type="password"],
.liseuse_login input[type="text"] {
  display: block;
  width: 100%;
  height: 40px;
  padding: 0 10px;
  border: 1px solid #b8bcc5;
  border-radius: var(--liseuse-radius);
  background: #ffffff;
  font-family: inherit;
  font-size: 14px;
  color: #333333;
}

.liseuse_login input:focus {
  border-color: #4961a7;
  outline: 2px solid #4961a7;
  outline-offset: 0;
}

/* role="alert" + hidden : le message n'est annoncé qu'au moment où le JS le
   révèle. Ne jamais le masquer par opacity, il serait lu au chargement. */
.liseuse_login .liseuse_login_error {
  padding: 10px 12px;
  border-radius: var(--liseuse-radius);
  background: #fdecec;
  color: #97161f;                  /* 6,5:1 */
  font-size: 13px;
}

.liseuse_login .liseuse_login_error[hidden] { display: none; }

.liseuse_login .liseuse_login_submit { margin-top: 6px; }

/* Comme dans l'écran d'accroche : .readButton n'est stylé que sous
   .mag_listCalameo dans la feuille du site. */
.liseuse_login .readButton {
  display: inline-block;
  min-width: 160px;
  padding: 12px 22px;
  border: 0;
  border-radius: var(--liseuse-radius);
  background: #4961a7;
  color: #ffffff;                  /* 5,8:1 */
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.liseuse_login .readButton:hover { background: #3d5292; }
.liseuse_login .readButton[disabled] { opacity: .6; cursor: default; }
.liseuse_login .readButton:focus { outline: none; }
.liseuse_login .readButton:focus-visible {
  outline: 2px solid #1d2b57;
  outline-offset: 2px;
}

.liseuse_login .liseuse_login_help,
.liseuse_login .liseuse_login_signup {
  margin-top: 16px;
  font-size: 13px;
  color: #555555;
}

/* --- Gestion du compte : déconnexion, changement de mot de passe -----------
   Le bouton secondaire est en retrait volontaire : « Accéder à la lecture »
   reste l'action principale de la page, « Se déconnecter » ne doit pas lui
   disputer l'attention. Contraste conservé au-dessus de 4,5:1. */

.liseuse_login .readButton.liseuse_login_secondary {
  background: #ffffff;
  color: #3d5292;                  /* 7,1:1 sur blanc */
  border: 1px solid #c3ccdf;
  font-weight: 500;
}

.liseuse_login .readButton.liseuse_login_secondary:hover {
  background: #eef1f8;
  border-color: #4961a7;
}

.liseuse_login .liseuse_login_chpwd {
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid #e4e8f1;
}

.liseuse_login .liseuse_login_chpwd > summary {
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  color: #3d5292;
  list-style: revert;              /* la puce native indique l'état ouvert/fermé */
}

.liseuse_login .liseuse_login_chpwd > summary:focus-visible {
  outline: 2px solid #1d2b57;
  outline-offset: 2px;
}

.liseuse_login .liseuse_login_chpwd[open] > summary { margin-bottom: 14px; }

.liseuse_login .liseuse_login_hint {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: #555555;                  /* 7,5:1 sur blanc */
}

/* « Se souvenir de cet ordinateur ». La case est DANS le <label> : toute la ligne
   devient cliquable, sans dépendre d'un attribut for/id correctement apparié. */
.liseuse_login .liseuse_login_remember label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 0;
  font-weight: 400;
  text-transform: none;
  cursor: pointer;
}

.liseuse_login .liseuse_login_remember input[type="checkbox"] {
  width: auto;
  margin: 0;
  flex: 0 0 auto;
}

/* Le formulaire de réinitialisation partage .liseuse_login_form avec celui de
   connexion : on le sépare visuellement pour qu'on ne confonde pas les deux
   champs « adresse électronique » de la page. */
#liseuse-reset-form {
  margin-top: 10px;
  padding: 14px 16px;
  border: 1px solid #e4e8f1;
  border-radius: var(--liseuse-radius);
  background: #fafbfd;
}

.liseuse_login .liseuse_login_help a,
.liseuse_login .liseuse_login_signup a {
  color: #4961a7;                  /* 5,8:1 sur blanc */
  text-decoration: underline;
}

@supports not selector(:focus-visible) {
  .liseuse_login .readButton:focus {
    outline: 2px solid #1d2b57;
    outline-offset: 2px;
  }
}

/* =========================================================================
 * 14. États posés par le JavaScript sur #liseuse
 *
 *   Ces cinq classes sont écrites par js/liseuse_<version>.js. Elles sont
 *   regroupées ici, après les requêtes média de la section 12, pour que leur
 *   cascade soit lisible d'un seul tenant : à spécificité égale, ce sont donc
 *   ces règles qui l'emportent.
 * ====================================================================== */

/* --- .liseuse_ready : révélation à l'initialisation ---------------------
   Posée à la toute fin de Reader.start(). Avant elle, la scène est vide — les
   images sont chargées en fetch() — et la barre, les flèches et la barre à
   vignettes ne répondent à rien : on ne montre pas ce squelette inerte.
   Le fond de #liseuse reste peint et la boîte garde sa hauteur : rien ne saute
   au moment de la révélation, la transition d'opacité déjà déclarée sur la
   barre et sur la barre à vignettes (sections 6 et 7) fait le reste.
   visibility, et pas seulement opacity : une opacité à zéro laisserait la
   saisie de page et les boutons dans le parcours de tabulation.
   Sans JavaScript la classe n'est jamais posée et les contrôles restent
   masqués — c'est le cas que couvre le repli .liseuse_noscript (section 11). */
#liseuse:not(.liseuse_ready) .liseuse_bar,
#liseuse:not(.liseuse_ready) .liseuse_nav,
#liseuse:not(.liseuse_ready) .liseuse_strip {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* --- .liseuse_single : mode page simple ---------------------------------
   Posée par setMode() sous SINGLE_MAX_W (700 px), le même seuil que la requête
   média de la section 12. Ces règles sont attachées au MODE et non à la
   largeur : elles restent justes si SINGLE_MAX_W change. */

/* Le feuilletage se fait au balayage horizontal : les flèches de bord
   mangeraient la largeur utile. Doublon assumé avec la requête média, qui
   couvre l'intervalle où la classe n'est pas encore posée. */
#liseuse.liseuse_single .liseuse_nav { display: none; }

/* Une seule vignette est affichée pendant le glissé (la seconde est mise à
   hidden par showPreview) : elle peut occuper toute la largeur utile au lieu
   des 46 % réservés à une double page. */
#liseuse.liseuse_single .liseuse_scrub_img { max-width: 92%; }

/* --- .liseuse_gated : écran d'accroche ouvert ---------------------------
   Posée par showGate(). Le voile de .liseuse_gate assombrit déjà la scène ; on
   l'atténue en plus pour que la page floutée derrière le message ne soit pas
   prise pour un rendu en cours de chargement. La navigation reste ACTIVE : le
   lecteur doit pouvoir revenir sur les pages libres. */
#liseuse.liseuse_gated .liseuse_stage { opacity: .72; }

/* Derrière le voile, la sélection porterait sur des mots invisibles. */
#liseuse.liseuse_gated .liseuse_text,
#liseuse.liseuse_gated .liseuse_text span {
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

/* --- .liseuse_native_fs : plein écran natif -----------------------------
   Posée sur fullscreenchange. Elle double les pseudo-classes :fullscreen et
   :-webkit-full-screen de la section 10, pour les navigateurs qui exposent
   l'API préfixée sans la pseudo-classe correspondante — la liseuse y resterait
   sinon bornée à son max-height de flux normal, au milieu d'un écran noir.
   Elle ne reprend SURTOUT pas le position:fixed / z-index 60000 du
   pseudo-plein-écran : en plein écran natif, l'élément est déjà dans la couche
   supérieure du navigateur. */
#liseuse.liseuse_native_fs {
  width: 100%;
  height: 100%;
  max-height: none;
  min-height: 0;
}

/* --- .liseuse_page_locked : page verrouillée ----------------------------
   Posée sur le conteneur d'une page au-delà de free_pages quand l'accès n'est
   pas accordé : l'image est alors la vignette agrandie et floutée
   (.liseuse_img_blur, section 2). Le flou seul se confond avec un défaut de
   chargement, d'où ce repère explicite ; il reste lisible sous le voile
   translucide de l'écran d'accroche.
   z-index 5 : au-dessus de l'image et du calque texte, très en dessous des
   barres (30) et de l'écran d'accroche (40). */
#liseuse .liseuse_page_locked { background: #dfe1e6; }

#liseuse .liseuse_page_locked::after {
  content: "Réservé aux abonnés";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  padding: 7px 8px;
  background: rgba(22, 24, 29, .86);
  color: var(--liseuse-fg);        /* 11,7:1 au pire cas, voile sur page blanche */
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-align: center;
  text-transform: uppercase;
}

/* =========================================================================
 * 15. Pleine fenêtre, raccourcis de bord, aperçu de piste, grille d'index
 *
 *   Ajoutés pour aligner la liseuse sur le comportement de référence
 *   (Calaméo) : la lecture occupe TOUT le viewport dès l'ouverture, la molette
 *   zoome, la piste montre la double page survolée, et une grille de toutes
 *   les doubles pages s'ouvre depuis la barre.
 * ====================================================================== */

/* --- Pleine fenêtre (défaut sur /liseuse/<slug>) ------------------------
   Même géométrie que le pseudo-plein-écran (section 10), mais posée dès le
   rendu PHP. L'en-tête et le pied de page du site restent dans le DOM, sous
   la liseuse ; html.liseuse_fullwindow_open coupe le défilement de la page
   hôte pour qu'on ne puisse pas les faire remonter. */
#liseuse.liseuse_fullwindow {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60000;
  width: 100vw;
  width: 100dvw;
  height: 100vh;
  height: 100dvh;
  max-height: none;
  min-height: 0;
  margin: 0;
}

html.liseuse_fullwindow_open,
html.liseuse_fullwindow_open body {
  overflow: hidden;
  height: 100%;
}

/* --- Bouton « quitter » et bouton « grille » ----------------------------- */
#liseuse .liseuse_btn_quit {
  margin-left: 6px;
  text-decoration: none;
  font-size: 22px;
  line-height: 1;
  /* C'est un <a>, pas un <button> : styles_<version>.css lui donnerait sinon
     la couleur de lien du site. */
  color: var(--liseuse-fg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#liseuse .liseuse_btn_quit:hover { background: #7a2d34; }

#liseuse .liseuse_btn_grid svg { display: block; }
#liseuse .liseuse_btn_grid[aria-pressed="true"] { background: var(--liseuse-accent); }

/* --- Flèches masquées en bord de numéro ---------------------------------
   hidden l'emporte sur display:block ; sans cette règle, l'attribut serait
   sans effet sur un <button> déjà stylé en display. */
#liseuse .liseuse_nav[hidden],
#liseuse .liseuse_nav_end[hidden] { display: none; }

/* --- Raccourcis « tout au début » / « tout à la fin » -------------------
   Plus petits que les flèches, alignés dessous : la barre verticale du
   glyphe dit « butée ». Mêmes couleurs et même retrait au zoom. */
#liseuse .liseuse_nav_end {
  position: absolute;
  top: calc(var(--liseuse-bar-h) + (100% - var(--liseuse-bar-h) - var(--liseuse-strip-h)) / 2 + 52px);
  z-index: 20;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: var(--liseuse-radius);
  background: rgba(22, 24, 29, .74);
  color: var(--liseuse-fg);
  cursor: pointer;
  opacity: .55;
  transition: opacity 120ms linear, background-color 120ms linear;
}
#liseuse .liseuse_nav_end::before {
  display: block;
  font-size: 15px;
  line-height: 34px;
  text-align: center;
  font-weight: 700;
}
#liseuse .liseuse_nav_first::before { content: "\2502\25C2"; }
#liseuse .liseuse_nav_last::before  { content: "\25B8\2502"; }
#liseuse .liseuse_nav_first { left: 14px; }
#liseuse .liseuse_nav_last  { right: 14px; }
#liseuse .liseuse_nav_end:hover { opacity: 1; background: rgba(22, 24, 29, .92); }
#liseuse .liseuse_nav_end:focus { outline: none; }
#liseuse .liseuse_nav_end:focus-visible {
  opacity: 1;
  outline: 2px solid var(--liseuse-focus);
  outline-offset: 2px;
}
#liseuse.liseuse_zoomed .liseuse_nav_end,
#liseuse.liseuse_single .liseuse_nav_end { display: none; }

/* --- Bulle de la piste : la double page survolée ------------------------
   Deux vignettes 240 px côte à côte (une seule en bord de numéro), au lieu
   d'une vignette 100 px : c'est l'aperçu de référence. Pendant le chargement
   la bulle garde sa hauteur et montre un voyant, pour que le survol rapide de
   la piste ne fasse pas clignoter des cadres vides. */
#liseuse .liseuse_strip_peek { min-width: 96px; }

#liseuse .liseuse_strip_peek_pages {
  position: relative;
  display: flex;
  gap: 2px;
  justify-content: center;
  min-height: 120px;
}

#liseuse .liseuse_strip_peek_img {
  height: 120px;
  width: auto;
  background: #ffffff;
  transition: opacity 120ms linear;
}
#liseuse .liseuse_strip_peek_img[hidden] { display: none; }

#liseuse .liseuse_strip_peek_loading .liseuse_strip_peek_img { opacity: 0; }

#liseuse .liseuse_strip_peek_spin {
  display: none;
  position: absolute;
  top: calc(50% - 10px);
  left: calc(50% - 10px);
  width: 20px;
  height: 20px;
  border: 2px solid rgba(255, 255, 255, .25);
  border-top-color: var(--liseuse-fg);
  border-radius: 50%;
  animation: liseuse_spin .8s linear infinite;
}
#liseuse .liseuse_strip_peek_loading .liseuse_strip_peek_spin { display: block; }

@keyframes liseuse_spin { to { transform: rotate(360deg); } }

/* --- Grille d'index ------------------------------------------------------
   Recouvre le viewport entre la barre haute et la barre à vignettes, qui
   restent visibles et actives. Une carte par double page ; la première et la
   dernière page (si le total est pair) sont seules. */
#liseuse .liseuse_index {
  position: absolute;
  top: var(--liseuse-bar-h);
  left: 0;
  right: 0;
  bottom: var(--liseuse-strip-h);
  z-index: 38;
  background: rgba(22, 24, 29, .96);
}
#liseuse .liseuse_index[hidden] { display: none; }

#liseuse .liseuse_index_close {
  position: absolute;
  top: 10px;
  right: 14px;
  z-index: 2;
  font-size: 22px;
}

#liseuse .liseuse_index_scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 28px 40px 32px;
}

#liseuse .liseuse_index_grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 22px 18px;
  align-items: end;
}

#liseuse .liseuse_index_item {
  display: block;
  width: 100%;
  padding: 6px;
  border: 3px solid transparent;
  border-radius: 10px;
  background: none;
  color: var(--liseuse-fg-soft);
  font-family: inherit;
  cursor: pointer;
  text-align: center;
  transition: border-color 100ms linear, background-color 100ms linear;
}
#liseuse .liseuse_index_item:hover,
#liseuse .liseuse_index_item:focus-visible {
  border-color: var(--liseuse-accent);
  background: rgba(73, 97, 167, .12);
  outline: none;
  color: var(--liseuse-fg);
}
/* Double page actuellement ouverte : repère persistant, distinct du survol. */
#liseuse .liseuse_index_item_current { border-color: #35c27a; }

#liseuse .liseuse_index_pages {
  display: flex;
  justify-content: center;
  gap: 2px;
  min-height: 60px;
}
#liseuse .liseuse_index_img {
  display: block;
  height: auto;
  max-height: 170px;
  width: auto;
  max-width: 50%;
  background: #ffffff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .5);
}

#liseuse .liseuse_index_num {
  display: flex;
  justify-content: center;
  gap: 40px;
  margin-top: 8px;
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Pagination de la grille : mobile seulement, voir la requête média. */
#liseuse .liseuse_index_pager {
  display: none;
  position: absolute;
  top: 50%;
  z-index: 3;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: #16181d;
  cursor: pointer;
}
#liseuse .liseuse_index_pager::before { display: block; font-size: 26px; line-height: 44px; text-align: center; }
#liseuse .liseuse_index_pager_prev::before { content: "\2039"; }
#liseuse .liseuse_index_pager_next::before { content: "\203A"; }
#liseuse .liseuse_index_pager_prev { left: 8px; }
#liseuse .liseuse_index_pager_next { right: 8px; }
#liseuse .liseuse_index_pager[hidden] { display: none; }

/* Grille ouverte : la scène et les flèches ne doivent plus recevoir de geste. */
#liseuse.liseuse_index_open .liseuse_nav,
#liseuse.liseuse_index_open .liseuse_nav_end { display: none; }
#liseuse.liseuse_index_open .liseuse_viewport { pointer-events: none; }

@media (max-width: 699px) {
  /* Colonne unique paginée (4 doubles pages par écran) avec chevrons de part
     et d'autre, à la Calaméo mobile. */
  #liseuse .liseuse_index_scroll { padding: 20px 56px 24px; overflow: hidden; }
  #liseuse .liseuse_index_grid {
    grid-template-columns: 1fr;
    gap: 14px;
    justify-items: center;
  }
  #liseuse .liseuse_index_item { max-width: 240px; }
  #liseuse .liseuse_index_img { max-height: 130px; }
  #liseuse .liseuse_index_pager { display: block; }
  #liseuse .liseuse_index_item[data-hidden-page="1"] { display: none; }
}
