/* =============================================================
   ICTraining - Personal coaching, Lutry
   Aesthetic: asymmetric Swiss / museum. Pure white, near-black ink,
   colour lives only in photography.
   Shape rule: border-radius 0 everywhere. Single exception: .btn-glass
   capsules overlaid on photos. No outlined boxes; hairlines (--line)
   are the only separators.
   Motion rule: content settles, it does not arrive. Transform/opacity/
   filter/clip-path only. No JS scroll listeners; IntersectionObserver
   plus CSS scroll-driven animations as progressive enhancement.
   ============================================================= */

:root {
  --paper: #ffffff;        /* page background, pure white */
  --ink: #2c292a;          /* near-black text */
  --ink-soft: #6f6f6f;     /* muted text, AA on white */
  --line: #e6e6e6;         /* hairlines */

  --r-capsule: 999px;      /* ONLY for .btn-glass; nothing else is rounded */

  --glass-bg: rgba(255, 255, 255, 0.3);
  --glass-blur: 14px;

  /* shared text CTA treatment, based on "Read the contract" */
  --cta-size: clamp(1.1rem, 1rem + 0.55vw, 1.35rem);
  --cta-line: 1.5px;
  --cta-line-height: 1.2;
  /* supporting copy follows 20% of the testimonial-name scale */
  --small-text: max(0.82rem, min(1.76vh, 16.4px));
  --small-text: max(0.82rem, min(1.76svh, 16.4px));
  /* shared photo-poster scale, based on plan-card titles and prices */
  --poster-title: min(6.6vh, 61px);
  --poster-title: min(6.6svh, 61px);

  --wordmark-h: clamp(34px, 3.2vw, 44px);  /* identity logo + section-title scale */

  --maxw: 1320px;
  --pad-x: clamp(1.1rem, 5vw, 3.25rem);
  /* Inline gutter for the full-bleed scrollers, so their first slide starts on
     the same line as .container text. Past --maxw the container is centred and
     its text gutter grows; under it the two match and this collapses to --pad-x.
     The % resolves against the track's containing block (100vw would count the
     scrollbar). Only use this on tracks whose parent spans the viewport. */
  --bleed-pad-x: max(var(--pad-x), calc((100% - var(--maxw)) / 2 + var(--pad-x)));
  --section-y: clamp(4rem, 5vw, 8rem);

  /* motion tokens */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);      /* expo-out: entrances + hovers */
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);  /* symmetric: crossfades, morphs */
  --t-tap: 120ms;
  --t-fast: 220ms;
  --t-med: 350ms;
  --t-slow: 650ms;
  --t-img: 1100ms;
  --d-1: 8px;
  --d-2: 16px;
  --s-img: 1.06;
  --blur: 8px;
}

/* --------------------------------- font --------------------------------- */
/* Questrial ships a single weight (400). Self-hosted so the page works over file://.
   The woff2 is a Latin-subset build of the ttf (4x smaller); the ttf stays as
   the archival source and legacy fallback. */
@font-face {
  font-family: "Questrial";
  src: url("Questrial-Regular.woff2") format("woff2"),
       url("Questrial-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------- reset / base --------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 84px; /* anchors land below the sticky header */
}

body {
  margin: 0;
  font-family: "Questrial", system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--ink);
  background: var(--paper);
  line-height: 1.42;
  font-size: clamp(0.94rem, 0.92rem + 0.12vw, 1rem);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { display: block; max-width: 100%; height: auto; }

a { color: inherit; text-decoration: none; }

h1, h2, h3 { margin: 0; font-weight: 400; line-height: 1.02; letter-spacing: -0.02em; }

p { margin: 0; }

ul, ol { margin: 0; padding: 0; list-style: none; }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}

#top-sentinel { position: absolute; top: 0; height: 1px; width: 1px; }

/* Visually hidden but read by search engines and screen readers. Used to give
   the image-based identity <h1> real, keyword-bearing text without altering the
   museum layout. Do not display:none it (that would hide it from crawlers too). */
.visually-hidden {
  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;
}

.section-title {
  font-size: clamp(2.1rem, 1.6rem + 2vw, 2.5rem); /* ~40px, the wordmark scale */
}

.arrow { font-style: normal; line-height: 1; }

/* --------------------------------- reveal system --------------------------------- */
/* Blocks fade + settle 16px up; images fade with a slow scale-settle inside
   their crop. script.js adds .is-visible via IntersectionObserver. */
.reveal {
  opacity: 0;
  transform: translateY(var(--d-2));
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.reveal.is-visible { opacity: 1; transform: none; }

.reveal--img {
  transform: none;            /* the frame only fades */
  overflow: hidden;
  contain: paint;
}
.reveal--img img {
  transform: scale(var(--s-img));
  transition: transform var(--t-img) var(--ease);
}
.reveal--img.is-visible img { transform: none; }

/* --------------------------------- buttons --------------------------------- */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: inherit;
  font-size: var(--cta-size);
  letter-spacing: -0.01em;
  line-height: var(--cta-line-height);
  white-space: normal;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.btn::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: var(--cta-line);
  background: currentColor;
  transform: scaleX(1);
  transform-origin: left;
  transition: transform 0.25s var(--ease);
}
.btn:hover { color: var(--ink-soft); }
.btn:hover::after { transform: scaleX(0); }
.btn--lg { font-size: var(--cta-size); }

