/**
 * Réservation de séjours — la feuille du parcours visiteur.
 *
 * Modale large sur ordinateur, plein écran sur téléphone.
 *
 * ⚠ La charte est celle de l'ÉTABLISSEMENT, pas la nôtre : ce formulaire est
 * la seule partie du module que son client voit, et elle doit se fondre dans
 * le site.
 *
 * **Elle n'est PAS substituée à l'installation — elle est HÉRITÉE.** C'est ce
 * que fait déjà le widget des tables, et c'est plus solide de deux façons :
 *
 *   • un site qui change de couleurs n'a rien à réinstaller — la feuille suit ;
 *   • une variable du site écrite en `var(--autre-chose)` ou en `color-mix()`
 *     ne peut pas être relevée par un script, qui retombe alors sur un défaut.
 *     C'est arrivé ici même : Aux Étangs définit `--ink: #ffffff` — le texte
 *     POSÉ SUR l'accent, et non l'accent — et le moteur s'est retrouvé noir au
 *     milieu d'un site rouge et crème.
 *
 * Le second terme de chaque `var()` est le repli : il sert sur un site qui
 * n'est pas des nôtres — WordPress, un hébergeur classique — où aucune de ces
 * variables n'existe. Le moteur y est neutre, et lisible.
 *
 * Les variables du site, telles que nos feuilles les définissent :
 *   --beige       le fond des boutons          --ink    le texte posé dessus
 *   --beige-deep  ce fond au survol            --body   la police de labeur
 *   --cream       un fond clair de page        --fast   la durée des transitions
 *
 * Tout est préfixé `sw-` et rien n'est déclaré sur un sélecteur d'élément :
 * le widget s'installe aussi sur des sites que nous n'avons pas faits, et il
 * n'a pas le droit d'y déplacer un paragraphe.
 */

