/* ═══════════════════════════════════════════════════════════════════════
   SCROLER — Bandeau d'offre de rentrée
   ───────────────────────────────────────────────────────────────────────
   Un ruban sombre posé tout en haut des sept pages, juste avant l'en-tête.
   Même matière que le reste de la pièce : un socle nuit, un faisceau
   ambré qui le balaie lentement, un liseré orange en pied de bandeau.

   Trois précautions structurent ce fichier :

   1. LA HAUTEUR DU DOCUMENT D'ACCUEIL NE DOIT PAS BOUGER. index.html ne
      contient que le hero et fait EXACTEMENT la hauteur de l'écran.
      hero.js s'en sert : `pageDefilable()` renvoie false, le verrou de
      molette n'est jamais relâché, et le carrousel tourne sans fin. Un
      bandeau posé dans le flux ajouterait sa hauteur au document et
      tuerait le carrousel après un tour.
      Deuxième garde-fou, moins visible : `heroCoversViewport()` exige que
      le haut du hero soit à moins de 2 px du haut de l'écran. Un bandeau
      en flux le repousserait de sa propre hauteur et la molette ne serait
      plus jamais captée — même défaut, autre porte.
      D'où la solution retenue : sur l'accueil UNIQUEMENT, le hero est
      remonté de la hauteur du bandeau et se réserve la même hauteur en
      BORDURE HAUTE TRANSPARENTE. Sa boîte de bordure garde donc 100svh
      et son bord haut reste à 0 — les deux gardes passent — tandis que
      sa boîte de rembourrage, qui sert de référence à tous ses enfants
      absolus, perd la bande du ruban : le titre, l'orbe et la scène se
      recentrent seuls dans la place restante. Voir le détail au § 9.
      La hauteur réelle est mesurée par promo.js et déposée dans
      `--scr-promo-h` sur :root. Sans JavaScript elle vaut 0 : le bandeau
      reprend sa place dans le flux, et comme hero.js n'est pas là non
      plus, il n'y a plus de carrousel à préserver.

   2. L'EN-TÊTE COLLANT DES SIX AUTRES PAGES. `.scr-head` est en
      `position: sticky; top: 0`. Le bandeau le précède dans le flux :
      il défile, disparaît, et l'en-tête vient se coller au bord haut.
      Rien n'est posé ici en `fixed` ni en `sticky` qui pourrait le
      chevaucher.

   3. AUCUN !important DE MISE EN FORME. Comme partout ailleurs : tout est
      préfixé `scr-promo` ou porté par une variable.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══ 1. Jetons du bandeau ═════════════════════════════════════════════ */
:root {
  /* Hauteur mesurée du bandeau, posée par promo.js. Repli 0 : sans JS,
     le bandeau reste dans le flux et ne déduit rien du hero.           */
  --scr-promo-h: 0px;

  /* Socle du ruban. Plus profond que --scr-night (#14100D) : le bandeau
     doit se détacher du fond des pages intérieures, et rester opaque
     au-dessus du papier clair de l'accueil.                            */
  --scr-promo-fond: #0E0A08;
}

/* ═══ 2. Le ruban ══════════════════════════════════════════════════════
   Le voisin immédiat du ruban n'est pas le fond de la page mais
   l'en-tête collant, presque aussi sombre que lui : deux aplats de nuit
   à 1,09:1 l'un de l'autre ne font pas une couture, et le ruban se lit
   alors comme une barre d'outils plutôt que comme une offre. Ce sont
   donc le liseré et la braise qui la font — un filet orange franc en
   pied, prolongé de quelques pixels vers le haut par une lueur
   rasante. Le ruban devient une surface éclairée par en bas.         */
.scr-promo {
  position: relative;
  z-index: 1;                       /* passe devant le hero remonté */
  overflow: hidden;                 /* borne le faisceau */
  background: var(--scr-promo-fond);
  /* Le liseré orange, en pied : il fait la couture avec l'en-tête.
     Plein, et non transparent : à .72 d'opacité il ne pesait que
     2,87:1 sur l'en-tête, sous le 3:1 attendu d'un séparateur. En
     --scr-orange-d il tient 3,70:1 sur le socle du ruban et 3,38:1
     sur l'en-tête, et il prend au passage la teinte exacte du bouton
     de l'offre — la couture et l'action sont du même orange.       */
  border-bottom: 1px solid var(--scr-orange-d);
  box-shadow:
    inset 0 1px 0 rgba(242,239,234,.07),          /* cheveu clair en tête */
    inset 0 -16px 20px -18px rgba(233,78,26,.75); /* braise rasante en pied */
  color: var(--scr-on-night);
}