/* Glass capsule over photos: the single rounded exception. Must stay a
   sibling of the photo (or inside a non-transforming frame), never inside
   an ancestor that animates filter/transform. */
.btn-glass {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.7rem;
  border: 0;
  border-radius: var(--r-capsule);
  overflow: hidden;
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  color: #fff;
  font: inherit;
  white-space: nowrap;
  cursor: pointer;
  transform: scale(1);
  transition: background-color var(--t-med) var(--ease), transform var(--t-med) var(--ease);
}
.btn-glass > span { position: relative; z-index: 1; }
/* one-pass shine sweep on hover */
.btn-glass::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, 0.45) 50%, transparent 60%);
  transform: translateX(-130%);
}
@media (hover: hover) {
  .btn-glass:hover { background-color: rgba(255, 255, 255, 0.45); }
  .btn-glass:hover::after {
    transform: translateX(130%);
    transition: transform 0.65s var(--ease);
  }
}
/* asymmetric press: fast in, slow spring back (declared in the base rule) */
.btn-glass:active { transform: scale(0.97); transition-duration: var(--t-tap); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .btn-glass { background: rgba(255, 255, 255, 0.9); }
}

/* --------------------------------- language switcher --------------------------------- */
.lang-switch { display: inline-flex; align-items: center; gap: 0.9rem; }
.lang-btn {
  font-family: inherit;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  line-height: 1.3;
  transition: color var(--t-fast) var(--ease);
}
.lang-btn:hover { color: var(--ink); }
.lang-btn[aria-pressed="true"] {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}

/* --------------------------------- header / nav --------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  transition: background-color 0.3s var(--ease);
}
/* the blur is NOT transitioned (Safari flickers); the bg fade masks it */
.site-header[data-elevated="true"] {
  background: rgba(255, 255, 255, 0.78);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  backdrop-filter: blur(12px) saturate(140%);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header[data-elevated="true"] { background: rgba(255, 255, 255, 0.94); }
}

.site-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 72px;
}

/* explicit columns: the nav is display:none on mobile and would otherwise
   stop occupying column 1, sliding the logo off-center */
.site-header__logo { grid-column: 2; justify-self: center; display: inline-flex; }
.site-header__logo img {
  height: 26px;
  width: auto;
  transition: transform var(--t-fast) var(--ease);
}
.site-header__logo:hover img { transform: scale(1.06); }

.nav {
  display: none; /* desktop only, see media query */
  grid-column: 1;
  gap: clamp(1rem, 2.4vw, 2.2rem);
  justify-self: start;
}
.nav a {
  position: relative;
  font-size: 0.96rem;
  color: var(--ink-soft);
  padding-bottom: 2px;
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease);
}
/* underline enters from the left, exits the way it was travelling */
.nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 2px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.25s var(--ease);
}
.nav a:hover { color: var(--ink); }
.nav a:hover::after { transform: scaleX(1); transform-origin: left; }

.site-header__end {
  grid-column: 3;
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: 1rem;
}
.site-header__end .lang-switch { display: none; } /* desktop only */

/* 3-bar toggle morphing to an X (bar pitch = 5px gap + 1.5px bar = 6.5px) */
.nav-toggle {
  display: grid;
  gap: 5px;
  justify-items: center;
  align-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}
.nav-toggle span {
  width: 22px;
  height: 1.5px;
  background: var(--ink);
  transition: translate 0.3s var(--ease-io), rotate 0.3s var(--ease-io),
              scale 0.2s var(--ease-io), opacity 0.2s linear;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { translate: 0 6.5px; rotate: 45deg; }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; scale: 0.4 1; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { translate: 0 -6.5px; rotate: -45deg; }

/* mobile menu: white panel under the header bar; children stagger in on
   open (inline --i indexes), close is one quick fade with no stagger */
.mobile-nav {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  min-height: calc(100vh - 72px);
  min-height: calc(100dvh - 72px);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1.25rem var(--pad-x) 2.5rem;
  background: var(--paper);
  overscroll-behavior: contain;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-fast) var(--ease-io), visibility 0s var(--t-fast);
}
.mobile-nav.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--t-fast) var(--ease), visibility 0s;
}
.mobile-nav > * {
  opacity: 0;
  translate: 0 14px;
  transition: opacity var(--t-med) var(--ease), translate 0.45s var(--ease);
}
.mobile-nav.is-open > * {
  opacity: 1;
  translate: 0 0;
  transition-delay: calc(60ms + var(--i, 0) * 45ms);
}
.mobile-nav a:not(.btn) {
  padding: 0.85rem 0;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  border-bottom: 1px solid var(--line);
}
.mobile-nav .lang-switch { margin-top: 1.25rem; }
.mobile-nav .btn { margin-top: 1.25rem; justify-content: center; }

