/* Motion system — layered on top of the inline #page-animations block.
   Loaded after it, so equal-specificity rules here win without !important. */
:root{
  --m-ease: cubic-bezier(.2,.7,.2,1);   /* signature curve, matches --anim-ease */
  --m-spring: cubic-bezier(.34,1.56,.64,1); /* overshoot, for hover/press only */
  --m-fast: .28s;
  --m-slow: .9s;
  --m-stagger-step: 90ms;
  --m-lift: 6px;
  --m-btn-lift: 3px;      /* hover lift — smaller than cards, buttons are denser */
  --m-btn-in: 160ms;      /* hover in */
  --m-btn-out: 90ms;      /* press — faster, so the button feels like it answers */
  --m-btn-bright: 1.08;
}

/* Staggered sibling reveals. Hidden state is gated on .js-anim (set by the
   existing inline head script) so a JS failure leaves everything visible. */
.js-anim [data-motion-stagger] > .m-stagger-child{
  opacity: 0;
  transform: translateY(18px);
}
.js-anim [data-motion-stagger].m-stagger-in > .m-stagger-child{
  animation: m-stagger-enter var(--m-slow) var(--m-ease) both;
  animation-delay: calc(var(--m-i, 0) * var(--m-stagger-step));
}
@keyframes m-stagger-enter{
  from{ opacity: 0; transform: translateY(18px); filter: blur(6px); }
  to  { opacity: 1; transform: none;             filter: blur(0); }
}
@media (prefers-reduced-motion: reduce){
  .js-anim [data-motion-stagger] > .m-stagger-child,
  .js-anim [data-motion-stagger].m-stagger-in > .m-stagger-child{
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
}

/* Nav condense: at rest the bar sits open and its backdrop is faint; once the
   page scrolls the bar tightens toward the top edge and the backdrop deepens. */
.framer-sh1dk2-container{
  transition: transform var(--m-fast) var(--m-ease);
  will-change: transform;
}
.m-scrolled .framer-sh1dk2-container{
  transform: translateY(-4px) scale(.985);
  transform-origin: 50% 0;
}
.framer-srdv3h{
  opacity: .55;
  transition: opacity var(--m-slow) var(--m-ease);
}
.m-scrolled .framer-srdv3h{
  opacity: 1;
}
@media (prefers-reduced-motion: reduce){
  .framer-sh1dk2-container,
  .m-scrolled .framer-sh1dk2-container{ transition: none !important; transform: none !important; }
  .framer-srdv3h,
  .m-scrolled .framer-srdv3h{ transition: none !important; opacity: 1 !important; }
}

/* Hero parallax: the photo drifts at ~35% of scroll speed. Scale keeps the
   frame filled while the image is offset, so no black gap appears at an edge.
   .framer-snsgll also carries an inline `transform: translateX(-50%)` baked
   into Framer's static export (its horizontal centering) on both the desktop
   and mobile copies. An inline style declaration beats an external stylesheet
   declaration for the same property regardless of selector specificity, so
   without !important this rule would never take effect at all. !important
   alone would still drop that centering, so translateX(-50%) is repeated
   here as part of the same transform so centering survives. */
.framer-snsgll{
  transform: translateX(-50%) translate3d(0, calc(var(--m-parallax, 0) * 1px), 0) scale(1.06) !important;
  will-change: transform;
}
@media (prefers-reduced-motion: reduce){
  .framer-snsgll{ transform: translateX(-50%) !important; }
}

/* Specialty description swap: fade and lift the new sentence into place so the
   text change reads at the same tempo as the tab underline. */
@keyframes m-text-swap{
  from{ opacity: 0; transform: translateY(8px); filter: blur(4px); }
  to  { opacity: 1; transform: none;            filter: blur(0); }
}
.m-swap{ animation: m-text-swap var(--m-fast) var(--m-ease) both; }
@media (prefers-reduced-motion: reduce){
  .m-swap{ animation: none !important; }
}

/* Pointer-reactive cards. --m-mx/--m-my are set by JS in the range -1..1.
   The tilt is deliberately small; past about 4deg it reads as a gimmick. */
[data-anim-hover="card"]{
  transform:
    translateY(calc(var(--m-hover, 0) * var(--m-lift) * -1))
    rotateX(calc(var(--m-my, 0) * -3deg))
    rotateY(calc(var(--m-mx, 0) * 3deg))
    !important;
  transform-style: preserve-3d;
  transition: transform var(--m-fast) var(--m-ease);
}
[data-anim-hover="card"]:hover{ --m-hover: 1; }

/* Buttons — crisp and clinical: small, fast, no overshoot.
   Hover is gated behind a real pointer so a tap on a phone never leaves a
   button stuck in its lifted state. */
[data-anim-hover="cta"]{
  transition: transform var(--m-btn-in) var(--m-ease), filter var(--m-btn-in) var(--m-ease);
}
[data-anim-hover="cta"] svg{ transition: transform var(--m-btn-in) var(--m-ease); }
@media (hover: hover) and (pointer: fine){
  [data-anim-hover="cta"]:hover{
    transform: translateY(calc(var(--m-btn-lift) * -1));
    filter: brightness(var(--m-btn-bright));
  }
  [data-anim-hover="cta"]:hover svg{ transform: translateX(4px); }
}
[data-anim-hover="cta"]:active{
  transform: scale(.985);
  transition-duration: var(--m-btn-out);
}

@media (prefers-reduced-motion: reduce){
  [data-anim-hover="card"]{ transform: none !important; transition: none !important; }
  [data-anim-hover="cta"],
  [data-anim-hover="cta"] svg{ transition: none !important; }
  [data-anim-hover="cta"]:hover,
  [data-anim-hover="cta"]:hover svg,
  [data-anim-hover="cta"]:active{ transform: none !important; filter: none !important; }
}
@media (hover: none){
  [data-anim-hover="card"]{ transform: none !important; }
}

/* Performance: promote only the elements that actually animate on scroll, and
   drop the hint again for everything else so the compositor is not flooded. */
.m-stagger-child{ will-change: opacity, transform; }
[data-motion-stagger].m-stagger-in > .m-stagger-child{ will-change: auto; }

/* Safety net: motion must never swallow a click. */
.framer-srdv3h{ pointer-events: none; }

/* The footer booking button is a Framer <div>, not a link. A stretched anchor
   inside it makes the whole button a real, no-JS, keyboard-reachable link
   without restructuring the generated markup. */
[data-framer-name="Desktop M"]{ position: relative; }
.m-btn-stretch{
  position: absolute;
  inset: 0;
  border-radius: inherit;
  text-decoration: none;
}

/* Mobile nav drawer. Framer's own open/close toggle didn't survive the static
   export (no JS ever set the "Menu Open" variant), so the hamburger did
   nothing. Framer's per-breakpoint sizing for this panel is ambiguous once
   it's driven outside its own runtime, so this defines an explicit, self-
   contained overlay instead of relying on it. Toggled by motion.js via
   .m-menu-open on <html>.
   height is an explicit calc(), not `bottom: 0` + `height: auto`: the header
   bar (.framer-sh1dk2-container) has `will-change: transform` for the scroll-
   condense effect, which makes IT the containing block for this fixed-position
   descendant instead of the viewport — `bottom: 0` would resolve against the
   header's own ~64px box and collapse the drawer to a sliver. calc(100dvh -
   64px) sidesteps that entirely since it doesn't depend on the containing
   block's size. */
/* The overlay box itself stays fixed/sized at all times, open or closed — only
   opacity/transform/pointer-events toggle. Position and size can't be
   transitioned smoothly (they don't interpolate the way opacity/transform do,
   and swapping "position: relative" <-> "fixed" outright is a hard cut with no
   in-between frame), so the box has to already be in its final place before
   the animation starts, with only the animatable properties changing. */
#view-mobile [data-framer-name="Links"]{
  display: flex !important;
  flex-direction: column !important;
  position: fixed !important;
  top: 64px !important;
  left: 0 !important;
  right: 0 !important;
  height: calc(100vh - 64px) !important;
  height: calc(100dvh - 64px) !important;
  overflow: auto !important;
  z-index: 999 !important;
  background: #000 !important;
  padding: 16px !important;
  opacity: 0 !important;
  pointer-events: none !important;
  transform: translateY(-14px) !important;
  transition: opacity var(--m-fast) var(--m-ease), transform var(--m-fast) var(--m-ease);
}
html.m-menu-open #view-mobile [data-framer-name="Links"]{
  opacity: 1 !important;
  pointer-events: auto !important;
  transform: translateY(0) !important;
}
/* Direct children fade/rise in with a stagger on open; motion.js sets
   transition-delay per child (staggered opening, simultaneous closing — see
   the comment in motion.js for why the delay isn't handled in CSS alone). */