:root {
  /* ══════════════════════════════════════════════════════════
     LA PALETTE, HÉRITÉE DU SITE — et la même logique que le
     widget des tables, sur le même site.

     Nos feuilles définissent six variables, et elles ont un
     RÔLE, pas une couleur :

       --ink-2   le fond du panneau        (ardoise)
       --cream   le texte sur ce fond
       --ink-3   les filets et bordures
       --beige   le fond des boutons       (l'accent — rouge ici)
       --ink     le texte POSÉ SUR --beige
       --beige-deep  ce même fond, au survol

     Le moteur des chambres était sur fond clair : deux modules
     du même site, deux apparences, et le client passait de
     l'un à l'autre sans comprendre qu'ils venaient d'ici.
     Un seul panneau, une seule logique.

     Le second terme de chaque `var()` est le repli : il sert
     sur un site qui n'est pas des nôtres, où aucune de ces
     variables n'existe.
     ══════════════════════════════════════════════════════════ */

  --sw-fond: var(--ink-2, #1f242b);
  --sw-texte: var(--cream, #e9edf2);
  --sw-encre: var(--cream, #ffffff);
  --sw-ligne: var(--ink-3, #333a44);
  --sw-primaire: var(--beige, #9d2b3c);
  --sw-primaire-clair: var(--beige-deep, #82212f);
  --sw-sur-primaire: var(--ink, #ffffff);
  --sw-police: var(--body, inherit);
  --sw-transition: var(--fast, 180ms cubic-bezier(.16, 1, .3, 1));

  /* Les surfaces posées SUR le panneau — cartes, champs, blocs. Un blanc très
     dilué plutôt qu'une couleur fixe : il s'accorde à n'importe quelle ardoise,
     du gris bleuté au brun profond, sans qu'on ait à la connaître. */
  --sw-carte: rgba(255, 255, 255, .045);
  --sw-carte-haut: rgba(255, 255, 255, .075);
  --sw-doux: color-mix(in srgb, var(--cream, #e9edf2) 62%, transparent);

  /**
   * L'accent, et ce à quoi il NE sert PAS.
   *
   * Mesuré sur cet écran : la couleur de marque éclaircie donne
   * rgb(184, 102, 115) sur une ardoise rgb(31, 38, 45), soit un contraste de
   * 3,7:1 — sous le seuil de 4,5:1 exigé pour du texte. Et l'éclaircir
   * davantage ne sauve rien : un rouge éclairci devient rose, jamais lisible.
   *
   * L'accent reste donc pour ce qui se REMARQUE sans se lire — une puce, un
   * filet, un montant économisé. Les liens, eux, passent en texte clair
   * souligné : sur fond sombre, c'est le soulignement qui dit « lien », pas la
   * couleur.
   */
  --sw-accent: color-mix(in srgb, var(--beige, #9d2b3c) 55%, white);

  --sw-souci: #ff9b91;
  --sw-ok: #7fd6a2;
  --sw-radius: 6px;
  --sw-ombre: 0 28px 70px rgba(0, 0, 0, .55);
}

/* `color-mix` manque à quelques navigateurs anciens : sans ce repli, la
   couleur devient « invalide » et le texte hérite du noir du site — illisible
   sur ardoise. Une règle de secours, écrite avant, ne coûte rien. */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
  :root {
    --sw-doux: rgba(233, 237, 242, .62);
    --sw-accent: #d98b95;
  }
  .sw-cal-jour.is-plage { background: rgba(157, 43, 60, .3); }
}

/* Le fond de page ne défile plus tant que la modale est ouverte : sans cela,
   la molette traverse et l'on repose le regard sur un site qui a bougé. */
html.sw-ouvert, body.sw-ouvert { overflow: hidden; }

.sw-root {
  position: fixed; inset: 0; z-index: 2147483000;
  font-family: var(--sw-police);
  /* La TAILLE de référence est posée ici, en pixels.
     Sans elle, le `font: inherit` du reset ci-dessous remonte jusqu'au body du
     site : Aux Étangs compose à 1,08 rem avec une interligne large, et la
     description d'une chambre y sortait en corps de texte d'article — six
     lignes là où il en fallait trois. Un widget qui s'installe partout fixe sa
     propre échelle, il ne l'emprunte pas. */
  font-size: 15px;
  color: var(--sw-texte);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
.sw-root[hidden] { display: none; }

/* Le voile. Il avait disparu d'une passe de remplacement, et la modale
   flottait alors au-dessus de la page sans rien pour l'en détacher : on lisait
   le site au travers, et le moteur n'avait plus de contour. */
.sw-backdrop {
  position: absolute; inset: 0;
  background: rgba(8, 9, 11, .68);
  backdrop-filter: blur(4px);
  animation: sw-fondu var(--sw-transition);
}
@keyframes sw-fondu { from { opacity: 0 } to { opacity: 1 } }
.sw-root *, .sw-root *::before, .sw-root *::after { box-sizing: border-box; }

/* ── Se protéger du site qui l'accueille ──────────────────────
   Le widget vit DANS la page : tout ce que le site déclare sur `h2`, `p`,
   `button` ou `ul` s'y applique. Aux Étangs met ses titres en serif à 2,6 rem —
   le message « aucune chambre disponible » y est sorti en titre de une.

   ⚠ Tout est enveloppé dans `:where()`, et ce n'est pas un raffinement :
   `:where()` a une spécificité NULLE. Écrit en clair, `.sw-root button` pèse
   (0,1,1) et l'emporte sur `.sw-primaire` (0,1,0) — le reset effaçait donc le
   fond, la bordure et l'alignement de TOUS les boutons du widget, et le moteur
   s'affichait en texte nu. C'est exactement ce qui est arrivé, et c'était
   invisible à la relecture : chaque règle était juste, c'est leur ordre de
   priorité qui ne l'était pas.

   Avec `:where()`, le reset ne pèse rien : il pose un plancher que la moindre
   classe recouvre, et il ne peut plus rien écraser. */
:where(.sw-root) :where(h1, h2, h3, h4, p, ul, ol, li, figure, details, summary, form, fieldset) {
  margin: 0; padding: 0; border: 0; font: inherit; color: inherit;
  letter-spacing: normal; text-transform: none; line-height: inherit;
}
:where(.sw-root) :where(ul, ol) { list-style: none; }
:where(.sw-root) :where(button, input, textarea, select, label) {
  font: inherit; color: inherit; letter-spacing: normal; text-transform: none;
}
:where(.sw-root) :where(button) {
  margin: 0; border: 0; padding: 0; background: none;
  text-align: inherit; border-radius: 0; box-shadow: none;
}
:where(.sw-root) :where(a) { text-decoration: none; color: inherit; background: none; }
:where(.sw-root) :where(img, svg, video) { display: block; max-width: 100%; }
:where(.sw-root) :where(table) { border-collapse: collapse; }
/* Les pseudo-éléments décoratifs que certains thèmes accrochent aux liens et
   aux boutons — une flèche, un soulignement animé — n'ont rien à faire ici. */
:where(.sw-root) :where(a, button)::before,
:where(.sw-root) :where(a, button)::after { content: none; }

/* La police, elle, se REPREND avec une spécificité normale.
 *
 * C'est le revers du `:where()` : il ne peut plus rien écraser, y compris ce
 * que le site déclare sur ses titres. Aux Étangs compose ses `h2` en serif, et
 * « Choisissez vos dates » y sortait en Marcellus au milieu d'un moteur en
 * Archivo. Une règle d'élément (0,1,1) bat celle du site (0,0,1), et elle ne
 * touche QUE la famille — les tailles restent aux composants. */
.sw-root h1, .sw-root h2, .sw-root h3, .sw-root h4,
.sw-root p, .sw-root li, .sw-root summary, .sw-root label,
.sw-root button, .sw-root input, .sw-root select, .sw-root textarea, .sw-root a {
  font-family: var(--sw-police);
  font-style: normal;
}

/* LES MESURES DU SITE NE TRAVERSENT PAS NON PLUS.
 *
 * Même raison, autres propriétés. Un site pose volontiers une largeur de
 * lecture sur ses balises nues — Aux Étangs écrit `h2 { max-width: 15em }` et
 * `p { max-width: 66ch }`, ce qui est juste pour une page d'article. Dans le
 * moteur, le titre du remerciement s'arrêtait donc à trois cents pixels et
 * cessait d'être centré : il était centré dans SA boîte, mais sa boîte ne
 * faisait plus la largeur de l'écran. On voyait un titre de travers sans
 * comprendre pourquoi, et rien dans la feuille du moteur ne l'expliquait.
 *
 * `:where()` à l'intérieur pour que les composants gardent la main : la règle
 * pèse 0,1,0 — assez pour battre `h2` (0,0,1), pas assez pour écraser une
 * classe du moteur déclarée plus bas. */
.sw-root :where(h1, h2, h3, h4, p, ul, ol, li, figure, blockquote) {
  max-width: none; min-width: 0;
  float: none; text-indent: 0;
  line-height: inherit; letter-spacing: normal;
}

/* ── La modale ───────────────────────────────────────────── */

.sw-modal {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(1160px, calc(100vw - 40px));
  /* La hauteur prend ce que l'écran donne, à une marge près. `dvh` suit la
     barre d'adresse mobile ; `vh` la laisse déborder sous l'écran. Le plafond
     n'existe que pour les très grands moniteurs, où une modale de deux mille
     pixels de haut oblige à lever les yeux pour lire son propre titre. */
  height: min(1020px, calc(100dvh - 32px));
  background: var(--sw-fond);
  border-radius: var(--sw-radius);
  box-shadow: var(--sw-ombre);
  display: flex; flex-direction: column;
  overflow: hidden;
  animation: sw-monte 240ms cubic-bezier(.16, 1, .3, 1);
}
@keyframes sw-monte {
  from { opacity: 0; transform: translate(-50%, calc(-50% + 14px)) }
  to { opacity: 1; transform: translate(-50%, -50%) }
}

/* Un message court — « pas encore ouvert », « chargement » — n'ouvre pas une
   modale de huit cents pixels de haut sur un fond vide. Elle prend la hauteur
   de ce qu'elle a à dire, et pas davantage. */
.sw-modal.est-court { height: auto; max-height: 90vh; }
.sw-modal.est-court .sw-steps { display: none; }

/* LE RÉTRÉCISSEMENT, ADOUCI.
 *
 * Deux écrans passent en `est-court` après coup : le hors service et le
 * remerciement. La modale y perd six cents pixels d'un coup, ce qui reste
 * moins brutal qu'un agrandissement — on ne lit rien à l'instant du saut —
 * mais sauter n'a aucune raison d'être.
 *
 * `interpolate-size` autorise l'interpolation depuis et vers `auto`, que le
 * CSS refusait historiquement. Là où le navigateur l'ignore, la transition ne
 * s'applique simplement pas : le comportement d'avant, jamais pire. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .sw-modal { transition: height 320ms cubic-bezier(.16, 1, .3, 1); }
  @media (prefers-reduced-motion: reduce) {
    .sw-modal { transition: none; }
  }
}

.sw-head {
  display: flex; align-items: flex-start; gap: .75rem;
  padding: .7rem 1rem;
  background: var(--sw-carte-haut);
  border-bottom: 1px solid var(--sw-ligne);
  flex: 0 0 auto;
}

.sw-retour, .sw-close {
  display: inline-flex; align-items: center; gap: .4rem; margin-top: -2px;
  border: 0; background: transparent; cursor: pointer;
  color: var(--sw-doux); font: inherit; font-size: .85rem;
  padding: .45rem .5rem; border-radius: 4px;
  transition: color var(--sw-transition), background var(--sw-transition);
}
.sw-retour:hover, .sw-close:hover { color: var(--sw-encre); background: var(--sw-carte-haut); }
.sw-retour[hidden] { display: none; }
.sw-retour svg, .sw-close svg {
  width: 18px; height: 18px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── Le fil des étapes ─────────────────────────────────────
   La pastille au-dessus, le nom en dessous.

   Les deux étaient côte à côte, et le trait qui relie deux étapes passait
   alors AU TRAVERS du libellé de la précédente — « Chambres » était barré par
   la ligne censée mener à « Tarifs ». Un trait horizontal ne peut relier deux
   points que s'il n'y a rien entre eux : le texte descend d'un cran, et le
   trait court librement à hauteur des pastilles. C'est la disposition des
   moteurs du marché, et c'est pour cette raison qu'ils l'ont tous adoptée. */

.sw-steps {
  display: flex; align-items: flex-start; flex: 1 1 auto;
  min-width: 0; gap: 0;
}
.sw-step {
  display: flex; flex-direction: column; align-items: center; gap: .2rem;
  flex: 1 1 0; min-width: 0;
  border: 0; background: transparent; font: inherit; font-size: .8rem;
  color: var(--sw-doux); padding: .1rem .2rem;
  cursor: default; position: relative;
}
.sw-step:not(:disabled) { cursor: pointer; }

/* Le trait part du centre de la pastille précédente et s'arrête au bord de
   celle-ci : d'où le `right: 50%` et la demi-largeur de pastille retranchée. */
.sw-step + .sw-step::before {
  content: ''; position: absolute;
  right: calc(50% + 16px); left: calc(-50% + 16px);
  top: 13px; height: 2px; background: var(--sw-ligne);
}
.sw-step.is-done::before, .sw-step.is-now::before { background: var(--sw-primaire); }

.sw-step-pastille {
  width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .78rem; font-weight: 600;
  background: var(--sw-carte-haut); color: var(--sw-doux);
  border: 1.5px solid var(--sw-ligne);
  flex: 0 0 auto; position: relative; z-index: 1;
  transition: background var(--sw-transition), color var(--sw-transition);
}
.sw-step-pastille svg {
  width: 14px; height: 14px; fill: none; stroke: currentColor;
  stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
}
.sw-step.is-now .sw-step-pastille,
.sw-step.is-done .sw-step-pastille {
  background: var(--sw-primaire); color: var(--sw-sur-primaire);
  border-color: var(--sw-primaire);
}
/* L'étape en cours porte un halo : sur un fil de cinq pastilles, la couleur
   seule ne suffit pas à dire où l'on en est — les franchies la portent aussi. */
.sw-step.is-now .sw-step-pastille {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--sw-primaire) 25%, transparent);
}
.sw-step.is-now .sw-step-nom { color: var(--sw-encre); font-weight: 600; }
/* Les étapes franchies sont cliquables : elles doivent se lire comme telles,
   et non comme du texte éteint. */
.sw-step.is-done .sw-step-nom { color: color-mix(in srgb, var(--sw-encre) 78%, transparent); }
.sw-step:not(:disabled):hover .sw-step-nom { color: var(--sw-encre); }
.sw-step-nom {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%; line-height: 1.35; padding-top: .1rem;
}

/* ── Le corps ────────────────────────────────────────────── */

.sw-body {
  flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.sw-body:focus { outline: none; }
.sw-etape { padding: clamp(1rem, 3vw, 2rem); max-width: 980px; margin: 0 auto; }

.sw-titre {
  margin: 0 0 1.3rem; font-size: 1.25rem;
  color: var(--sw-encre); font-weight: 600; line-height: 1.25;
  letter-spacing: -.01em;
}
.sw-sous-titre {
  margin: 1.8rem 0 .8rem; font-size: 1rem; color: var(--sw-encre); font-weight: 600;
}
.sw-doux { color: var(--sw-doux); font-size: .85rem; margin: 0; }

/* ── L'attente, et pourquoi c'est un squelette ─────────────
 *
 * La modale s'ouvrait en `est-court` — `height: auto` — avec le mot
 * « Recherche… » au milieu, puis reprenait sa taille pleine dès que la
 * configuration arrivait. Deux cents pixels de haut qui deviennent mille, d'un
 * coup, sous les yeux du visiteur : le calendrier semblait jaillir, et la
 * fenêtre changeait de forme avant même qu'on ait rien lu.
 *
 * On ouvre donc à la TAILLE DÉFINITIVE, et on remplit avec la forme de ce qui
 * arrive : deux champs de dates, deux grilles de mois, le compteur, le bouton.
 * Rien ne bouge quand le vrai contenu prend sa place — il se substitue au
 * fantôme, case pour case.
 *
 * Le chatoiement reste lent et discret : il dit « ça vient », il ne réclame
 * pas l'attention. Coupé pour qui a demandé moins d'animations — un balayage
 * continu est exactement ce que ce réglage existe pour éteindre. */

.sw-squelette {
  padding: 1.5rem 1.5rem 2rem;
  display: flex; flex-direction: column; gap: 1.3rem;
  /* La même largeur que l'étape 1, pour que rien ne se décale au remplacement. */
  max-width: 100%;
}

.sw-sq {
  position: relative; overflow: hidden;
  background: var(--sw-carte, rgba(127, 127, 127, .10));
  border-radius: 10px;
}
/* Le balayage : une bande claire qui traverse, et rien d'autre. Pas de
   pulsation — deux animations concurrentes sur un même écran donnent
   l'impression que quelque chose cloche. */
.sw-sq::after {
  content: ''; position: absolute; inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg,
    transparent, color-mix(in srgb, var(--sw-encre, #fff) 8%, transparent), transparent);
  animation: sw-chatoie 1.6s ease-in-out infinite;
}
@keyframes sw-chatoie { to { transform: translateX(100%) } }

/* L'APPARITION EN CASCADE.
 *
 * Tout poser d'un bloc donne un mur gris. Chaque rangée arrive avec quelques
 * dizaines de millisecondes de retard sur la précédente : l'œil suit une
 * descente, et l'attente se lit comme une construction plutôt que comme un
 * écran figé. Le retard est plafonné — au-delà d'un demi-tour, on n'attend
 * plus, on patiente. */
.sw-squelette > *, .sw-sq-grille > * {
  opacity: 0;
  animation: sw-parait 420ms cubic-bezier(.16, 1, .3, 1) forwards;
}
@keyframes sw-parait {
  from { opacity: 0; transform: translateY(6px) }
  to { opacity: 1; transform: none }
}
.sw-squelette > *:nth-child(1) { animation-delay: 0ms }
.sw-squelette > *:nth-child(2) { animation-delay: 45ms }
.sw-squelette > *:nth-child(3) { animation-delay: 90ms }
.sw-squelette > *:nth-child(4) { animation-delay: 190ms }
.sw-squelette > *:nth-child(5) { animation-delay: 225ms }
.sw-squelette > *:nth-child(6) { animation-delay: 260ms }
.sw-sq-grille > *:nth-child(1) { animation-delay: 110ms }
.sw-sq-grille > *:nth-child(2) { animation-delay: 130ms }
.sw-sq-grille > *:nth-child(3) { animation-delay: 150ms }
.sw-sq-grille > *:nth-child(4) { animation-delay: 170ms }
.sw-sq-grille > *:nth-child(5) { animation-delay: 190ms }
.sw-sq-grille > *:nth-child(6) { animation-delay: 210ms }

/* Le vrai contenu ne remplace pas le fantôme d'un coup sec : il se fond
   dedans. La forme étant déjà la bonne, rien ne se déplace — seule la matière
   change. */
.sw-body.est-neuf { animation: sw-fond 260ms ease-out; }
@keyframes sw-fond { from { opacity: .35 } to { opacity: 1 } }

.sw-sq-titre { height: 26px; width: 210px; border-radius: 7px; }
/* Les initiales des jours : sept petites pastilles, comme la vraie ligne
   d'en-tête. Sans elles, la grille flottait sans repère. */
.sw-sq-jours { display: grid; grid-template-columns: repeat(7, 1fr); gap: .45rem; }
.sw-sq-init { height: 11px; width: 13px; border-radius: 3px; margin: 0 auto; opacity: .55; }
/* Le bouton se devine : c'est l'action qui attend au bout, et la teinter
   raconte déjà ce qu'on va pouvoir faire. */
.sw-sq-bouton {
  background: color-mix(in srgb, var(--sw-primaire, #8a2b3a) 24%, transparent);
}
.sw-sq-champs { display: flex; gap: .8rem; align-items: stretch; }
.sw-sq-champ { height: 74px; flex: 1 1 0; }
.sw-sq-nuits { height: 74px; width: 96px; border-radius: 999px; flex: 0 0 auto; }

.sw-sq-mois { display: grid; grid-template-columns: 1fr 1fr; gap: 1.6rem; }
.sw-sq-grille { display: flex; flex-direction: column; gap: .5rem; }
.sw-sq-entete { height: 20px; width: 150px; margin: 0 auto .35rem; border-radius: 6px; }
.sw-sq-semaine { display: grid; grid-template-columns: repeat(7, 1fr); gap: .45rem; }
.sw-sq-jour { height: 62px; border-radius: 8px; }
/* Les jours passés du mois courant sont vides sur la vraie grille : les
   laisser vides ici aussi, sinon le squelette promet plus qu'il ne livre. */
.sw-sq-jour.est-vide { background: transparent; }
.sw-sq-jour.est-vide::after { display: none; }

.sw-sq-ligne { height: 16px; width: 330px; border-radius: 5px; }
.sw-sq-compteur { height: 62px; border-radius: 10px; }
.sw-sq-bouton { height: 58px; border-radius: 10px; }

@media (max-width: 720px) {
  .sw-sq-mois { grid-template-columns: 1fr; }
  .sw-sq-jour { height: 46px; }
  .sw-sq-champs { flex-wrap: wrap; }
  .sw-sq-nuits { width: 100%; height: 48px; }
}

@media (prefers-reduced-motion: reduce) {
  .sw-sq::after { animation: none; }
}

.sw-attente, .sw-vide {
  padding: 3.5rem 1.5rem; text-align: center; color: var(--sw-doux);
  max-width: 460px; margin: 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: .9rem;
}
/* Dans un état vide, le titre n'est plus un titre d'étape : il annonce une
   impasse. Il reste une phrase, pas une manchette. */
.sw-vide .sw-titre {
  margin: 0; font-size: 1.05rem; font-weight: 600; color: var(--sw-encre);
}
.sw-vide p { margin: 0; font-size: .9rem; }
/* Le bouton ne prend pas toute la largeur : une bande pleine de la couleur de
   la marque, sur un écran par ailleurs vide, se lit comme une alerte. */
.sw-vide .sw-primaire, .sw-vide .sw-secondaire { width: auto; min-width: 200px; }
.sw-appel { margin: 0; }
.sw-appel a {
  color: var(--sw-encre); text-decoration: underline;
  text-decoration-color: var(--sw-doux); text-underline-offset: 4px;
}

/* ── Boutons ─────────────────────────────────────────────── */

.sw-primaire, .sw-secondaire {
  display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
  padding: .85rem 1.4rem; border-radius: 4px; font: inherit; font-size: .95rem;
  font-weight: 500; cursor: pointer; text-decoration: none;
  transition: background var(--sw-transition), border-color var(--sw-transition),
              transform var(--sw-transition), opacity var(--sw-transition);
}
.sw-primaire {
  width: 100%; border: 1px solid var(--sw-primaire);
  background: var(--sw-primaire); color: var(--sw-sur-primaire);
}
.sw-primaire:hover:not(:disabled) { background: var(--sw-primaire-clair); border-color: var(--sw-primaire-clair); }
.sw-primaire:disabled { opacity: .4; cursor: not-allowed; }
.sw-secondaire {
  border: 1px solid var(--sw-ligne); background: var(--sw-carte); color: var(--sw-encre);
}
.sw-secondaire:hover { border-color: var(--sw-primaire); background: var(--sw-carte-haut); }
.sw-compact { width: auto; padding: .6rem 1.1rem; font-size: .88rem; }
.sw-large { width: 100%; margin-top: .8rem; }

.sw-lien {
  border: 0; background: none; padding: 0; font: inherit; font-size: .85rem;
  color: var(--sw-encre); cursor: pointer;
  text-decoration: underline; text-decoration-color: var(--sw-doux);
  text-underline-offset: 4px; text-decoration-thickness: 1px;
  display: inline-flex; align-items: center; gap: .4rem;
  transition: text-decoration-color var(--sw-transition);
}
.sw-lien:hover { text-decoration-color: var(--sw-encre); }
.sw-lien svg {
  width: 14px; height: 14px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round;
}

/* ── La barre d'action ───────────────────────────────────
   Le bouton principal était collé en bas par un `position: sticky` nu : il
   flottait au-dessus du calendrier, et l'on voyait les cases défiler derrière
   ses coins arrondis. Une barre le porte, avec un fond opaque et un dégradé au
   ras du contenu — on comprend alors que ce qui passe dessous continue.

   Elle est dans le flux, sur toutes les étapes qui en ont un : elle ne
   recouvre jamais la dernière ligne, puisqu'elle en fait partie. */
.sw-actions {
  position: sticky; bottom: 0; z-index: 4;
  margin: 1.4rem -.6rem -.4rem;
  padding: .8rem .6rem .6rem;
  background: var(--sw-fond);
  /* Le dégradé fait la transition avec ce qui défile dessous : une coupure
     nette se lit comme un bord de fenêtre au milieu de la page. */
  box-shadow: 0 -14px 18px -6px var(--sw-fond);
}
.sw-actions::before {
  content: ''; position: absolute; left: 0; right: 0; top: -22px; height: 22px;
  background: linear-gradient(to top, var(--sw-fond), transparent);
  pointer-events: none;
}

/* ── Étape 1 : les dates ─────────────────────────────────── */

.sw-dates-resume {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin-bottom: 1.2rem;
}
.sw-date-case {
  flex: 1 1 160px; min-width: 140px;
  padding: .7rem .95rem; border: 1px solid var(--sw-ligne);
  border-radius: 4px; background: var(--sw-carte); cursor: pointer;
  transition: border-color var(--sw-transition), box-shadow var(--sw-transition);
}
.sw-date-case:hover { border-color: var(--sw-doux); }
/* Celui qu'on est en train de remplir. Une bordure pleine de la couleur de
   marque se lit comme une erreur de saisie : on met un halo, qui désigne sans
   alerter. */
.sw-date-case.is-active {
  border-color: var(--sw-primaire); background: var(--sw-carte-haut);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--sw-primaire) 22%, transparent);
}
.sw-date-label {
  display: block; font-size: .7rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--sw-doux); margin-bottom: .15rem;
}
.sw-date-case strong { font-size: .98rem; color: var(--sw-encre); font-weight: 600; }
.sw-date-fleche { color: var(--sw-doux); flex: 0 0 auto; }
.sw-date-fleche svg {
  width: 18px; height: 18px; fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.sw-date-nuits {
  flex: 0 0 auto; font-size: .85rem; color: var(--sw-doux);
  padding: .35rem .8rem; background: var(--sw-carte);
  border: 1px solid var(--sw-ligne); border-radius: 999px;
  white-space: nowrap;
}
/* Vide tant qu'aucun départ n'est choisi, elle flottait à droite comme un
   bouton mort. `:empty` ne suffit pas : le gabarit y laisse une espace. */
.sw-date-nuits:empty, .sw-date-nuits:blank { display: none; }

.sw-cal-zone { position: relative; margin-bottom: 1rem; }
/* Les deux flèches encadrent les mois plutôt que de se serrer dans le coin du
   second : à droite, « précédent » désigne le mois de gauche, ce que personne
   ne lit ainsi. */
.sw-cal-nav {
  position: absolute; top: -2px; left: 0; right: 0; z-index: 2;
  display: flex; justify-content: space-between; pointer-events: none;
}
.sw-cal-nav button { pointer-events: auto; }
.sw-cal-nav button {
  width: 32px; height: 32px; border: 1px solid var(--sw-ligne);
  background: var(--sw-carte); border-radius: 4px; cursor: pointer;
  color: var(--sw-texte); display: inline-flex; align-items: center; justify-content: center;
  transition: border-color var(--sw-transition);
}
.sw-cal-nav button:hover:not(:disabled) { border-color: var(--sw-primaire); }
.sw-cal-nav button:disabled { opacity: .3; cursor: not-allowed; }
.sw-cal-nav svg {
  width: 16px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}

.sw-cal-mois { display: grid; grid-template-columns: 1fr 1fr; gap: 1.6rem; }
.sw-cal h3 {
  margin: 0 0 .9rem; font-size: .95rem; font-weight: 600;
  color: var(--sw-encre); text-transform: capitalize; text-align: center;
}
.sw-cal-dow, .sw-cal-grille { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.sw-cal-dow span {
  text-align: center; font-size: .68rem; color: var(--sw-doux);
  letter-spacing: .08em; padding-bottom: .3rem;
}
.sw-cal-vide { aspect-ratio: 1 / .92; }

/* Une case de calendrier porte le jour ET son prix : c'est ce qui évite de
   chercher une nuit abordable en tâtonnant, combinaison après combinaison. */
.sw-cal-jour {
  aspect-ratio: 1 / .92; min-height: 44px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; border: 1px solid transparent; border-radius: 4px;
  background: var(--sw-carte); cursor: pointer; font: inherit;
  color: var(--sw-texte); padding: 2px;
  transition: background var(--sw-transition), border-color var(--sw-transition);
}
.sw-cal-jour b { font-size: .88rem; font-weight: 500; line-height: 1; }
.sw-cal-jour small {
  font-size: .62rem; color: var(--sw-doux); line-height: 1;
  min-height: .7em; white-space: nowrap;
}
.sw-cal-jour:hover:not(:disabled) { background: var(--sw-carte-haut); border-color: var(--sw-primaire); }
.sw-cal-jour.is-bloque {
  /* Estompés, non rayés. Une grille entière de chiffres barrés se lit comme
     une annulation, alors qu'il s'agit simplement de jours passés. Le barré
     reste pour ce qui est refusé POUR UNE RAISON — une nuit complète. */
  color: color-mix(in srgb, var(--sw-doux) 45%, transparent);
  background: transparent; cursor: default;
}
.sw-cal-jour.is-bloque small { visibility: hidden; }
/* La plage retenue.
 *
 * Elle était peinte avec `--sw-fond` : sur un panneau ardoise, c'est la
 * couleur du panneau — les nuits entre l'arrivée et le départ n'étaient donc
 * marquées par rien, et l'on voyait deux cases rouges isolées sans comprendre
 * ce qu'on avait choisi.
 *
 * Elle prend maintenant une teinte de l'accent, et les cases se touchent :
 * c'est une BARRE continue de l'arrivée au départ, pas cinq carrés côte à
 * côte. Les coins ne s'arrondissent qu'aux deux extrémités. */
.sw-cal-jour.is-plage {
  background: color-mix(in srgb, var(--sw-primaire) 26%, transparent);
  border-color: transparent; border-radius: 0;
}
.sw-cal-jour.is-plage:hover:not(:disabled) {
  background: color-mix(in srgb, var(--sw-primaire) 38%, transparent);
}

.sw-cal-jour.is-arrivee, .sw-cal-jour.is-depart {
  background: var(--sw-primaire); border-color: var(--sw-primaire);
  color: var(--sw-sur-primaire); font-weight: 600;
}
/* L'arrivée ferme la barre à gauche, le départ à droite : les deux angles
   intérieurs restent droits pour que la bande soit continue. */
.sw-cal-jour.is-arrivee { border-radius: 4px 0 0 4px; }
.sw-cal-jour.is-depart { border-radius: 0 4px 4px 0; }
/* Sauf s'il n'y a qu'une nuit : les deux bouts sont alors la même case. */
.sw-cal-jour.is-arrivee.is-depart { border-radius: 4px; }
.sw-cal-jour.is-arrivee small, .sw-cal-jour.is-depart small { color: rgba(255, 255, 255, .78); }

/* Une bande ne peut pas traverser un bord de semaine : le dimanche ferme la
   ligne, le lundi la rouvre. Sans cela, l'arrondi manquait d'un côté et la
   barre semblait coupée au milieu d'un mot. */
.sw-cal-grille .sw-cal-jour.is-plage:nth-child(7n + 1) { border-radius: 4px 0 0 4px; }
.sw-cal-grille .sw-cal-jour.is-plage:nth-child(7n) { border-radius: 0 4px 4px 0; }
.sw-cal-jour.is-cta { position: relative; }
.sw-cal-jour.is-cta::after {
  content: ''; position: absolute; bottom: 3px; width: 10px; height: 2px;
  background: var(--sw-doux); border-radius: 2px;
}

.sw-horaires {
  font-size: .78rem; color: var(--sw-doux);
  padding: .6rem 0 1rem; border-bottom: 1px solid var(--sw-ligne); margin-bottom: 1.1rem;
}

.sw-occupants, .sw-occupation { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.2rem; }
.sw-compteur { flex: 1 1 180px; }
.sw-compteur-label {
  display: block; font-size: .78rem; color: var(--sw-doux); margin-bottom: .35rem;
}
.sw-compteur-boites {
  display: flex; align-items: center; justify-content: space-between;
  border: 1px solid var(--sw-ligne); border-radius: 4px;
  background: var(--sw-carte); padding: .25rem;
}
.sw-compteur-boites button {
  width: 36px; height: 36px; border: 0; background: transparent; cursor: pointer;
  color: var(--sw-encre); border-radius: 3px;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--sw-transition), opacity var(--sw-transition);
}
.sw-compteur-boites button:hover:not(:disabled) { background: var(--sw-carte-haut); }
.sw-compteur-boites button:disabled { opacity: .25; cursor: not-allowed; }
.sw-compteur-boites svg {
  width: 16px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round;
}
.sw-compteur-valeur { font-size: 1rem; font-weight: 600; color: var(--sw-encre); }

.sw-promo { margin-bottom: 1.4rem; }
.sw-promo-champ label {
  display: block; font-size: .78rem; color: var(--sw-doux); margin-bottom: .3rem;
}
.sw-promo-champ input {
  width: 100%; max-width: 260px; padding: .65rem .8rem; font: inherit;
  border: 1px solid var(--sw-ligne); border-radius: 4px; background: var(--sw-carte);
  text-transform: uppercase;
}

/* ── Étape 2 : les cartes ────────────────────────────────── */

.sw-rappel-dates {
  display: flex; align-items: center; gap: .9rem; flex-wrap: wrap;
  padding: .7rem 1rem; background: var(--sw-carte); border: 1px solid var(--sw-ligne);
  border-radius: 4px; margin-bottom: 1.2rem; font-size: .85rem;
}
.sw-rappel-quand { font-weight: 600; color: var(--sw-encre); }
.sw-rappel-dates .sw-lien { margin-left: auto; }

.sw-cartes {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 1.2rem;
}
.sw-carte {
  background: var(--sw-carte); border: 1px solid var(--sw-ligne);
  border-radius: var(--sw-radius); overflow: hidden;
  display: flex; flex-direction: column;
  transition: border-color var(--sw-transition), box-shadow var(--sw-transition);
}
.sw-carte:hover { background: var(--sw-carte-haut); border-color: var(--sw-doux); }
.sw-carte.is-indispo { opacity: .62; }

.sw-carte-media { position: relative; }
.sw-galerie { position: relative; aspect-ratio: 16 / 10; background: var(--sw-carte-haut); }
.sw-galerie img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity var(--sw-transition);
}
.sw-galerie img.is-vue { opacity: 1; }
/* Une catégorie sans photo n'affiche pas un appareil photo barré : elle
   n'affiche rien. Un défaut de contenu ne doit pas ressembler à une panne. */
.sw-galerie-vide {
  background: linear-gradient(135deg, var(--sw-carte-haut), var(--sw-carte));
}
/* La barre de la galerie : deux chevrons encadrant les points.
   Les points seuls suffisent au doigt, qui balaie ; à la souris ils font des
   cibles de sept pixels, et l'on clique à côté. Le tout repose sur un voile
   sombre — sans lui, des points blancs sur une chambre blanche disparaissent. */
/* ── Le paiement dans la modale ─────────────────────────────
   Le cadre de Stripe est un iframe : il apporte son propre fond clair, quel
   que soit le thème du site. On lui donne donc un socle blanc et un peu d'air,
   plutôt que de le poser à même le fond sombre où ses bords flotteraient. */
/* Ce qui est réglé se dit en vert, une fois. C'est la seule couleur vive de
   l'écran de remerciement, et elle porte la bonne nouvelle. */
.sw-merci-note.est-regle {
  border-left-color: var(--sw-ok);
  color: var(--sw-encre);
}

.sw-etape-paiement { display: flex; flex-direction: column; gap: .9rem; }

/* La phrase qui précède le formulaire de carte.
 *
 * Elle était en gris pâle et en petit, comme une mention légale — alors que
 * c'est la seule chose qui rassure au moment précis où l'on donne son numéro
 * de carte. « Rien ne sera débité » doit se lire d'un coup d'œil, pas se
 * chercher. Elle prend donc la taille du texte courant, la couleur de l'encre,
 * et le liseré d'accent qui la désigne comme une information, pas un détail. */
.sw-avant-paiement {
  margin: 0; font-size: 1rem; line-height: 1.55; color: var(--sw-encre);
  padding: .9rem 1.1rem; background: var(--sw-carte);
  border-left: 3px solid var(--sw-accent); border-radius: 0 6px 6px 0;
  max-width: 62ch;
}
/* Le montant, lui, se détache : c'est le chiffre qu'on vérifie. */
.sw-avant-paiement strong { color: var(--sw-encre); font-weight: 700; }
.sw-stripe-cadre {
  background: #ffffff; border-radius: var(--sw-rayon, 8px);
  padding: .6rem; min-height: 320px;
}
.sw-paiement-plus-tard {
  display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
  justify-content: center; margin: 0;
}

/* Le mot qui accompagne la redirection : il explique le saut vers un domaine
   étranger, et ne doit pas ressembler à une erreur. */
.sw-vers-paiement {
  display: flex; flex-direction: column; align-items: center; gap: .4rem;
  margin-top: 1.2rem;
}
.sw-vers-paiement a {
  color: var(--sw-primaire); text-decoration: underline; font-weight: 600;
}

.sw-galerie-barre {
  position: absolute; bottom: .55rem; left: 50%; transform: translateX(-50%);
  max-width: calc(100% - 1.2rem);
  display: flex; align-items: center; gap: .15rem;
  padding: .2rem .25rem; border-radius: 999px;
  background: rgba(20, 24, 30, .42);
  backdrop-filter: blur(3px);
  opacity: .82; transition: opacity var(--sw-transition);
}
.sw-carte:hover .sw-galerie-barre, .sw-galerie-barre:focus-within { opacity: 1; }

.sw-galerie-fleche {
  flex: none; width: 22px; height: 22px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 50%; background: none; cursor: pointer;
  color: rgba(255, 255, 255, .85);
  transition: background var(--sw-transition), color var(--sw-transition);
}
.sw-galerie-fleche:hover { background: rgba(255, 255, 255, .18); color: #ffffff; }
.sw-galerie-fleche svg {
  width: 13px; height: 13px; fill: none;
  stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}

.sw-galerie-points {
  display: flex; align-items: center; gap: .3rem;
  padding: 0 .25rem; overflow-x: auto;
  scrollbar-width: none; -ms-overflow-style: none;
}
.sw-galerie-points::-webkit-scrollbar { display: none; }
.sw-galerie-points button {
  flex: none;
  width: 7px; height: 7px; border-radius: 50%; border: 0; padding: 0; cursor: pointer;
  background: rgba(255, 255, 255, .55);
  transition: background var(--sw-transition), transform var(--sw-transition);
}
.sw-galerie-points button.is-vue { background: #ffffff; transform: scale(1.25); }

.sw-badge {
  position: absolute; top: .7rem; left: .7rem;
  background: rgba(26, 26, 26, .82); color: #ffffff;
  font-size: .7rem; letter-spacing: .08em; text-transform: uppercase;
  padding: .3rem .6rem; border-radius: 3px;
}

.sw-carte-corps { padding: 1rem 1.1rem 1.1rem; display: flex; flex-direction: column; flex: 1; }
.sw-carte-corps h3 { margin: 0 0 .5rem; font-size: 1.05rem; color: var(--sw-encre); font-weight: 600; }
.sw-carte-meta {
  display: flex; align-items: center; gap: .4rem;
  margin: 0 0 .6rem; font-size: .83rem; color: var(--sw-texte);
}
.sw-carte-meta svg {
  width: 15px; height: 15px; flex: 0 0 auto; fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; color: var(--sw-doux);
}
.sw-desc { margin: 0 0 .9rem; font-size: .88rem; line-height: 1.6; }

/* Le groupe tient dans cette catégorie, mais pas dans une seule de ses
   chambres : on le dit sur la carte, avant le prix — qui les compte toutes. */
.sw-multi {
  margin: 0 0 .7rem; font-size: .8rem; color: var(--sw-encre);
  padding: .4rem .6rem; background: var(--sw-carte-haut); border-radius: 4px;
}

/* La description sur la carte : deux lignes, sans dépliant.
 *
 * Un « Plus » à ouvrir sur chacune des trois cartes demandait trois clics pour
 * comparer trois chambres — et le chevron coloré attirait l'œil sur un lien de
 * service au lieu du prix. Le texte entier est à l'étape suivante, là où l'on
 * décide vraiment. */
.sw-carte-desc {
  margin: 0 0 .8rem; font-size: .85rem; line-height: 1.55; color: var(--sw-texte);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Les équipements en étiquettes : on les balaie du regard au lieu de les lire,
   et c'est ce qu'on fait vraiment quand on compare deux chambres. */
.sw-equipements {
  display: flex; flex-wrap: wrap; gap: .35rem; margin: 0 0 .9rem;
}
.sw-equipements li {
  font-size: .74rem; line-height: 1.3; padding: .25rem .55rem;
  background: var(--sw-carte-haut); border-radius: 999px; color: var(--sw-texte);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.sw-equip-reste { color: var(--sw-doux); }

.sw-plus { margin-bottom: .7rem; font-size: .85rem; }
.sw-plus summary {
  cursor: pointer; color: var(--sw-encre); font-size: .85rem;
  list-style: none; display: inline-flex; align-items: center; gap: .3rem;
}
.sw-plus summary::-webkit-details-marker { display: none; }
.sw-plus summary::before { content: '▾'; transition: transform var(--sw-transition); }
.sw-plus[open] summary::before { transform: rotate(180deg); }
.sw-plus p { margin: .5rem 0 0; font-size: .85rem; line-height: 1.6; }
/* Les équipements : une coche par ligne. Le reset a retiré les puces natives —
   elles revenaient de toute façon au style du site, quand il en avait un — et
   une liste sans marque se lit comme un paragraphe hachuré. */
.sw-plus ul { margin: .7rem 0 0; display: flex; flex-direction: column; gap: .3rem; }
.sw-plus li {
  position: relative; padding-left: 1.3rem;
  font-size: .85rem; line-height: 1.45; color: var(--sw-texte);
}
.sw-plus li::before {
  content: ''; position: absolute; left: 0; top: .42em;
  width: 11px; height: 6px; border-left: 1.6px solid var(--sw-accent);
  border-bottom: 1.6px solid var(--sw-accent); transform: rotate(-45deg);
}

.sw-comparatif {
  margin: .2rem 0 .8rem; padding: .7rem .85rem;
  background: var(--sw-fond); border-radius: 4px; font-size: .82rem;
}
.sw-comparatif-notre { display: flex; justify-content: space-between; align-items: baseline; }
.sw-comparatif-notre strong { color: var(--sw-encre); font-size: .95rem; }
.sw-comparatif ul { list-style: none; margin: .4rem 0 0; padding: 0; }
.sw-comparatif li { display: flex; justify-content: space-between; color: var(--sw-doux); }
.sw-economie { margin: .45rem 0 0; color: var(--sw-ok); font-weight: 600; }
/* Le chevron du dépliant : la couleur y est décorative, et le mot à côté est
   déjà lisible. */
.sw-plus summary::before { color: var(--sw-accent); }

.sw-carte-pied {
  margin-top: auto; padding-top: .8rem; border-top: 1px solid var(--sw-ligne);
  display: flex; align-items: flex-end; justify-content: space-between; gap: .8rem;
}
.sw-prix { display: flex; flex-direction: column; gap: 1px; }
.sw-prix-label { font-size: .72rem; color: var(--sw-doux); }
.sw-prix strong { font-size: 1.25rem; color: var(--sw-encre); font-weight: 600; line-height: 1.1; }
.sw-prix-unite { font-size: .72rem; color: var(--sw-doux); }
/* Une catégorie complète n'a ni prix ni bouton : son pied se retrouvait seul
   en bas d'une carte aussi haute que ses voisines, avec un vide au milieu. Le
   message remonte contre le contenu et prend toute la ligne. */
.sw-carte.is-indispo .sw-carte-pied {
  margin-top: .4rem; border-top: 0; padding-top: 0; justify-content: flex-start;
}
.sw-raison {
  margin: 0; font-size: .85rem; color: var(--sw-doux);
  padding: .5rem .7rem; background: var(--sw-carte-haut); border-radius: 4px; width: 100%;
}

/* ── La combinaison de chambres ───────────────────────────
   Quand aucune catégorie ne loge le groupe seule. Ce n'est pas un état
   d'erreur — c'est une proposition, et elle doit se lire comme telle : un
   bloc, des lignes, un total, un bouton. Pas un message d'excuse. */
.sw-combi-intro { margin: -.8rem 0 1.2rem; }
.sw-combi {
  background: var(--sw-carte); border: 1px solid var(--sw-ligne);
  border-radius: var(--sw-radius); padding: .4rem 1.1rem 1.1rem;
}
.sw-combi-lignes { display: flex; flex-direction: column; }
.sw-combi-lignes li {
  display: grid; grid-template-columns: auto 1fr auto auto;
  align-items: baseline; gap: .7rem;
  padding: .7rem 0; border-bottom: 1px solid var(--sw-ligne); font-size: .92rem;
}
.sw-combi-lignes li:last-child { border-bottom: 0; }
.sw-combi-nb { color: var(--sw-doux); font-variant-numeric: tabular-nums; }
.sw-combi-nom { color: var(--sw-encre); font-weight: 500; }
.sw-combi-cap { font-size: .8rem; color: var(--sw-doux); }
.sw-combi-prix { font-variant-numeric: tabular-nums; white-space: nowrap; }
.sw-combi .sw-total { margin-top: .9rem; }
.sw-combi .sw-actions { margin-bottom: -.5rem; }


/* Sur téléphone, quatre colonnes ne tiennent pas : la capacité passe sous le
   nom, et le prix garde sa colonne — c'est lui qu'on compare. */
@media (max-width: 620px) {
  .sw-combi-lignes li { grid-template-columns: auto 1fr auto; row-gap: .1rem; }
  .sw-combi-cap { grid-column: 2; font-size: .76rem; }
}

/* ── Étape 3 : tarifs et suppléments ─────────────────────── */

.sw-tete-cat {
  display: flex; gap: 1.4rem; margin-bottom: 1.8rem; align-items: flex-start;
  padding-bottom: 1.4rem; border-bottom: 1px solid var(--sw-ligne);
}
.sw-tete-cat img {
  width: 300px; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--sw-radius); flex: 0 0 auto;
}
.sw-tete-cat-texte { flex: 1; min-width: 0; }
.sw-tete-cat .sw-titre { margin-bottom: .5rem; }
.sw-tete-cat .sw-carte-meta { margin-bottom: .8rem; }
.sw-tete-cat .sw-equipements { margin-bottom: 0; }

.sw-deux-colonnes { display: grid; grid-template-columns: 1fr 1fr; gap: 1.6rem; align-items: start; }
.sw-colonne h3 {
  margin: 0 0 .8rem; font-size: .95rem; color: var(--sw-encre); font-weight: 600;
}
.sw-colonne h3 + h3, .sw-occupation + h3 { margin-top: 1.6rem; }

.sw-extras { display: flex; flex-direction: column; gap: .7rem; }
.sw-extra {
  display: flex; gap: .85rem; padding: .8rem;
  background: var(--sw-carte); border: 1px solid var(--sw-ligne); border-radius: 4px;
  transition: border-color var(--sw-transition);
}
.sw-extra.is-choisi { border-color: var(--sw-primaire); }
.sw-extra img {
  width: 92px; height: 92px; object-fit: cover; border-radius: 3px; flex: 0 0 auto;
}
.sw-extra-corps { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.sw-extra-corps h4 { margin: 0 0 .25rem; font-size: .92rem; color: var(--sw-encre); font-weight: 600; }
.sw-extra-corps p {
  margin: 0 0 .5rem; font-size: .82rem; color: var(--sw-texte);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.sw-extra-pied {
  margin-top: auto; display: flex; align-items: center;
  justify-content: space-between; gap: .6rem; flex-wrap: wrap;
}
.sw-extra-prix { display: flex; flex-direction: column; }
.sw-extra-prix strong { font-size: .98rem; color: var(--sw-encre); }
.sw-extra-prix small { font-size: .72rem; color: var(--sw-doux); }

.sw-tarifs { display: flex; flex-direction: column; gap: .7rem; }
.sw-tarif {
  padding: 1rem; background: var(--sw-carte);
  border: 1px solid var(--sw-ligne); border-radius: 4px;
}
.sw-tarif h4 { margin: 0 0 .35rem; font-size: .95rem; color: var(--sw-encre); font-weight: 600; }
.sw-tarif-conditions {
  margin: 0 0 .8rem; font-size: .82rem; color: var(--sw-texte); white-space: pre-line;
}
.sw-tarif-pied {
  display: flex; align-items: flex-end; justify-content: space-between; gap: .8rem;
  padding-top: .7rem; border-top: 1px solid var(--sw-ligne);
}

/* Les trois classes qu'un contrôle mécanique a trouvées posées par le script
   sans jamais avoir été habillées. À l'œil, elles ne se voyaient pas — un bloc
   sans style ressemble à un bloc qu'on a voulu discret. */
.sw-etape-tarifs { max-width: 100%; }
/* La première étape n'a pas de largeur propre : elle porte le calendrier, qui
   occupe la sienne. La classe existait pourtant dans le gabarit — trouvée par
   la recette, jamais habillée. */
.sw-etape-dates { max-width: 100%; }
.sw-form { display: block; }
/* Le champ de carte de Stripe s'insère ici. Vide tant que le paiement n'est
   pas branché : il ne doit alors occuper aucune place. */
.sw-stripe:empty { display: none; }
.sw-stripe { margin-top: .9rem; }

/* ── Étape 4 : le récapitulatif ──────────────────────────── */

.sw-etape-recap { max-width: 720px; }
.sw-recap-sejour {
  padding: 1rem 1.1rem; background: var(--sw-carte);
  border: 1px solid var(--sw-ligne); border-radius: 4px; margin-bottom: 1.1rem;
}
.sw-recap-dates strong { display: block; font-size: 1.02rem; color: var(--sw-encre); }
.sw-recap-dates span { font-size: .85rem; color: var(--sw-doux); }

.sw-recap-lignes {
  background: var(--sw-carte); border: 1px solid var(--sw-ligne);
  border-radius: 4px; padding: .5rem 1.1rem;
}
.sw-ligne {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: .5rem 0; font-size: .9rem;
}
.sw-ligne + .sw-ligne { border-top: 1px solid var(--sw-ligne); }
.sw-ligne-douce { color: var(--sw-doux); font-size: .82rem; }
.sw-ligne.is-remise { color: var(--sw-ok); }
.sw-ligne-forte { font-size: 1rem; font-weight: 600; color: var(--sw-encre); }

.sw-taxes {
  margin-top: .7rem; background: var(--sw-carte);
  border: 1px solid var(--sw-ligne); border-radius: 4px; padding: .5rem 1.1rem;
}
.sw-taxes summary {
  display: flex; justify-content: space-between; cursor: pointer;
  font-size: .9rem; padding: .4rem 0; list-style: none;
}
.sw-taxes summary::-webkit-details-marker { display: none; }
.sw-taxes .sw-doux { padding: .4rem 0 .2rem; }

/* La ventilation de TVA sous le détail : une mention, pas une ligne de compte.
   Trouvée par la recette — posée dans le gabarit, jamais habillée, et
   invisible à la relecture parce qu'un texte sans style ressemble à un texte
   qu'on a voulu discret. */
.sw-taxes-note {
  margin: .5rem .2rem 0; font-size: .78rem; line-height: 1.5;
}

.sw-total {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-top: 1.1rem; padding: 1rem 1.1rem;
  background: var(--sw-carte); border: 1px solid var(--sw-primaire); border-radius: 4px;
}
.sw-total span { font-size: 1rem; color: var(--sw-encre); }
.sw-total strong { font-size: 1.4rem; color: var(--sw-encre); font-weight: 600; }
.sw-note-paiement {
  margin: .7rem 0 1.4rem; font-size: .85rem; color: var(--sw-texte);
  padding: .75rem .9rem; background: var(--sw-carte);
  border-left: 2px solid var(--sw-accent); border-radius: 0 4px 4px 0;
}

/* ── Étape 5 : le formulaire ─────────────────────────────── */

.sw-etape-fin { max-width: 720px; }
.sw-champs { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem; }
.sw-champ { display: flex; flex-direction: column; gap: .3rem; }
.sw-champ-large { grid-column: 1 / -1; }
.sw-champ > span { font-size: .78rem; color: var(--sw-doux); }
.sw-champ input, .sw-champ textarea {
  width: 100%; padding: .7rem .8rem; font: inherit; font-size: .92rem;
  border: 1px solid var(--sw-ligne); border-radius: 4px;
  background: var(--sw-carte); color: var(--sw-encre);
  transition: border-color var(--sw-transition);
}
.sw-champ input:focus, .sw-champ textarea:focus, .sw-champ select:focus {
  outline: none; border-color: var(--sw-primaire);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--sw-primaire) 28%, transparent);
}
/* Les champs eux-mêmes : une surface, pas un rectangle blanc au milieu de
   l'ardoise. Le texte saisi reste en clair. */
.sw-champ select {
  width: 100%; padding: .7rem .8rem; font: inherit; font-size: .92rem;
  border: 1px solid var(--sw-ligne); border-radius: 4px;
  background: var(--sw-carte); color: var(--sw-encre);
  appearance: none; -webkit-appearance: none; padding-right: 2rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .6rem center; background-size: 14px;
  cursor: pointer;
}
/* Le texte saisi hérite sinon du gris de labeur : sur ardoise, il faut le
   clair. Et le texte d'invite doit rester en retrait, sans disparaître. */
.sw-champ input, .sw-champ textarea { color: var(--sw-encre); }
.sw-champ input::placeholder, .sw-champ textarea::placeholder { color: var(--sw-doux); }
.sw-champ input.is-souci { border-color: var(--sw-souci); }
.sw-champ textarea { resize: vertical; min-height: 76px; }
.sw-aide, .sw-verdict { font-size: .74rem; color: var(--sw-doux); }
.sw-verdict.is-ok { color: var(--sw-ok); }
.sw-verdict.is-souci { color: var(--sw-souci); }

.sw-bascule, .sw-case {
  display: flex; align-items: flex-start; gap: .6rem;
  margin: 1rem 0; font-size: .88rem; cursor: pointer;
}
.sw-bascule input, .sw-case input {
  width: 17px; height: 17px; margin: 2px 0 0; flex: 0 0 auto;
  accent-color: var(--sw-primaire); cursor: pointer;
}
.sw-case a {
  color: var(--sw-encre); text-decoration: underline;
  text-decoration-color: var(--sw-doux); text-underline-offset: 3px;
}
.sw-pro { margin-top: .4rem; }

.sw-paiement {
  padding: 1rem 1.1rem; background: var(--sw-carte);
  border: 1px solid var(--sw-ligne); border-radius: 4px;
}
.sw-paiement-montant {
  display: flex; justify-content: space-between; align-items: baseline;
  padding-bottom: .7rem;
}
.sw-paiement-montant strong { font-size: 1.2rem; color: var(--sw-encre); }
.sw-recap-final { margin: 1.1rem 0; }

/* Le piège : hors de l'écran, mais accessible au remplissage automatique d'un
   robot. `display:none` serait ignoré par la plupart d'entre eux. */
.sw-piege {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0;
}

.sw-erreur {
  margin: 0 0 .9rem; padding: .7rem .9rem; font-size: .88rem;
  color: var(--sw-souci); background: rgba(255, 155, 145, .1);
  border: 1px solid rgba(255, 155, 145, .3); border-radius: 4px;
}

/* ── Étape 6 : la confirmation ───────────────────────────── */

.sw-merci { text-align: center; padding: 2.5rem 1.5rem 3rem; max-width: 560px; margin: 0 auto; }

/* La coche : un vert sourd, pas le vert d'un feu de signalisation. Sur une
   ardoise, un vert saturé est la seule chose qu'on voit de l'écran — et ce
   n'est pas la coche qu'on vient lire, c'est la référence. */
.sw-merci-coche {
  width: 52px; height: 52px; margin: 0 auto 1.1rem; border-radius: 50%;
  background: color-mix(in srgb, var(--sw-ok) 22%, transparent);
  border: 1.5px solid color-mix(in srgb, var(--sw-ok) 55%, transparent);
  display: flex; align-items: center; justify-content: center;
}
.sw-merci-coche svg {
  width: 26px; height: 26px; fill: none; stroke: var(--sw-ok);
  stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round;
}

.sw-merci .sw-titre { margin-bottom: .4rem; }
.sw-merci-ref { font-size: .88rem; color: var(--sw-doux); margin: 0 0 1.6rem; }
.sw-merci-ref strong { color: var(--sw-encre); letter-spacing: .04em; }

.sw-merci-carte {
  text-align: left; background: var(--sw-carte);
  border: 1px solid var(--sw-ligne); border-radius: var(--sw-radius);
  padding: 1.1rem 1.2rem; margin-bottom: 1.1rem;
}
/* Les dates au-dessus du détail, et le compte sur sa propre ligne : réunis,
   ils se lisaient comme une seule phrase sans ponctuation. */
.sw-merci-dates { margin-bottom: .9rem; }
.sw-merci-dates strong {
  display: block; font-size: 1rem; color: var(--sw-encre); margin-bottom: .1rem;
}
.sw-merci-dates span { font-size: .85rem; color: var(--sw-doux); }
.sw-merci-carte .sw-recap-lignes {
  background: transparent; border: 0; border-top: 1px solid var(--sw-ligne);
  padding: .3rem 0 0; border-radius: 0;
}
.sw-merci-horaires {
  margin: .9rem 0 0; padding-top: .8rem; border-top: 1px solid var(--sw-ligne);
  font-size: .82rem; color: var(--sw-doux);
}
.sw-merci-note {
  margin: .8rem 0 0; font-size: .85rem; color: var(--sw-texte);
  padding: .7rem .85rem; background: var(--sw-carte-haut);
  border-left: 2px solid var(--sw-accent); border-radius: 0 4px 4px 0;
}

.sw-merci-actions {
  display: flex; align-items: center; justify-content: center;
  gap: 1rem; flex-wrap: wrap; margin-top: 1.4rem;
}
.sw-merci-actions .sw-secondaire { width: auto; }

/* ══════════════════════════════════════════════════════════
   TÉLÉPHONE — plein écran

   Pas une modale rétrécie : la modale disparaît. Sur un écran de 375 px, une
   carte de chambre avec sa photo, son prix et son bouton n'entre pas dans une
   fenêtre à marges — et le peu qu'on gagne en « élégance » se paie en
   réservations abandonnées.
   ══════════════════════════════════════════════════════════ */

@media (max-width: 860px) {
  .sw-modal {
    inset: 0; width: 100%; height: 100%; max-height: none;
    transform: none; left: 0; top: 0;
    border-radius: 0; animation: sw-glisse 240ms cubic-bezier(.16, 1, .3, 1);
    /* La barre d'adresse mobile mange de la hauteur : `dvh` suit ses
       apparitions, `vh` la laisse déborder sous l'écran. */
    height: 100dvh;
  }
  @keyframes sw-glisse {
    from { opacity: 0; transform: translateY(18px) }
    to { opacity: 1; transform: none }
  }
  .sw-backdrop { display: none; }

  /* Le fil des cinq étapes ne tient pas en largeur : il devient un compteur.
     Tassé, il était illisible et ne servait plus à rien. */
  .sw-steps { justify-content: center; }
  .sw-step { display: none; }
  .sw-step::before { display: none; }
  .sw-steps::after {
    content: attr(data-mobile);
    font-size: .85rem; color: var(--sw-encre); font-weight: 600;
  }

  .sw-retour span { display: none; }
  .sw-cal-mois { grid-template-columns: 1fr; gap: 1.4rem; }
  .sw-deux-colonnes { grid-template-columns: 1fr; gap: 1.6rem; }
  .sw-cartes { grid-template-columns: 1fr; }
  .sw-champs { grid-template-columns: 1fr; }
  .sw-tete-cat { flex-direction: column; }
  .sw-tete-cat img { width: 100%; }
  .sw-etape { padding: 1rem 1rem 2.5rem; }

  /* La barre d'action colle au bas de l'écran, sous le pouce : sur téléphone,
     un bouton qu'il faut aller chercher au bout d'un long défilement est la
     première cause d'abandon. */
  .sw-actions { margin-inline: -.9rem; padding-inline: .9rem; }
}

/* ── Téléphone : faire tenir l'étape à l'écran ────────────
   Sur 375 × 667, la première étape demandait deux écrans de défilement pour
   arriver au bouton. Tout se resserre : les marges, le calendrier, les
   compteurs. Ce qui ne peut pas tenir — la liste des chambres, les tarifs —
   défile ; ce qui le peut ne doit pas. */
@media (max-width: 620px) {
  .sw-etape { padding: .9rem .9rem 1.2rem; }
  .sw-titre { font-size: 1.1rem; margin-bottom: .9rem; }
  .sw-sous-titre { margin: 1.2rem 0 .6rem; font-size: .95rem; }

  .sw-dates-resume { gap: .4rem; margin-bottom: .8rem; }
  .sw-date-case { padding: .55rem .7rem; flex: 1 1 42%; min-width: 0; }
  .sw-date-case strong { font-size: .9rem; }
  .sw-date-label { font-size: .62rem; letter-spacing: .08em; }
  .sw-date-nuits { font-size: .78rem; padding: .25rem .6rem; }

  .sw-cal h3 { font-size: .88rem; margin-bottom: .6rem; }
  .sw-cal-jour { min-height: 38px; }
  .sw-cal-jour b { font-size: .82rem; }
  .sw-cal-jour small { font-size: .58rem; }
  .sw-cal-zone { margin-bottom: .7rem; padding-top: 2.6rem; }
  /* Sur un seul mois, les flèches posées en absolu tombaient sur la ligne des
     jours de la semaine — la flèche gauche recouvrait le « L ». Elles
     remontent au-dessus, en ligne, avec le nom du mois entre elles. */
  .sw-cal-nav { top: 0; align-items: center; }
  .sw-cal-mois { gap: 1.1rem; }
  .sw-cal h3 { margin-top: -2.1rem; margin-bottom: 1.4rem; }
  .sw-cal + .sw-cal h3 { margin-top: 0; margin-bottom: .6rem; }

  .sw-horaires { padding: .45rem 0 .7rem; margin-bottom: .7rem; font-size: .74rem; }
  .sw-occupants, .sw-occupation { gap: .6rem; margin-bottom: .8rem; }
  .sw-compteur-boites button { width: 40px; height: 40px; }
  .sw-promo { margin-bottom: 1rem; }

  .sw-rappel-dates { padding: .55rem .7rem; font-size: .8rem; gap: .5rem; }
  .sw-carte-corps { padding: .8rem .9rem .9rem; }
  .sw-carte-corps h3 { font-size: .98rem; }
  .sw-tete-cat { gap: .9rem; margin-bottom: 1.2rem; padding-bottom: 1rem; }
  .sw-equipements li { font-size: .7rem; padding: .2rem .45rem; }
}

@media (max-width: 420px) {
  .sw-extra img { width: 68px; height: 68px; }
  /* Le prix par nuit disparaît des cases : à cette largeur, sept colonnes de
     chiffres à deux lignes deviennent illisibles. Il reste sur les cartes. */
  .sw-cal-jour small { display: none; }
  .sw-cal-jour { min-height: 36px; }
  .sw-equipements { gap: .25rem; }
}

/* ── Accessibilité ───────────────────────────────────────── */

.sw-root :focus-visible {
  outline: 2px solid var(--sw-accent); outline-offset: 2px; border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .sw-modal, .sw-backdrop { animation: none; }
  .sw-root * { transition: none !important; }
}

/* Le lien qui va chercher les informations d'une société au registre européen.
   Discret : c'est un raccourci, pas une étape du parcours. Un bouton plein y
   ferait croire qu'il faut cliquer pour continuer. */
.sw-lien-discret {
  align-self: flex-start;
  margin-top: .3rem; padding: 0;
  background: none; border: 0;
  font: inherit; font-size: .82rem;
  color: var(--sw-accent);
  text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer;
}
.sw-lien-discret:hover { opacity: .8; }
.sw-lien-discret:disabled {
  color: var(--sw-doux); cursor: progress; text-decoration: none;
}

/* La caution : une information, pas une alerte. Elle est normale pour un gîte,
   et l'écrire en rouge ferait reculer un client qui s'y attendait. */
.sw-caution {
  margin: .7rem 0 0; padding: .7rem .9rem;
  background: var(--sw-fond-doux, rgba(255,255,255,.04));
  border-left: 3px solid var(--sw-accent);
  font-size: .88rem; line-height: 1.5; color: var(--sw-encre);
  max-width: 62ch;
}

/* ── Quand il n'y a rien à vendre ─────────────────────────
   Une phrase seule dans une modale vide donne l'impression d'un site cassé.
   L'écran garde donc la tenue du reste du moteur : un repère, un titre, une
   phrase, une sortie. */
.sw-vide-riche {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; padding: 2.6rem 1.5rem 2.8rem; gap: .2rem;
}
.sw-vide-marque {
  display: flex; align-items: center; justify-content: center;
  width: 64px; height: 64px; border-radius: 50%;
  background: rgba(255, 255, 255, .05);
  color: var(--sw-accent); margin-bottom: 1.1rem;
}
.sw-vide-titre {
  margin: 0; font-size: 1.15rem; font-weight: 600; color: var(--sw-encre);
  line-height: 1.3;
}
.sw-vide-texte {
  margin: .5rem 0 0; max-width: 42ch; font-size: .95rem;
  line-height: 1.55; color: var(--sw-doux);
}
.sw-vide-actions {
  display: flex; gap: .6rem; flex-wrap: wrap; justify-content: center;
  margin-top: 1.4rem;
}
.sw-vide-actions .sw-primaire { width: auto; min-width: 190px; }

/* Le code promotionnel, au récapitulatif : le champ et son bouton sur une même
   ligne, parce qu'on tape puis on valide sans changer de zone du regard. */
.sw-promo { margin: .2rem 0 .9rem; }
.sw-promo-ligne { display: flex; gap: .5rem; align-items: stretch; }
.sw-promo-ligne input { flex: 1; min-width: 0; }
/* DEUX CLASSES INVENTÉES, DEUX BOUTONS INVISIBLES.
   `.sw-bouton` et `.sw-bouton-second` n'existaient dans aucune feuille : les
   vrais boutons du moteur s'appellent `.sw-primaire` et `.sw-secondaire`.
   Résultat, le bouton « Appliquer » du code promo n'avait ni fond, ni bordure,
   et héritait d'un gris presque blanc — invisible sur fond clair. */
.sw-promo-ligne .sw-secondaire { flex: 0 0 auto; padding-inline: 1.1rem; }

/* CE QUE LE BON A PAYÉ, SOUS LE TOTAL.
   Deux lignes discrètes, alignées comme le total mais en retrait : elles ne
   contredisent pas le total, elles l'expliquent. Le client vient de lire un
   prix ; ici il apprend ce qu'il en reste à sa charge. */
.sw-apres-bon {
  margin: -.4rem 0 .8rem;
  padding: .55rem .9rem;
  background: var(--sw-carte);
  border-radius: var(--sw-radius);
  border-left: 2px solid var(--sw-ok);
}
.sw-ligne-bon {
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: .9rem; padding: .12rem 0;
  color: var(--sw-doux);
}
.sw-ligne-bon strong { color: var(--sw-encre); font-weight: 600; }
/* La dernière ligne est celle qu'on retient : ce qu'il faudra sortir au
   comptoir. Elle se lit donc en clair, pas en gris. */
.sw-ligne-bon:last-child { color: var(--sw-texte); }
.sw-ligne-bon:last-child strong { font-size: 1rem; }