/* --------------------------------- hero --------------------------------- */
.hero { position: relative; }
.hero__media {
  margin: 0;
  height: min(74vh, 780px);
  height: min(74svh, 780px);
  position: relative;
}
.hero__media picture { display: block; height: 100%; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
@media (max-width: 767px) {
  .hero__media,
  .hero__media picture,
  .hero__media img { height: auto; }
}
@media (min-width: 768px) {
  .hero__media,
  .hero__media picture,
  .hero__media img { height: auto; }
}
/* legibility scrim, bottom half: taller title + CTA sit higher on the photo */
.hero__media::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 52%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.42), transparent);
  pointer-events: none;
}
.hero__overlay {
  position: absolute;
  left: var(--pad-x);
  right: var(--pad-x);
  bottom: clamp(1.5rem, 4vw, 3rem);
}
.hero__kicker {
  color: #fff;
  font-size: var(--poster-title);
  line-height: 0.92;
  max-width: 13ch;
  letter-spacing: -0.01em;
}
/* underlined text CTA on the photo; hover is a flat tone shift, no box.
   The underline mirrors the nav: visible at rest, hides toward the left
   on hover (the nav's line exits toward the right). */
.hero__cta {
  position: relative;
  display: inline-block;
  margin-top: clamp(2rem, 6vw, 3.5rem);
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  font: inherit;
  font-size: var(--cta-size);
  line-height: var(--cta-line-height);
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.hero__cta::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: var(--cta-line);
  background: currentColor;
  transform: scaleX(1);
  transform-origin: left;
  transition: transform 0.25s var(--ease);
}
.hero__cta:hover { color: rgba(255, 255, 255, 0.75); }
.hero__cta:hover::after { transform: scaleX(0); }

/* --------------------------------- identity --------------------------------- */
/* Keep the identity visually attached to the hero, then leave enough room below
   for the wordmark to introduce the gallery. */
.identity { padding-block: clamp(1.75rem, 4vw, 2.75rem); }
.identity__title { display: flex; justify-content: flex-start; }
/* signature entrance: the wordmark wipes in from the right edge it hangs on */
.identity__wordmark.reveal {
  height: var(--wordmark-h);
  width: auto;
  opacity: 1;
  transform: none;
  clip-path: inset(0 -2% 0 100%);
}
.identity__wordmark.reveal.is-visible { clip-path: inset(0 -2% 0 -2%); }

/* --------------------------------- gallery --------------------------------- */
.gallery { 
  padding-block: 0 var(--section-y) ; 
  padding-bottom: clamp(1.75rem, 4vw, 2.5rem);
}

.gallery__track {
  display: flex;
  align-items: center;
  justify-content: safe center;     /* centers when nothing overflows */
  gap: clamp(0.225rem, 0.625vw, 0.5rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scroll-padding-inline: var(--bleed-pad-x);
  padding-inline: var(--bleed-pad-x);
  scrollbar-width: none;
}
.gallery__track::-webkit-scrollbar { display: none; }
.gallery__item {
  flex: none;
  margin: 0;
  scroll-snap-align: start;
}
/* height-driven like the testimonial photos, with one consistent photo height */
.gallery__item img {
  width: auto;
  height: min(56vh, 520px);
  height: min(56svh, 520px);
}

/* subtle per-image drift while the strip scrolls: CSS-only, gated twice */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view(inline)) {
    .gallery__item img {
      scale: 1.12; /* bleed so the +-5% drift never exposes an edge */
      animation: gallery-drift linear both;
      animation-timeline: view(inline);
      animation-range: cover 0% cover 100%;
    }
    @keyframes gallery-drift {
      from { translate: 5% 0; }
      to   { translate: -5% 0; }
    }
  }
}

/* --------------------------------- statement --------------------------------- */
.statement { padding-block: 0 var(--section-y); }
.statement__body {
  margin-left: 0;
  max-width: 45ch;
  text-align: left;
  font-size: clamp(1.1rem, 1rem + 0.55vw, 1.35rem);
  line-height: 1.32;
  letter-spacing: -0.01em;
}

/* --------------------------------- témoignages --------------------------------- */
.temoins { padding-block: 0 var(--section-y); }
.temoins .section-title { margin-bottom: clamp(1.75rem, 4vw, 2.75rem); }

.temoins__track {
  display: flex;
  justify-content: safe center;     /* centers when nothing overflows */
  gap: clamp(0.225rem, 0.5vw, 0.375rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scroll-padding-inline: var(--bleed-pad-x);
  padding-inline: var(--bleed-pad-x);
  scrollbar-width: none;
}
.temoins__track::-webkit-scrollbar { display: none; }

.temoin {
  position: relative;
  flex: none;
  width: auto;                /* shrink-wraps the height-capped photo */
  margin: 0;
  scroll-snap-align: center;
  scroll-snap-stop: always;   /* a flick never skips the middle slide */
  cursor: pointer;            /* clicking a slide activates its review */
}
/* height-driven so the photo leaves ~1/3 of the screen to the review below */
.temoin img {
  height: min(56vh, 520px);
  height: min(56svh, 520px);
  width: auto;
}
/* soft scrim so the white caption reads on any photo */
.temoin::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 60%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.35), transparent);
  pointer-events: none;
}
/* poster caption, matched to the reference layouts: a huge name that nearly
   spans the photo, right-anchored, with the quote hanging directly under it
   as a left-aligned block ending on the same right margin. The photos are
   height-driven (svh), so the type scales with them. */