/* Faisceau ambré : il traverse le ruban de gauche à droite, puis revient.
   Deux règles le tiennent :

   • L'ellipse est centrée DANS la boîte (`at 50% 50%`) et non sur son
     bord gauche. Son alpha retombe à zéro à 24,5 % de part et d'autre du
     centre, donc la lueur ne touche jamais les bords de son propre
     élément : aucune arête ne peut apparaître, ni au bord du dégradé, ni
     sous le `overflow: hidden` du ruban. Une ellipse posée `at 0% 50%`
     serait coupée en deux par ce bord et se lirait comme une paroi
     verticale traversant le bandeau — pas comme un faisceau.
   • L'allure est LINÉAIRE. Les courbes du site (--scr-ease est un
     ease-out quasi exponentiel) sont faites pour des gestes qui
     arrivent quelque part ; appliquées ici, elles font filer le faisceau
     en cinq secondes puis le garent hors cadre les deux tiers du temps.
     Un balayage n'arrive nulle part, il passe : vitesse constante, 22 s
     dans chaque sens, environ 100 px par seconde.

   Aucune couleur de texte ne descend sous son seuil — les ratios notés
   à chaque déclaration sont mesurés au pic du faisceau.              */
.scr-promo__lueur {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 34% 150% at 50% 50%,
    rgba(233,78,26,.085) 0%, rgba(233,78,26,.045) 42%, rgba(233,78,26,0) 72%);
  animation: scrPromoBalai 22s linear infinite alternate;
}
/* ±78 % : le faisceau occupe 25,5 % → 74,5 % de la largeur du ruban et
   sort donc entièrement du cadre à chaque extrémité — il ne se retourne
   jamais à vue. Son cœur reste dans le cadre 82 % du cycle, sa traîne
   un peu plus : relevé sur des captures à chaud, le pic du faisceau
   passe par x = 5, 319, 755 puis 1219 en 1440 de large, à raison d'une
   centaine de pixels par seconde.                                    */
@keyframes scrPromoBalai {
  from { transform: translateX(-78%); }
  to   { transform: translateX(78%); }
}

/* ═══ 3. Rangée ════════════════════════════════════════════════════════
   Pleine largeur avec la gouttière du site, comme `.scr-head` — et non
   bridée à --scr-max : un ruban se coupe au bord de l'écran.          */
.scr-promo__in {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px clamp(14px, 1.8vw, 26px);
  padding-block: 11px;
  padding-inline: var(--scr-gutter);
}

/* L'échéance, accrochée à l'étiquette : une annonce de réduction sans
   date de fin est une annonce fragile. Elle reste en mono, un cran plus
   discrète que l'étiquette — c'est une précision, pas un argument.
   `white-space: nowrap` : « jusqu'au 30 » puis « septembre » sur deux
   lignes se lirait comme une date tronquée.                          */
.scr-promo__jusqua {
  white-space: nowrap;
  color: rgba(242,239,234,.72);          /* 8,6:1 sur le socle du bandeau */
  letter-spacing: .12em;
}
/* Le barré de l'hébergement suit celui du prix : même famille, même
   discrétion — il compare, il ne crie pas. */
.scr-promo__quoi s {
  color: rgba(242,239,234,.62);          /* 6,6:1, comme <s>900 € HT</s> */
  text-decoration-thickness: 1px;
}

/* ═══ 4. Étiquette — ce qu'on lit en premier ═══════════════════════════
   Même dessin que `.scr-eyebrow` : le tiret, la mono, l'orange.
   Ratios au § 13, faisceau arrêté à son pic.                          */
.scr-promo__label {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font-family: var(--scr-mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--scr-orange);
  white-space: nowrap;
}
.scr-promo__label::before {
  content: "";
  width: 22px;
  height: 1px;
  background: currentColor;
  opacity: .55;
}

/* ═══ 5. Ce que contient l'offre ═══════════════════════════════════════
   Le texte courant en rgba(242,239,234,.86), les mots qui portent
   l'offre en papier plein. Ratios au § 13.                            */