#view-mobile [data-framer-name="Links"] > *{
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--m-fast) var(--m-ease), transform var(--m-fast) var(--m-ease);
}
html.m-menu-open #view-mobile [data-framer-name="Links"] > *{
  opacity: 1 !important;
  transform: none !important;
}
@media (prefers-reduced-motion: reduce){
  #view-mobile [data-framer-name="Links"],
  #view-mobile [data-framer-name="Links"] > *{
    transition: none !important;
  }
}

/* Framer baked a fixed 128px width plus overflow:hidden onto the first group's
   item wrappers — sized for the original short English labels. The French ones
   are wider ("Cataracte" needs 157px, "Chirurgie réfractive" 303px) and were
   being clipped mid-word once the drawer actually opened. Let them size to
   their content: the drawer is 375px wide minus 2x16px padding = 343px of room,
   so even the longest label fits on one line without wrapping. Scoped to the
   drawer so the identical classes elsewhere in the export keep Framer's sizing. */
#view-mobile [data-framer-name="Links"] .framer-1h8weuy,
#view-mobile [data-framer-name="Links"] .framer-12ursez,
#view-mobile [data-framer-name="Links"] .framer-1ty1vos{
  width: auto !important;
  max-width: 100% !important;
  overflow: visible !important;
}
/* That wrapper is a centred flex column. While every child was pinned to the
   full 128px the centring had nothing to do; once they shrink-wrap to their
   text it starts indenting the shorter label ("Cataracte" sat 73px in, out of
   line with every other menu item), so align to the start explicitly. */
#view-mobile [data-framer-name="Links"] .framer-1h8weuy{
  align-items: flex-start !important;
}

/* Hamburger -> X. Framer had already authored this exact end state as a
   variant (.framer-Q5Ezz.framer-v-guzk3q .framer-1d8v8sh{ top: calc(50% - 1.5px) })
   but nothing ever switched to that variant. Reusing its own numbers here
   instead of guessing new ones, just driven by .m-menu-open. */
#view-mobile .framer-qcfjfh .framer-awyvpq,
#view-mobile .framer-qcfjfh .framer-1d8v8sh{
  transition: transform var(--m-fast) var(--m-ease), top var(--m-fast) var(--m-ease);
}
html.m-menu-open #view-mobile .framer-qcfjfh .framer-awyvpq{
  top: calc(50% - 1.5px) !important;
  transform: rotate(45deg) !important;
}
html.m-menu-open #view-mobile .framer-qcfjfh .framer-1d8v8sh{
  top: calc(50% - 1.5px) !important;
  transform: rotate(-45deg) !important;
}
@media (prefers-reduced-motion: reduce){
  #view-mobile .framer-qcfjfh .framer-awyvpq,
  #view-mobile .framer-qcfjfh .framer-1d8v8sh{ transition: none !important; }
}