.temoin__caption {
  --cap: var(--poster-title);
  position: absolute;
  left: 4%;
  right: 4%;
  bottom: 24%;                      /* identical position on every slide, as in the reference posters */
  z-index: 1;
  display: grid;
  gap: 0;                           /* the quote hugs the name */
  justify-items: end;
  color: #fff;
  opacity: 0.35;
  transform: translateY(var(--d-1));
  transition: opacity var(--t-med) var(--ease), transform var(--t-slow) var(--ease);
}
.temoin.is-active .temoin__caption { opacity: 1; transform: none; }
.temoin__name {
  font-size: var(--cap);
  line-height: 0.92;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
/* line breaks are hand-set in the i18n strings (white-space: pre-line).
   The box hangs from its right anchor (the longest line ends there, see the
   per-client offsets below) while the lines inside read left-aligned,
   ragged right, like the reference posters. */
.temoin__quote {
  font-size: var(--small-text);
  max-width: 100%;
  margin-top: calc(var(--cap) * -0.03);  /* tucks into the name's descender space */
  white-space: pre-line;
  line-height: 1.06;
  text-align: left;
}
/* French guillemets around the short quote, kept out of the i18n strings */
.temoin__quote::before { content: "\00AB\00A0"; }
.temoin__quote::after { content: "\00A0\00BB"; }

/* per-client caption adjustments (positioning tweaks live here):
   the quote's right edge ends on the second m of Sammy (before the y);
   Anna and Julien end on their last letter, so they need no offset */
.temoin[data-temoin="sammy"] .temoin__quote {
  padding-right: calc(var(--cap) * 0.52);
}
/* Julien's quote wraps within the width of "Julien" itself (~2.6em of the
   name size), so it never sticks out left of the name; natural wrapping
   replaces the hand-set line breaks at this narrow width */
.temoin[data-temoin="julien"] .temoin__quote {
  max-width: calc(var(--cap) * 2.6);
  white-space: normal;
}

/* Only the active long review reserves height, so the section rhythm follows
   the visible text. Inactive reviews are overlaid for the crossfade. */
.temoins__reviews {
  position: relative;
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
}
.temoin-review {
  margin: 0;
  margin-left: 0;
  width: min(100%, 52ch);
  text-align: left;
  opacity: 0;
  filter: blur(var(--blur));
  visibility: hidden;
  transition: opacity var(--t-fast) var(--ease-io),
              filter var(--t-fast) var(--ease-io),
              visibility 0s var(--t-fast);
}
.temoin-review:not(.is-active) {
  position: absolute;
  top: 0;
  right: 0;
  pointer-events: none;
}
/* enter delayed 160ms: the old text is mostly gone before the new arrives,
   so the swap reads as one continuous dissolve */
.temoin-review.is-active {
  position: relative;
  opacity: 1;
  filter: blur(0);
  visibility: visible;
  transition: opacity var(--t-med) var(--ease) 160ms,
              filter var(--t-med) var(--ease) 160ms,
              visibility 0s 160ms;
}
/* reviews read at the statement scale */
.temoin-review p {
  margin-bottom: 1.1rem;
  font-size: clamp(1.1rem, 1rem + 0.55vw, 1.35rem);
  line-height: 1.32;
  letter-spacing: -0.01em;
}
.temoin-review p:last-child { margin-bottom: 0; }

/* every review shows at most 6 lines, so the three stacked reviews share
   the same height and no dead space opens up before the services section.
   6 (not 5) so Sammy's short real quote fits in full across FR/EN/ES at the
   52ch column width; longer text comes back via the read-more controls. */
.temoin-review > p {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  line-clamp: 6;
  overflow: hidden;
}
.temoin-review.is-expanded > p {
  display: block;
  -webkit-line-clamp: none;
  line-clamp: none;
  overflow: visible;
}

/* Anna's long review: first paragraph is the preview, the rest expands */
.temoin-review__extra {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-med) var(--ease);
}
.temoin-review__extra > div { overflow: hidden; min-height: 0; }
.temoin-review__extra p {
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.temoin-review.is-expanded .temoin-review__extra { grid-template-rows: 1fr; }
.temoin-review.is-expanded .temoin-review__extra p {
  opacity: 1;
  transition-delay: 120ms;
}
.temoin-review__more {
  display: flex;
  width: fit-content;
  margin-top: clamp(0.5rem, 1vw, 0.75rem);
  margin-left: 0;
  text-align: left;
}

/* --------------------------------- services --------------------------------- */
.services { padding-block: 0 clamp(1.75rem, 4vw, 2.5rem); }
.services__list {
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--line);
}
.service-row {
  position: relative;
  display: grid;
  gap: 0.5rem;
  padding-block: 1.35rem;
  transition: opacity var(--t-fast) var(--ease);
}
/* hairline draws in with the row */
.service-row::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease) 0.15s;
}
.service-row.is-visible::before { transform: scaleX(1); }
.service-row__name { font-size: var(--cta-size); }
.service-row__desc {
  color: var(--ink-soft);
  max-width: 46ch;
  font-size: var(--small-text);
}
/* editorial dimming: hovering the list spotlights one row */
@media (hover: hover) {
  .services__list:hover .service-row { opacity: 0.35; }
  .services__list:hover .service-row:hover { opacity: 1; }
}