.scr-promo__quoi {
  flex: 1 1 340px;
  min-width: 0;
  margin: 0;
  font-size: 15.5px;
  font-weight: 300;
  line-height: 1.45;
  color: var(--scr-on-night-soft);
}
.scr-promo__quoi b { font-weight: 400; color: var(--scr-paper); }

/* ═══ 6. Le prix ═══════════════════════════════════════════════════════
   Le montant retenu en papier plein plutôt qu'en orange : à cette taille
   l'orange de marque suffirait pour la norme, mais pas pour un chiffre
   qui doit frapper.
   Le prix d'avant est un vrai <s> — le barré existe donc pour un lecteur
   d'écran, doublé d'un « au lieu de » en .scr-sr pour lever toute
   ambiguïté sur les restitutions qui n'annoncent pas la rature.       */
.scr-promo__prix {
  flex: 0 0 auto;
  margin: 0 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--scr-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.scr-promo__prix b {
  font-weight: 500;
  font-size: 19px;
  letter-spacing: .01em;
  color: var(--scr-paper);
}
.scr-promo__prix s {
  font-weight: 400;
  font-size: 13px;
  letter-spacing: .04em;
  color: rgba(242,239,234,.62);
  text-decoration-thickness: 1px;
  text-underline-offset: 0;
}

/* ═══ 7. L'action ══════════════════════════════════════════════════════
   Ce bouton tombe 25 px au-dessus de `.scr-head__cta`, dans le même coin
   haut-droit, et sur quatre pages il mène au même endroit. Lui donner le
   même dessin — filet orange, fond vide, même mono, même rayon — donnait
   deux pilules jumelles empilées : l'œil n'y lisait pas « une offre,
   puis la navigation » mais un bouton dupliqué, et l'action du ruban
   perdait toute distinction à l'instant précis où elle doit frapper.
   Le ruban prend donc le bouton PLEIN. Ce n'est pas un dessin nouveau :
   c'est exactement l'état survolé de `.scr-head__cta` — fond
   --scr-orange-d, texte blanc — posé à demeure. Une braise déjà allumée
   à côté d'une braise éteinte, dans le même vocabulaire.
   Au survol, le ruban monte d'un cran vers l'orange de marque et son
   texte passe à la nuit, là où l'en-tête ne fait que rejoindre l'état
   que le ruban tient en permanence. Ratios au § 13.                  */
.scr-promo__cta {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 22px;
  border: 1.5px solid var(--scr-orange-d);
  border-radius: 999px;
  background: var(--scr-orange-d);
  color: #fff;
  font-family: var(--scr-mono);
  font-weight: 500;
  font-size: 11.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .28s ease, border-color .28s ease, color .28s ease;
}
.scr-promo__cta:hover {
  background: var(--scr-orange);
  border-color: var(--scr-orange);
  color: var(--scr-night);
}

/* ═══ 8. La fermeture ══════════════════════════════════════════════════
   Un vrai <button>, porteur d'un aria-label explicite, cible de 44×44.
   Il arrive `hidden` dans le HTML et c'est promo.js qui le découvre :
   sans JavaScript, rien ne serait mémorisé et le bouton mentirait.    */
.scr-promo__fermer {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: rgba(242,239,234,.72);
  font-family: var(--scr-mono);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  transition: background-color .25s ease, color .25s ease;
}
/* `hidden` doit rester opérant : l'attribut l'emporte sur le display
   ci-dessus grâce au sélecteur d'attribut, plus spécifique.           */
.scr-promo__fermer[hidden] { display: none; }
.scr-promo__fermer:hover {
  background: rgba(242,239,234,.09);
  color: var(--scr-paper);
}

/* ═══ 9. Accueil — le ruban se pose SUR le hero ════════════════════════
   `#scroler-hero` n'existe que sur index.html : la règle ne touche
   qu'elle. Le hero remonte de la hauteur exacte du bandeau, donc le
   document conserve 100svh et le bord haut du hero reste à 0.
   Ce fichier est chargé APRÈS hero.css : à spécificité égale (1,0,0),
   c'est bien cette hauteur-ci qui s'applique.                         */
#scroler-hero {
  /* La bande réservée au ruban est une BORDURE transparente, et non une
     marge ni un rembourrage. C'est le seul des trois qui fasse les deux
     choses à la fois :
       • la boîte de bordure garde 100svh et, remontée de la même
         hauteur, son bord haut reste à 0 — c'est ce que mesurent
         `getBoundingClientRect()` et donc `heroCoversViewport()` ;
       • la boîte de rembourrage, elle, perd cette hauteur — et c'est
         ELLE qui sert de référence à tous les enfants en
         `position: absolute` du hero. Le titre, l'orbe, la scène et les
         repères se recentrent donc seuls dans la place restante, sans
         qu'aucun de leurs pourcentages n'ait à être retouché.
     Un `padding-top` n'aurait rien décalé : les enfants absolus se
     calent sur la boîte de rembourrage, bordure comprise mais
     rembourrage exclu. Une marge, elle, aurait déplacé la boîte de
     bordure et fait échouer `heroCoversViewport()`.
     `box-sizing: border-box` est posé globalement par base.css : la
     bordure est bien prise DANS les 100svh.
     Cette hauteur change à chaud le jour où le visiteur ferme le ruban :
     la scène 3D grandit d'autant, sans qu'aucun événement ne prévienne
     hero.js. C'est promo.js qui s'en charge — voir le commentaire
     « Prévenir la page » de ce fichier.                              */
  border-top: var(--scr-promo-h) solid transparent;
  margin-top: calc(-1 * var(--scr-promo-h));
}