/* --------------------------------- app --------------------------------- */
.app {
  padding-block: 0 var(--section-y);
  display: grid;
  gap: clamp(1.25rem, 3vw, 2rem);
}
.app__media {
  position: relative;
  margin: 0;
  aspect-ratio: 2 / 3;
  overflow: hidden;
}
.app__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.app__name {
  position: absolute;
  z-index: 1;
  top: clamp(1.25rem, 5vw, 3rem);
  right: clamp(1rem, 4vw, 2.5rem);
  width: clamp(9rem, 38vw, 14rem);
}
.app__name img {
  width: 100%;
  height: auto;
}
.app__contract {
  position: absolute;
  z-index: 1;
  right: clamp(1.25rem, 4vw, 2.5rem);
  bottom: clamp(1.25rem, 4vw, 2.5rem);
  display: inline-block;
  padding: 0;
  color: #fff;
  font-size: var(--cta-size);
  line-height: var(--cta-line-height);
  letter-spacing: -0.01em;
  transition: opacity var(--t-fast) var(--ease);
}
.app__contract::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: var(--cta-line);
  background: currentColor;
  transform: scaleX(1);
  transform-origin: left;
  transition: transform 0.25s var(--ease);
}
@media (hover: hover) {
  .app__contract:hover { opacity: 0.7; }
  .app__contract:hover::after { transform: scaleX(0); }
}
.app__body {
  max-width: 52ch;
  font-size: clamp(1.1rem, 1rem + 0.55vw, 1.35rem);
  line-height: 1.32;
  letter-spacing: -0.01em;
}

/* --------------------------------- certificats --------------------------------- */
.certs { padding-block: 0 var(--section-y); }
.certs__list {
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--line);
}
.cert-row {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem;
  padding-block: 1.25rem;
}
.cert-row::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease) 0.15s;
}
.cert-row.is-visible::before { transform: scaleX(1); }
.cert-row__title { font-size: var(--cta-size); }
.cert-row__meta {
  color: var(--ink-soft);
  font-size: var(--small-text);
  text-align: left;
  flex: none;
}
.cert-row__link {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
}
.cert-row__link:hover { text-decoration: underline; text-underline-offset: 3px; }
.cert-row__link .arrow { font-size: 0.78em; transition: transform var(--t-fast) var(--ease); }
.cert-row__link:hover .arrow { transform: translate(2px, -2px); }

/* --------------------------------- séance découverte --------------------------------- */
.free {
  padding-block: 0 var(--section-y);
  display: grid;
  gap: 0;
}
.free > .section-title {
  max-width: 16ch;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}
.free__media {
  position: relative;
  margin: 0;
  aspect-ratio: 4160 / 5335;
  overflow: hidden;
}
.free__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
/* bottom scrim so the white overlay CTA reads on the photo */
.free__media::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 46%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.5), transparent);
  pointer-events: none;
}
/* booking CTA on the photo, bottom-right, underlined like the hero CTA
   (the section's black button was removed). z-index clears the scrim. */
.free__cta {
  position: absolute;
  z-index: 1;
  right: clamp(1rem, 3.5vw, 2rem);
  bottom: clamp(1rem, 3.5vw, 2rem);
  display: inline-block;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  font: inherit;
  font-size: var(--cta-size);
  line-height: var(--cta-line-height);
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.free__cta::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: var(--cta-line);
  background: currentColor;
  transform: scaleX(1);
  transform-origin: left;
  transition: transform 0.25s var(--ease);
}
.free__cta:hover { color: rgba(255, 255, 255, 0.75); }
.free__cta:hover::after { transform: scaleX(0); }

/* Phone: the single feature photos (discovery + app) bleed to the screen
   edges. Negative inline margin = pad-x pulls them out of the container
   padding; desktop resets this (the two-column layout keeps them capped). */
.free__media, .app__media { margin-inline: calc(var(--pad-x) * -1); }
.free__steps {
  display: grid;
  gap: 1.5rem;
  margin-top: clamp(1.25rem, 3vw, 2rem);
}
.free-step {
  display: block;
}
.free-step__title {
  font-size: clamp(1.1rem, 1rem + 0.55vw, 1.35rem);
  line-height: 1.32;
  letter-spacing: -0.01em;
}
.free-step p {
  color: var(--ink-soft);
  max-width: 46ch;
  font-size: var(--small-text);
  line-height: 1.42;
  margin-top: 0.5rem;
}

/* --------------------------------- tarifs --------------------------------- */
/* Poster carousel: same machinery and geometry as the témoignages. Each card
   is a photo with the pack name + tagline top-left and the price block
   lower-right (anchored like the temoin captions, bottom 24%). Name and
   price share --cap-p, ~12% of the card height, the reference poster scale;
   long names bleed off the right edge, clipped by the reveal frame, as in
   the reference posters. */
.pricing { padding-block: 0 var(--section-y); }
.pricing .section-title { margin-bottom: clamp(1.75rem, 4vw, 2.75rem); }

/* two rows: mensuel first, then the packs */
.plan-group + .plan-group { margin-top: clamp(2.5rem, 6vw, 4rem); }
.plan-group__title {
  font-size: var(--small-text);
  color: var(--ink-soft);
  letter-spacing: 0.04em;
  margin-bottom: clamp(0.9rem, 2vw, 1.25rem);
}

.plans__track {
  display: flex;
  justify-content: safe center;     /* centers when nothing overflows */
  gap: clamp(0.225rem, 0.5vw, 0.375rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scroll-padding-inline: var(--pad-x);
  padding-inline: var(--pad-x);
  scrollbar-width: none;
}
.plans__track::-webkit-scrollbar { display: none; }

.plan-card {
  position: relative;
  flex: none;
  width: auto;                /* shrink-wraps the height-capped photo */
  margin: 0;
  scroll-snap-align: center;
  scroll-snap-stop: always;   /* a flick never skips a card */
  cursor: pointer;            /* clicking a card activates its description */
}
.plan-card img {
  height: min(56vh, 520px);
  height: min(56svh, 520px);
  width: auto;
}
/* scrims both ends: the name reads at the top, the price at the bottom */
.plan-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 42%;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.38), transparent);
  pointer-events: none;
}
.plan-card::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 60%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.35), transparent);
  pointer-events: none;
}
/* the whole caption dims on inactive cards, like the temoin captions */
.plan-card__caption {
  --cap-p: var(--poster-title);
  position: absolute;
  inset: 0;
  z-index: 1;
  color: #fff;
  opacity: 0.35;
  transform: translateY(var(--d-1));
  transition: opacity var(--t-med) var(--ease), transform var(--t-slow) var(--ease);
}
.plan-card.is-active .plan-card__caption { opacity: 1; transform: none; }
.plan-card__head {
  position: absolute;
  top: 4.5%;
  left: 4%;
  right: 0;                   /* no right inset: long names bleed like the posters */
}
.plan-card__name {
  display: block;
  font-size: var(--cap-p);
  line-height: 1;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
/* hand-set line breaks in the i18n strings (white-space: pre-line) */
.plan-card__tag {
  display: block;
  margin-top: calc(var(--cap-p) * 0.14);
  font-size: var(--small-text);
  line-height: 1.15;
  white-space: pre-line;
}
/* price block: right-aligned, with an underline that reaches the photo edge */
.plan-card__pricing {
  position: absolute;
  left: 4%;
  right: 0;
  bottom: 24%;
  display: grid;
  justify-items: end;
}
.plan-card__amount {
  margin-right: 4%;
  font-size: var(--cap-p);
  line-height: 0.92;
  letter-spacing: -0.01em;
}
.plan-card__rule {
  width: 52%;
  height: 3px;
  margin-top: calc(var(--cap-p) * 0.07);
  background: currentColor;
}

/* All descriptions share one grid cell, so the longest one reserves the
   height and the CTA stays fixed across languages and viewport widths. */
.plans__descs {
  position: relative;
  display: grid;
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
}
.plan-desc {
  grid-area: 1 / 1;
  margin-left: 0;
  width: min(100%, 52ch);
  text-align: left;
  opacity: 0;
  filter: blur(var(--blur));
  visibility: hidden;
  transition: opacity var(--t-fast) var(--ease-io),
              filter var(--t-fast) var(--ease-io),
              visibility 0s var(--t-fast);
}
.plan-desc:not(.is-active) {
  pointer-events: none;
}
/* enter delayed 160ms so the swap reads as one continuous dissolve */
.plan-desc.is-active {
  opacity: 1;
  filter: blur(0);
  visibility: visible;
  transition: opacity var(--t-med) var(--ease) 160ms,
              filter var(--t-med) var(--ease) 160ms,
              visibility 0s 160ms;
}
.plan-desc p {
  font-size: clamp(1.1rem, 1rem + 0.55vw, 1.35rem);
  line-height: 1.32;
  letter-spacing: -0.01em;
}

.plans__cta {
  display: flex;
  justify-content: flex-start;
  margin-top: clamp(0.5rem, 1vw, 0.75rem);
}
/* the label carries the active pack name, so it must be allowed to wrap */
.plan-cta { white-space: normal; text-align: left; }
/* script.js restarts this animation when the active pack changes */
.plan-cta__label.is-swapping { animation: cta-label-in var(--t-med) var(--ease); }
@keyframes cta-label-in {
  from { opacity: 0; filter: blur(4px); }
}

/* --------------------------------- remboursement --------------------------------- */
/* left-aligned statement: a prominent headline over the refund body, per the
   reference. (The statement and reviews still hang right; this one leads left.) */
.refund { padding-block: 0 var(--section-y); }
.refund .section-title {
  text-align: left;
  font-size: clamp(2.1rem, 1.6rem + 2vw, 2.5rem);
  letter-spacing: -0.02em;
  max-width: 15ch;
}
.refund__body {
  margin-top: 1.5rem;
  max-width: 42ch;
  text-align: left;
  color: var(--ink);
  font-size: var(--cta-size);
  line-height: 1.32;
}

/* --------------------------------- faq --------------------------------- */
.faq { padding-block: 0 var(--section-y); }
.faq__head { margin-bottom: clamp(1.75rem, 4vw, 2.75rem); }
.faq__list { border-top: 1px solid var(--line); max-width: 860px; }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.35rem 0;
  cursor: pointer;
  list-style: none;
  font-size: var(--cta-size);
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__chevron {
  width: 9px; height: 9px;
  flex: none;
  border-right: 1.5px solid var(--ink);
  border-bottom: 1.5px solid var(--ink);
  transform: rotate(45deg);
  transition: transform var(--t-fast) var(--ease-io);
}
.faq__item[open] .faq__chevron { transform: rotate(-135deg); }
.faq__answer {
  padding: 0 0 1.5rem;
  color: var(--ink-soft);
  max-width: 72ch;
  font-size: var(--small-text);
  animation: faq-in var(--t-med) var(--ease);
}
@keyframes faq-in {
  from { opacity: 0; transform: translateY(-4px); }
}
/* Chromium: real height glide, no JS, no max-height hack */
@supports (interpolate-size: allow-keywords) {
  .faq__item { interpolate-size: allow-keywords; }
  .faq__item::details-content {
    block-size: 0;
    overflow: clip;
    transition: block-size var(--t-med) var(--ease),
                content-visibility var(--t-med) allow-discrete;
  }
  .faq__item[open]::details-content { block-size: auto; }
}

/* --------------------------------- closing cta --------------------------------- */
.closing { padding-block: 0 var(--section-y); }
.closing__inner { text-align: left; max-width: 720px; margin-inline: 0; }
.closing__title { font-size: clamp(2.1rem, 1.5rem + 3vw, 3.2rem); }
.closing__body {
  color: var(--ink-soft);
  margin: 1.25rem 0 0.75rem;
  max-width: 48ch;
  font-size: var(--cta-size);
  line-height: 1.32;
}
.closing__inner .btn { display: flex; width: fit-content; margin-left: 0; text-align: left; }

/* --------------------------------- footer --------------------------------- */
.site-footer {
  background: #000;
  color: #fff;
  font-size: var(--cta-size);
  line-height: 1.32;
  letter-spacing: -0.01em;
}
.site-footer__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-top: clamp(3.25rem, 7vw, 6rem);
  padding-bottom: clamp(2.25rem, 5vw, 4rem);
}
.site-footer__logo { display: block; width: min(100%, 300px); }
.site-footer__logo img { width: 100%; height: auto; filter: invert(1); }
.site-footer :focus-visible { outline-color: #fff; }
.site-footer__details {
  margin-top: clamp(3rem, 6vw, 4.5rem);
}
.site-footer__address {
  font-style: normal;
}
.site-footer__address,
.site-footer__hours { white-space: pre-line; }
.site-footer__contact,
.site-footer__hours { margin-top: 2rem; }
.site-footer__contact { display: flex; flex-direction: column; align-items: flex-start; }
.site-footer__contact a { transition: color var(--t-fast) var(--ease); }
.site-footer__contact a:hover { color: rgba(255, 255, 255, 0.68); }
.site-footer__nav {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.2rem;
  margin-top: clamp(3rem, 6vw, 4.5rem);
  line-height: 1.32;
}
.site-footer__nav a {
  display: inline-flex;
  align-items: baseline;
  gap: 0.55rem;
  transition: color var(--t-fast) var(--ease);
}
.site-footer__nav a:hover { color: rgba(255, 255, 255, 0.68); }
.site-footer__bottom {
  display: flex;
  justify-content: center;
  padding-block: 1rem;
  font-size: var(--small-text);
  color: rgba(255, 255, 255, 0.68);
  text-align: center;
}

/* --------------------------------- booking modal (native <dialog>) --------------------------------- */
.booking-modal {
  width: min(880px, 94vw);
  max-width: 94vw;
  max-height: 90vh;
  padding: 0;
  border: none;
  background: var(--paper);
  color: var(--ink);
  overflow: hidden;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.28);
}
.booking-modal[open] { display: flex; flex-direction: column; }
.booking-modal::backdrop {
  background: rgba(19, 19, 19, 0.55);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.booking-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex: none;
  padding: 1.05rem 1.25rem;
  border-bottom: 1px solid var(--line);
}
.booking-modal__title { font-size: 1.1rem; }
.booking-modal__close {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  flex: none;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.booking-modal__close:hover { background: color-mix(in srgb, var(--ink) 5%, var(--paper)); }
.booking-modal__close:active { transform: translateY(1px); }
.booking-modal__body {
  position: relative;
  /* The embed reports its own height (see script.js), so the desktop panel grows
     to fit each step exactly: no inner scrollbar, no dead space. min-height just
     reserves room for the loading overlay before the first resize message. */
  flex: 1 1 auto;
  min-height: 420px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.booking-modal__loading {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 1.5rem;
  color: var(--ink-soft);
  text-align: center;
}
/* `hidden` must win over the display rule above, so JS can dismiss the overlay
   once the booking iframe has loaded. */
.booking-modal__loading[hidden] { display: none; }
.booking-modal__iframe {
  display: block;
  width: 100%;
  border: 0;
}

/* open/close choreography: open is CSS-only; close adds .is-closing from JS
   (animatedClose) and waits for the keyframe before dialog.close() */
@media (prefers-reduced-motion: no-preference) {
  .booking-modal[open] { animation: dlg-in var(--t-med) var(--ease); }
  .booking-modal[open]::backdrop { animation: bd-in var(--t-med) linear; }
  .booking-modal.is-closing { animation: dlg-out 180ms var(--ease-io) forwards; }
  .booking-modal.is-closing::backdrop { animation: bd-out 180ms linear forwards; }
  @keyframes dlg-in {
    from { opacity: 0; transform: translateY(10px) scale(0.985); }
  }
  @keyframes dlg-out {
    to { opacity: 0; transform: translateY(6px) scale(0.99); }
  }
  @keyframes bd-in { from { opacity: 0; } }
  @keyframes bd-out { to { opacity: 0; } }
}

/* =============================================================
   Responsive: desktop layer
   ============================================================= */
@media (min-width: 981px) {
  :root {
    --small-text: max(0.82rem, min(2.12vh, 21.2px));
    --small-text: max(0.82rem, min(2.12svh, 21.2px));
    --poster-title: min(7.8vh, 78px);
    --poster-title: min(7.8svh, 78px);
  }

  .nav a,
  .site-header__end .lang-btn { font-size: var(--small-text); }

  .nav { display: flex; }
  .site-header__end .lang-switch { display: inline-flex; }
  .nav-toggle { display: none; }
  .mobile-nav { display: none; }

  .site-footer__inner {
    display: grid;
    grid-template-columns: minmax(260px, 1.05fr) minmax(260px, 0.95fr) minmax(260px, 1fr);
    align-items: start;
    column-gap: clamp(3rem, 7vw, 7rem);
  }
  .site-footer__logo { width: min(100%, 300px); }
  .site-footer__details,
  .site-footer__nav { margin-top: 0; }

  .hero__media { height: auto; }
  .hero__overlay { bottom: clamp(12rem, 15vw, 18rem); }
  .hero__cta { margin-top: 1.25rem; }
  .hero__kicker {
    font-size: var(--poster-title);
    max-width: 13ch;
  }

  .gallery__item img {
    height: min(66vh, 660px);
    height: min(66svh, 660px);
  }

  .temoin img {
    height: min(66vh, 660px);
    height: min(66svh, 660px);
  }
  .temoin__caption { --cap: var(--poster-title); }

  .service-row {
    grid-template-columns: 1fr minmax(0, 46ch);
    column-gap: 2rem;
    align-items: baseline;
  }
  .service-row__desc { justify-self: start; text-align: left; }

  .app {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    gap: clamp(2rem, 5vw, 5rem);
    align-items: start;
  }
  .app__media { max-width: 520px; margin-inline: 0; }
  .app__copy { text-align: left; }
  .app__body { margin-left: 0; max-width: 52ch; }

  .free {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    align-items: start;
    column-gap: clamp(2rem, 5vw, 5rem);
  }
  .free > .section-title { grid-column: 1 / -1; }
  .free__media { max-width: 560px; margin-inline: 0; }
  .free__steps { margin-top: 0; }

  .plan-card img {
    height: min(66vh, 660px);
    height: min(66svh, 660px);
  }
  .plan-card__caption { --cap-p: var(--poster-title); }
}

/* fine-tuning on small phones */
@media (max-width: 600px) {
  :root { --section-y: clamp(3.5rem, 14vw, 5rem); }

  .site-footer__logo { width: min(82%, 270px); }

  /* Phone: full-screen sheet. The head stays a thin bar; the body fills all
     remaining width and height beneath it. */
  .booking-modal {
    width: 100vw;
    max-width: 100vw;
    height: 100vh;
    height: 100dvh;
    max-height: 100dvh;
  }
  .booking-modal__body {
    flex: 1 1 auto;
    min-height: 0;
  }
  /* The phone sheet is full-screen, so the iframe fills it regardless of the
     pixel height script.js sets for the desktop panel. */
  .booking-modal__iframe { height: 100% !important; }
}

/* =============================================================
   Reduced motion: collapse everything to instant / static.
   States are class-driven final values, so every interaction still
   works, it only stops animating. JS never waits on animation events
   without a timeout (see script.js).
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
  .reveal { opacity: 1; transform: none; }
  .reveal--img img { transform: none; }
  .identity__wordmark.reveal { clip-path: none; }
  .service-row::before, .cert-row::before { transform: none; }
  .temoin__caption { opacity: 1; transform: none; }
  .plan-card__caption { opacity: 1; transform: none; }
  .mobile-nav > * { opacity: 1; translate: none; }
}