/* ═══ 10. Mobile ═══════════════════════════════════════════════════════
   Trois rangées : l'étiquette, puis l'offre, puis le prix et l'action
   côte à côte — le bouton reste au bas du ruban, donc dans le rayon du
   pouce, et garde ses 44 px de cible.

   Le ruban est ici compté au pixel près, et non par confort de dessin :
   sur l'accueil, en 390 × 844, le hero ne laisse que neuf pixels entre
   ses commandes discrètes et son titre. Chaque rangée ajoutée au ruban
   se paie là-bas. D'où la croix sortie du flux, le rembourrage rogné et
   l'interligne resserré ; le § 11 rend au hero le reste.              */
@media (max-width: 860px) {
  .scr-promo__in {
    gap: 6px 14px;
    padding-block: 10px;
  }
  /* La croix quitte le flux : en rangée, ses 44 px imposaient leur
     hauteur à la ligne de l'étiquette et coûtaient 26 px de ruban. Elle
     garde sa cible pleine ; l'étiquette et l'offre lui réservent sa
     place.
     Les 7 px du haut et les 8 px minimum de droite ne sont pas un
     réglage d'œil : l'anneau de focus du site fait 3 px, décalé de 3 px,
     soit 6 px hors de la boîte du bouton. Collée plus près du bord, la
     croix se voyait rogner son anneau par le `overflow: hidden` du § 2 —
     le seul endroit du ruban où le dessin n'était pas fini.          */
  .scr-promo__fermer {
    position: absolute;
    top: 7px;
    right: max(8px, calc(var(--scr-gutter) - 12px));
    z-index: 2;
  }
  /* Le même rembourrage de fin de ligne sur les DEUX lignes que la croix
     survole. Sans lui sur `__quoi`, le pouce posé sur le dernier mot de
     sa première ligne ne touchait pas le texte : il fermait le bandeau.
     Rien ne le laissait voir — le glyphe × est loin au-dessus — et le
     piège escamotait justement l'offre qu'il faut montrer.           */
  .scr-promo__label  { flex: 1 0 100%; padding-inline-end: 48px; }
  .scr-promo__quoi   { flex: 1 0 100%; padding-inline-end: 48px; font-size: 14.5px; line-height: 1.4; }
  .scr-promo__prix   { margin: 0 auto 0 0; gap: 9px; }
  .scr-promo__prix b { font-size: 17px; }
  .scr-promo__cta    { padding: 11px 16px; letter-spacing: .08em; }
}

@media (max-width: 340px) {
  .scr-promo__prix s { font-size: 12px; }
  .scr-promo__cta { padding: 11px 13px; font-size: 11px; }
}

/* ═══ 11. Accueil étroit — rendre au hero ce que le ruban lui prend ════
   Sous 640 px, hero.css ancre le bloc haut à 21 % de la hauteur
   disponible. Deux éléments ne descendent donc PAS du même nombre de
   pixels quand le ruban rétrécit cette hauteur :
     • `.scr__util` (son, rejouer) est ancré à 20 px du haut : il descend
       de TOUTE la hauteur du ruban ;
     • `.scr__head` est centré en pourcentage : il ne descend que de
       79 % de cette même hauteur.
   L'écart entre les deux se referme donc de 21 % du ruban — et il ne
   valait déjà que 9 px sur un écran de 844. Sans compensation,
   « rejouer l'intro » s'imprime en travers de « Bienvenue sur Scroler… ».
   On rend cet écart au bloc haut. Le facteur .23 est le plus grand des
   trois taux d'ancrage du hero (23 % en large, 21 % en étroit, 19 % en
   écran court) : il couvre le pire cas à trois pixels près, et le bloc
   garde sa marge avant le début du dégradé du sol. La compensation étant
   proportionnelle à `--scr-promo-h`, elle suit le ruban si celui-ci
   gagne une ligne.
   Le décalage est le même dans les deux états : il ne peut pas sauter
   pendant l'animation qui fait remonter le bloc.                      */
@media (max-width: 640px) {
  #scroler-hero .scr__head {
    transform: translate(-50%, calc(-50% + var(--scr-promo-h) * .23));
  }
}


/* ═══ 12. Préférences système ══════════════════════════════════════════ */

/* Le faisceau cesse de balayer ; la lueur reste, posée au milieu du
   ruban, où ses deux bords s'éteignent d'eux-mêmes. Le dessin du bandeau
   est intact, seul le mouvement disparaît.                            */
@media (prefers-reduced-motion: reduce) {
  .scr-promo__lueur { animation: none; transform: none; }
}

/* En couleurs forcées, les fonds et les filets d'auteur sont ignorés :
   on redonne au ruban un bord et un bouton visibles, et on retire la
   lueur, qui ne serait plus qu'un aplat.                              */
@media (forced-colors: active) {
  /* Une bordure transparente peut se voir imposer une couleur : le hero
     porterait alors un bandeau plein de 67 px. On rend le ruban au flux
     normal, quitte à ce que l'accueil défile un peu.                 */
  #scroler-hero { border-top: 0; margin-top: 0; }
  .scr-promo { border-bottom: 1px solid CanvasText; }
  .scr-promo__lueur { display: none; }
  /* Le fond plein du bouton est ignoré dans ce mode comme tous les
     autres : son filet redevient le seul dessin qui le distingue.    */
  .scr-promo__cta { border: 1.5px solid LinkText; }
  .scr-promo__fermer { border: 1px solid ButtonText; }
  .scr-promo__prix s { text-decoration-line: line-through; }
}

/* ═══ 13. Contrastes mesurés ═══════════════════════════════════════════
   Relevés sur les pixels RENDUS, et non calculés sur les couleurs
   déclarées. Le fond retenu est le plus clair qu'on ait pu relever sur
   les lignes sans texte du ruban, faisceau au pic et grain compris :
   (34,16,10). Sur le socle nu (14,10,8), les mêmes textes gagnent
   entre trois et quatre dixièmes de point.

     Étiquette #E94E1A .................................... 4,86:1
     Offre rgba(242,239,234,.86) ......................... 11,96:1
     Mots en <b> et prix retenu #F2EFEA .................. 15,97:1
     Prix barré rgba(242,239,234,.62) ..................... 6,64:1
     Croix rgba(242,239,234,.72) ......................... 8,65:1
     Bouton #fff sur --scr-orange-d ....................... 5,32:1
     Bouton survolé --scr-night sur --scr-orange .......... 5,02:1
     Liseré --scr-orange-d sur le socle du ruban .......... 3,70:1
     Liseré --scr-orange-d sur l'en-tête collant .......... 3,38:1

   Les quatre premières valeurs concernent du texte : la plus basse,
   l'étiquette, est en mono de 11 px et tient le 4,5:1 exigé. Les mots
   courants et les chiffres, eux, sont très au-dessus du 7:1 visé par le
   site. Les deux dernières lignes ne sont pas du texte : ce sont des
   séparateurs, pour lesquels le seuil applicable est 3:1.            */

/* ═══ 14. Impression ═══════════════════════════════════════════════════
   Le bandeau porte déjà `.scr-no-print`, que base.css masque. La règle
   qui compte ici est la seconde : sans elle, le hero d'accueil resterait
   remonté d'une hauteur de bandeau qui n'est plus imprimée.           */
@media print {
  .scr-promo { display: none; }
  #scroler-hero { border-top: 0; margin-top: 0; }
}
