/* =========================================================
   Homepage — Clinica Joelle content in Stockie's layout language, painted in
   the clinic's own palette (gold #e6bc56, navy #232e51, near-black #0b0100)
   and set in Objective. Tokens come from the child style.css; colours here are
   written against those so the palette is changed in one place.
   Loads after css/brand.css.
   ========================================================= */

.joelle-home { overflow: hidden; }

.jh-section { padding: 100px 0; }

.jh-label {
  display: inline-block;
  margin-bottom: 14px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--primary-deep);
}

.jh-heading-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  margin-bottom: 48px;
}
.jh-heading-row h2 { margin: 0 0 12px; }
.jh-heading-row p { max-width: 560px; margin: 0; color: var(--muted); }
.jh-heading-row .btn { flex: 0 0 auto; }

.jh-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }

/* ---- Hero -------------------------------------------------------------
   The clinic's own finished banner: photograph on the left, logo and "We
   guide, you shine" set into the light panel on the right. The text is part
   of the artwork, so nothing is laid over it except the two buttons — see
   the note in front-page.php.

   Full-bleed, as on clinicajoelle.com.
   --------------------------------------------------------------------- */
.jh-hero {
  position: relative;
  /* Letterboxing colour, sampled from the banner's own light panel, so any
     sliver beside the image reads as part of it. It also fills the strip the
     padding below reserves. */
  background: #f1f0ee;
  /* Stockie's header is position:absolute over the page with a transparent
     background, so without this the banner runs underneath it and the nav
     sits on the artwork. Reserve exactly the header's height instead:
     .header-wrap is 100px and .site-header adds a 1px bottom border. The two
     breakpoints below are Stockie's own, where that bar shrinks. */
  padding-top: 101px;
}
@media (max-width: 1024px) { .jh-hero { padding-top: 91px; } }
@media (max-width: 768px)  { .jh-hero { padding-top: 81px; } }
/* The containing block for the buttons, so their offsets are measured
   against the artwork and not against the hero's header strip. */
.jh-hero-media { position: relative; }
.jh-hero-media img {
  display: block;
  width: 100%;
  /* The file's own ratio at every width. The banner is a composition — the
     logo and the motto are pixels in it — so cropping it would cut the
     wording off rather than just trim some background. */
  aspect-ratio: 1600 / 481;
  object-fit: cover;
  object-position: center;
}
/* The right-hand panel of the banner. The artwork's own lettering has been
   painted out of the JPEG — that side is flat grey now — and the words are
   set here as live text instead: it scales, it can be changed without a new
   export, and it can be read by search engines and screen readers.

   Percentages of the photograph, so the block tracks the panel at any
   width. The panel starts about 56% across and the old lettering ran from
   59% to 92%, which is the room there is. */
/* A single column: the wordmark, the motto under it, EGYPT signing it off
   between two rules. */
.jh-hero-panel {
  position: absolute;
  left: 54%;
  right: 4%;
  top: 9%;
  bottom: 23%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2%;
  text-align: center;
  pointer-events: none;
}
.jh-hero-line {
  display: block;
  width: 100%;
  /* The deeper gold of the original lettering, not the brand's flat one. */
  color: #c79a34;
}
.jh-hero-wordmark { width: 58%; }
/* One line per word, stacked, with the logo's own proportions: JOELLE is
   46% of CLINICA's width and sits a quarter of a cap height below it,
   because that is what it measures in the artwork. Nothing here is a type
   size — the letters are outlines taken out of the .ai file, so each word
   simply fills the box it is given.

   One path per letter inside, in case a line ever wants a stagger. */
.jh-wm-line { display: block; }
.jh-wm-clinica { width: 100%; }
.jh-wm-joelle { width: 46.1%; margin: 4.2% auto 0; }
.jh-wm-svg { display: block; width: 100%; height: auto; }
/* --wm-fill is set on each svg and points at its own gradient, sampled off
   the logo so the two words keep the ramp they really have — CLINICA
   bright at both ends, JOELLE the duller gold it is in the file. */
.jh-wm-svg path { fill: var(--wm-fill, currentColor); }


/* Text_Slide: the line fades up from a little below where it belongs.
   --line is 0 for CLINICA and 1 for JOELLE, so the second follows the
   first rather than arriving with it. EGYPT sets --rise-delay instead,
   because it waits for the motto to finish writing. */
.jh-fx [data-rise] {
  opacity: 0;
  transform: translateY(42px);
}
.jh-fx [data-rise].is-up {
  opacity: 1;
  transform: translateY(0);
  /* Longhands, not the shorthand: a var() sitting in the shorthand's
     delay slot made Chrome drop the whole declaration, and every line
     appeared at once instead of rising. */
  transition-property: opacity, transform;
  transition-duration: 760ms, 900ms;
  transition-timing-function: ease, cubic-bezier(.16, .84, .3, 1);
  transition-delay: var(--rise-delay, calc(var(--line, 0) * 190ms));
}
/* The motto, roughly as wide as CLINICA so the two read as one block. */
.jh-hero-motto { width: 56%; opacity: .92; margin-top: 1%; }

/* EGYPT signing the hero off, a rule running out either side of it. */
.jh-hero-signoff {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4%;
  width: 52%;
  margin-top: 1%;
}
.jh-signoff-word { flex: 0 0 34%; min-width: 0; }
/* The rules are drawn last and together, outwards from the word — scaleX
   from the inner edge, so each one grows away from EGYPT rather than
   sliding past it. A transform, not a width, so it costs no layout.

   An explicit basis rather than flex-grow: an empty element with
   flex-basis:auto has nothing to grow from and came out zero wide. */
.jh-signoff-rule {
  flex: 0 0 24%;
  height: 1px;
  background: #c79a34;
  transform: scaleX(0);
}
.jh-signoff-rule:first-child { transform-origin: 100% 50%; }
.jh-signoff-rule:last-child { transform-origin: 0 50%; }
/* 3260ms is where EGYPT lands: its 2500ms wait plus the 760ms rise. The
   rules start as it settles, so the pair reads as one closing beat. */
.jh-fx .jh-signoff-rule.is-drawn {
  transform: scaleX(1);
  transition: transform 620ms cubic-bezier(.22, .68, .3, 1) 3260ms;
}

/* Centred on the panel, under the lettering. Positioned against the
   photograph like the panel is, not nested inside it. */
.jh-hero-actions {
  position: absolute;
  left: 54%;
  right: 4%;
  bottom: 6%;
  z-index: 2;
  text-align: center;
}
.jh-hero-actions .jh-actions {
  margin-top: 0;
  flex-wrap: nowrap;
  justify-content: center;
}

@media (max-width: 1400px) {
  .jh-hero-actions .btn { padding: 10px 15px; font-size: 11px; }
}
@media (max-width: 1100px) {
  /* The panel holds four rows now, not two, so it has to stop well above
     the buttons: at 768 its old 6% bottom put the sign-off rule and the
     top of BOOK A CONSULTATION on the same pixel. */
  .jh-hero-panel { left: 53%; right: 2%; top: 7%; bottom: 26%; }
  .jh-hero-actions .btn { padding: 8px 11px; font-size: 9.5px; letter-spacing: .04em; }
}
@media (max-width: 760px) {
  /* The lettering comes off the photograph on a phone.
     The banner is cropped to about 2.6:1 there, which leaves a grey panel
     some 180px wide — the whole lockup inside it came out at a CLINICA of
     22px over a JOELLE of 8, pressed up against the model's hair. Below
     the picture it has the full width of the screen, the photograph is
     left to be a photograph, and nothing has to shrink.

     Same move the two buttons already make, and the panel sits between
     them and the banner because that is its order in the markup. */
  /* With the lettering gone the banner's right-hand third is empty grey,
     because that grey is where the lettering used to be. So the crop
     tightens onto the two women: 16:10 rather than the file's 3.3:1, held
     left of centre, which is the whole of both of them and none of the
     blank panel. Phones are sent this window already cut out
     (hero-banner-phone*.webp, see front-page.php), so if the 30% changes,
     re-cut those files to match; the rule still frames the JPEG fallback. */
  .jh-hero-media img { aspect-ratio: 16 / 10; object-position: 30% center; }
  .jh-hero-panel {
    position: static;
    gap: 10px;
    padding: 22px 18px 4px;
  }
  .jh-hero-wordmark { width: 72%; }
  .jh-hero-motto { width: 72%; }
  .jh-hero-signoff { width: 66%; }
  /* The travel is a fraction of the lettering at every other width; 42px
     of it over a 30px CLINICA would start the line below the picture. */
  .jh-fx [data-rise] { transform: translateY(18px); }
  /* Two buttons will not fit under the lettering on a panel this narrow,
     so they leave the banner too. */
  .jh-hero-actions {
    position: static;
    padding: 10px 16px 4px;
  }
  .jh-hero-actions .jh-actions { gap: 10px; align-items: stretch; }
  .jh-hero-actions .btn {
    flex: 1 1 0;
    min-width: 0;
    /* 13px rather than 10: a single-line label came to a 38px box, under
       the 44px minimum for something meant to be tapped. */
    padding: 13px 6px;
    min-height: 44px;
    font-size: 10px;
    letter-spacing: .06em;
    line-height: 1.35;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* ---- Reviews ----------------------------------------------------------
   One review at a time, in the band the intro paragraph used to hold. The
   reviews themselves come from the Reviews page (inc/reviews.php), so this
   is only the frame around them.

   Every review is in the markup at once and the script toggles which one is
   visible, rather than building slides from data — so with the script blocked
   the first review still shows instead of an empty box.
   --------------------------------------------------------------------- */
.jh-reviews { background: var(--cream); }
.jh-reviews-head { margin-bottom: 36px; }

.jh-reviews-slider {
  position: relative;
  /* Room down each side for the arrows, which sit outside the quote. */
  padding: 0 64px;
  /* It is draggable, so it should say so — and a drag must not select the
     quote's text on the way past. pan-y keeps vertical scrolling native. */
  cursor: grab;
  touch-action: pan-y;
  user-select: none;
}
.jh-reviews-slider.is-dragging { cursor: grabbing; }
/* The arrows and dots are buttons, not part of the drag surface. */
.jh-reviews-nav,
.jh-reviews-dot { cursor: pointer; }

/* The stage is a grid with every review in the same cell, so it is as tall as
   the longest one and the arrows and dots never jump between slides — the
   reviews run from about 200 to 550 characters, which would otherwise move
   them by a hundred pixels or more. */
.jh-reviews-stage {
  display: grid;
  /* The reviews are different lengths, so a short one has slack in the cell.
     Centring splits that above and below it rather than leaving it all
     underneath, which read as a gap between the quote and the dots. */
  align-items: center;
}
.jh-review {
  grid-area: 1 / 1;
  margin: 0;
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity .45s ease, transform .45s ease, visibility .45s;
  /* The hidden reviews still occupy the cell, so they must not swallow a
     click or a tab stop meant for the visible one. */
  pointer-events: none;
}
.jh-review.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
}

.jh-review-mark {
  display: block;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 68px;
  line-height: .7;
  color: var(--primary);
  margin-bottom: 18px;
}
.jh-review-quote {
  margin: 0 auto;
  max-width: 820px;
  border: 0;
  padding: 0;
  font-size: clamp(16px, 1.45vw, 20px);
  line-height: 1.65;
  color: var(--ink);
  font-style: normal;
  quotes: none;
}
.jh-review-by {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 26px;
}
.jh-review-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--primary);
  color: var(--ink);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .02em;
}
.jh-review-name {
  font-weight: 600;
  color: var(--ink);
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: 13px;
}
.jh-review-source {
  color: var(--muted);
  font-size: 13px;
}

/* Same circular control as the treatment cards, so the two sliders on the
   page read as the same component. */
.jh-reviews-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: #fff;
  color: var(--ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease;
}
.jh-reviews-nav:hover {
  background: var(--primary);
  border-color: var(--primary);
}
.jh-reviews-prev { left: 0; }
.jh-reviews-next { right: 0; }

.jh-reviews-dots {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 34px;
}
.jh-reviews-dot {
  /* Stockie styles every <button> on the site as a full button — including
     `min-height: 20px` and `line-height: 20px`, which held these at 20px tall
     against the 9px height and stretched them into ovals. The reset below
     undoes that rule for the dots specifically; the drop shadow and the hover
     sweep it also adds (button:before) go with it. */
  -webkit-appearance: none;
  appearance: none;
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  min-height: 0;
  line-height: 0;
  font-size: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  box-shadow: none;
  background: rgba(11, 1, 0, .18);
  cursor: pointer;
  transition: background-color .25s ease, transform .25s ease;
}
.jh-reviews-dot::before { display: none; }
.jh-reviews-dot.is-active {
  background: var(--primary);
  transform: scale(1.3);
}

@media (max-width: 767px) {
  /* No room for arrows beside the quote at this width — the dots and a swipe
     are enough, and the quote gets the full column back. */
  .jh-reviews-slider { padding: 0; }
  .jh-reviews-nav { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .jh-review { transition: none; }
}

/* ---- Service cards ---- */
/* Was 0, which ran the heading straight into the band above it. */
.jh-services { padding-top: 90px; }
.jh-card img {
  display: block;
  width: 100%;
  aspect-ratio: 5 / 4;
  object-fit: cover;
  margin-bottom: 20px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, .08);
}
.jh-card .jh-label { margin-bottom: 6px; }
.jh-card h4 { margin: 0 0 8px; }
.jh-card p { color: var(--muted); margin: 0 0 32px; }
/* The wellness photograph is a wide landscape with the subjects low in the
   frame; a centred 5:4 crop shows only the treeline behind them. */
.jh-card-wellness img { object-position: center 78%; }

/* ---- Results (dark) ---- */
.jh-results { background: var(--navy); color: #fff; }
.jh-results h2 { color: #fff; }
.jh-results .jh-label { color: var(--primary); }
.jh-results .jh-heading-row p { color: rgba(255, 255, 255, .72); }
.jh-results .btn-outline { color: #fff; border-color: rgba(255, 255, 255, .6); }
.jh-results .btn-outline:hover { background: var(--primary); border-color: var(--primary); color: var(--ink); }

/* ---- Before / after: a side-scrolling row ----------------------------
   Was a fixed four-column grid. Six cards left a ragged 4 + 2, and every
   card the clinic adds would mean another CSS change; a scroll track takes
   as many as there are.

   A native scroll container with snap points, not a JS carousel: swipe,
   trackpad and the arrow keys all work with no script, and the two buttons
   just call scrollBy.
   --------------------------------------------------------------------- */
/* ---- Before / after gallery -----------------------------------------
   A hairline gold rule round the whole row with a botanical sprig at two
   opposite corners. The earlier version was a heavy bevelled case; this
   is the same idea at a whisper — the photographs are the loud thing in
   this section and the frame should not compete with them.
   --------------------------------------------------------------------- */
.jh-ba-strip { position: relative; }

.jh-ba-frame {
  position: relative;
  padding: 30px;
  /* Four separate hairlines, not a border — each one strongest at the
     sprig it grows out of and fading to nothing at its far end, so the
     rule reads as two open brackets rather than a closed box.
     The sprigs sit top-right and bottom-left, so the top and right lines
     fade away from the top-right, and the bottom and left away from the
     bottom-left. */
  background-image:
    linear-gradient(to right,  transparent 0%, rgba(230, 188, 86, .55) 62%),
    linear-gradient(to bottom, rgba(230, 188, 86, .55) 0%, transparent 62%),
    linear-gradient(to right,  rgba(230, 188, 86, .55) 0%, transparent 62%),
    linear-gradient(to top,    rgba(230, 188, 86, .55) 0%, transparent 62%);
  background-size: 100% 1px, 1px 100%, 100% 1px, 1px 100%;
  background-position: left top, right top, left bottom, left bottom;
  background-repeat: no-repeat;
}

.jh-ba-track {
  display: grid;
  grid-auto-flow: column;
  /* Four across, the fifth peeking in to show the row continues. */
  grid-auto-columns: calc((100% - 3 * 22px) / 4);
  gap: 22px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.jh-ba-track::-webkit-scrollbar { display: none; }
.jh-ba-track:focus-visible { outline: 2px solid var(--primary); outline-offset: 6px; }

.jh-ba-card { margin: 0; scroll-snap-align: start; }
.jh-ba-card img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
}

/* ---- Corner sprigs ---------------------------------------------------
   One drawing, used twice — the bottom-left copy is the same SVG turned
   180 degrees. The offsets put the sprig's own corner on the frame's
   corner: its stem turns at about 94% across and 13% down its box, so a
   230px sprig needs pulling up 30px and out 15px to line up.
   --------------------------------------------------------------------- */
.jh-ba-vine {
  position: absolute;
  width: 230px;
  height: 230px;
  color: var(--primary);
  pointer-events: none;
  opacity: .85;
}
.jh-ba-vine svg { display: block; width: 100%; height: 100%; }
.jh-ba-vine-tr { top: -30px; right: -15px; }
.jh-ba-vine-bl { bottom: -30px; left: -15px; transform: rotate(180deg); }

/* ---- Control bar -----------------------------------------------------
   Counter, segmented rail and arrows on one line under the gallery.
   --------------------------------------------------------------------- */
.jh-ba-foot {
  display: flex;
  align-items: center;
  gap: 26px;
  margin-top: 40px;
}
.jh-ba-count {
  flex: 0 0 auto;
  color: rgba(255, 255, 255, .5);
  font-size: 13px;
  letter-spacing: .14em;
}
.jh-ba-count b {
  color: var(--primary);
  font-size: 20px;
  font-weight: 600;
  letter-spacing: .08em;
}

/* One continuous bar, not segments: the gold length is the share of the
   row on screen and it slides along as you scroll. */
.jh-ba-rail {
  flex: 1 1 auto;
  max-width: 560px;
  height: 2px;
  background: rgba(255, 255, 255, .18);
  position: relative;
  overflow: hidden;
  border-radius: 2px;
}
.jh-ba-rail span {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 25%;
  border-radius: 2px;
  background: var(--primary);
  transition: width .4s cubic-bezier(.2, .7, .2, 1), transform .4s cubic-bezier(.2, .7, .2, 1);
}

.jh-ba-arrows { flex: 0 0 auto; display: flex; gap: 12px; margin-left: auto; }
.jh-ba-nav {
  width: 48px;
  height: 48px;
  min-height: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(230, 188, 86, .5);
  border-radius: 50%;
  background: transparent;
  color: var(--primary);
  cursor: pointer;
  box-shadow: none;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease, opacity .2s ease;
}
.jh-ba-nav::before { display: none; }
.jh-ba-nav svg { width: 19px; height: 19px; }
/* Forward is the filled one — it is the arrow people press. */
.jh-ba-next {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--navy);
}
.jh-ba-nav:hover:not(:disabled) {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--navy);
}
.jh-ba-nav:disabled { opacity: .35; pointer-events: none; }

@media (max-width: 1100px) {
  .jh-ba-frame { padding: 24px; }
  .jh-ba-track { grid-auto-columns: calc((100% - 2 * 18px) / 3); gap: 18px; }
  .jh-ba-vine { width: 180px; height: 180px; top: auto; }
  .jh-ba-vine-tr { top: -23px; right: -12px; }
  .jh-ba-vine-bl { bottom: -23px; left: -12px; }
}
@media (max-width: 760px) {
  .jh-ba-frame { padding: 16px; }
  .jh-ba-track { grid-auto-columns: calc((100% - 14px) / 2); gap: 14px; }
  .jh-ba-vine { width: 130px; height: 130px; }
  .jh-ba-vine-tr { top: -17px; right: -9px; }
  .jh-ba-vine-bl { bottom: -17px; left: -9px; }
  .jh-ba-foot { gap: 14px; margin-top: 28px; }
  .jh-ba-nav { width: 42px; height: 42px; }
  .jh-ba-rail { gap: 10px; }
}
@media (max-width: 480px) {
  .jh-ba-track { grid-auto-columns: 82%; }
  /* No room for it beside the counter and the arrows at this width. */
  .jh-ba-rail { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .jh-ba-rail span { transition: none; }
}

/* Before / after compare sliders */
.ba-gallery {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
  margin-top: 24px;
}
.ba-slider {
  position: relative;
  aspect-ratio: 2 / 1;
  overflow: hidden;
  user-select: none;
}
.ba-slider-image { position: absolute; inset: 0; }
.ba-slider-image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ba-before img { filter: grayscale(65%) brightness(.82) contrast(.92); }
.ba-after { clip-path: inset(0 0 0 var(--pos)); }
.ba-slider-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  width: 2px;
  background: #fff;
  transform: translateX(-50%);
  pointer-events: none;
}
.ba-slider-handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--primary);
  transform: translate(-50%, -50%);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .3);
}
.ba-slider-handle::before {
  content: "\2194";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  color: var(--ink);
}
.ba-slider-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
  -webkit-appearance: none;
  appearance: none;
}
.ba-label {
  position: absolute;
  top: 16px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding: 4px 10px;
  background: rgba(11, 1, 0, .75);
  color: #fff;
  pointer-events: none;
}
.ba-label-before { left: 16px; }
.ba-label-after { right: 16px; }

/* ---- Values ----------------------------------------------------------
   Just the reception lettering now — the four numbered values that used
   to sit under it were removed, so the section is one line of script on
   cream with room to breathe.
   --------------------------------------------------------------------- */
.jh-values { background: var(--cream); text-align: center; }

/* ---- Doctors slider ---------------------------------------------------
   A scroll-snap track rather than a carousel library: it is swipeable on
   touch, arrow-key navigable, and degrades to a plain scrolling row if the
   JavaScript never runs. The buttons scroll it by one card.
   --------------------------------------------------------------------- */
.jh-doctors { background: #fff; }
.jh-doctors .jh-heading-row { margin-bottom: 32px; }

.jh-slider { position: relative; }
.jh-slider-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 3 * var(--gap)) / 4);
  gap: var(--gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Room for the card shadow, which a clipped overflow would otherwise cut. */
  padding-bottom: 8px;
  scrollbar-width: none;
}
.jh-slider-track::-webkit-scrollbar { display: none; }

.jh-doc {
  scroll-snap-align: start;
  background: #fff;
  border: 1px solid var(--line);
  transition: box-shadow .3s ease, transform .3s ease;
}
.jh-doc:hover { box-shadow: 0 12px 32px rgba(0, 0, 0, .10); transform: translateY(-3px); }
.jh-doc img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: center top;
}
.jh-doc-body { padding: 20px 22px 24px; }
.jh-doc-name {
  margin: 0 0 8px;
  font-size: 15px;
  line-height: 1.35;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink);
}
.jh-doc-role {
  margin: 0;
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--primary-deep);
}

/* The arrows straddle the left and right edges of the track, centred on the
   card photographs. Half of each button sits outside the container's 25px
   gutter, which is what keeps them clear of the cards themselves. */
.jh-slider-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 6px 20px rgba(11, 1, 0, .16);
  transition: background .2s ease, border-color .2s ease, color .2s ease, opacity .2s ease;
}
.jh-slider-prev { left: -24px; }
.jh-slider-next { right: -24px; }
.jh-slider-btn:hover:not(:disabled) {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--ink);
}
/* At an end the arrow has nothing to do, so it goes rather than sitting
   greyed over the photograph. pointer-events keeps it unclickable while
   the opacity transition runs. */
.jh-slider-btn:disabled {
  opacity: 0;
  pointer-events: none;
}

@media (max-width: 600px) {
  .jh-slider-btn { width: 40px; height: 40px; font-size: 17px; }
  .jh-slider-prev { left: -8px; }
  .jh-slider-next { right: -8px; }
}

/* ---- Trusted by celebrities ------------------------------------------
   A row of portraits, fanned like a handful of photographs laid on a
   table. Each is tilted by a different amount and sits a little higher or
   lower than its neighbour, so the row reads as a spread of prints rather
   than a tidy grid of thumbnails — and overlapping them slightly is what
   makes four pictures look like a collection.

   The tilt and overlap are the resting state. js/home-effects.js deals the
   cards into it as the section arrives.
   --------------------------------------------------------------------- */
.jh-celebs { background: var(--cream); }
.jh-celebs-head { text-align: center; max-width: 720px; margin: 0 auto 56px; }
.jh-celebs-head h2 { margin: 0 0 16px; }
.jh-celebs-head p { color: var(--muted); margin: 0; }

.jh-celebs-strip {
  display: flex;
  justify-content: center;
  align-items: center;
  /* Negative, so the prints overlap at the edges. */
  gap: 0;
  padding: 20px 0 40px;
}
.jh-celeb {
  position: relative;
  flex: 0 0 auto;
  width: 23%;
  max-width: 300px;
  margin: 0 -1.4%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: #fff;
  /* The white border is the print's edge; the shadow lifts it off the one
     behind. */
  border: 8px solid #fff;
  box-shadow: 0 18px 44px rgba(11, 1, 0, .22);
  /* Lift from the bottom edge, like a print being picked up off the table
     rather than growing from its middle. */
  transform-origin: center bottom;
  /* Its own compositor layer, so the lift is a GPU transform and not a
     repaint of the photograph on every frame. */
  backface-visibility: hidden;
  transition:
    transform .55s cubic-bezier(.2, .7, .2, 1),
    box-shadow .55s cubic-bezier(.2, .7, .2, 1);
}
.jh-celeb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Faces sit high in a standing portrait, so bias the crop upward rather
     than taking the middle and cutting foreheads. */
  object-position: center 22%;
  margin: 0;
}

/* Name and role, on a gradient over the foot of the print so the lettering
   stays readable whatever is behind it. Inside the frame rather than under
   it, because the prints overlap — a caption below would be covered by the
   next photograph along. */
.jh-celeb-who {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 36px 14px 12px;
  background: linear-gradient(to top, rgba(11, 1, 0, .82) 0%, rgba(11, 1, 0, .55) 45%, transparent 100%);
  color: #fff;
  text-align: center;
  pointer-events: none;
}
.jh-celeb-name {
  display: block;
  font-weight: 600;
  font-size: 14px;
  letter-spacing: .05em;
  text-transform: uppercase;
  line-height: 1.25;
}
.jh-celeb-role {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--primary);
}

/* The fan. Each print leans a different way and sits at its own height, so
   no two edges line up. */
.jh-celeb:nth-child(1) { transform: rotate(-6deg) translateY(10px); z-index: 1; }
.jh-celeb:nth-child(2) { transform: rotate(2.5deg) translateY(-14px); z-index: 2; }
.jh-celeb:nth-child(3) { transform: rotate(-2deg) translateY(8px); z-index: 3; }
.jh-celeb:nth-child(4) { transform: rotate(5.5deg) translateY(-6px); z-index: 2; }

/* Hovering straightens a print and brings it to the front, which is also
   how you get a clear look at one that is partly covered.

   Only the hovered print changes. There used to be a companion rule that
   lightened the shadow on all four whenever the cursor was anywhere on the
   strip — four box-shadow transitions firing at once, and a box-shadow
   transition repaints rather than composites, so that one rule was most of
   the stutter.

   No !important either: the script now clears its inline transform once the
   prints have landed, so there is nothing left to outrank. */
.jh-celeb:hover,
.jh-celeb:focus-within {
  transform: rotate(0deg) translateY(-12px) scale(1.05);
  box-shadow: 0 26px 54px rgba(11, 1, 0, .28);
  z-index: 5;
}

@media (max-width: 900px) {
  /* A swipeable row, not a stack. Four portraits in a column came to about
     1500px of scrolling, and shrinking them to fit two across left the
     faces too small to recognise — which is the entire point of the
     section. Side-scrolling keeps them big and the section one screen tall.

     Straight, not fanned: overlapping tilted prints only read as a spread
     when you can see the whole spread at once. js/home-effects.js drops the
     rotation at this width too. */
  .jh-celebs-strip {
    justify-content: flex-start;
    gap: 14px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    /* Room for the shadows, which would otherwise be clipped by the
       scroll container. */
    padding: 16px 20px 28px;
    /* Edge-to-edge, so a card can sit under the page gutter as you scroll
       and it's obvious the row continues. */
    margin: 0 -20px;
    scrollbar-width: none;
  }
  .jh-celebs-strip::-webkit-scrollbar { display: none; }
  .jh-celeb {
    width: 62%;
    max-width: 260px;
    margin: 0;
    border-width: 6px;
    scroll-snap-align: center;
  }
  /* Straight, not fanned — and now that the script clears its inline
     transform when the prints land, these have to be unset here or the
     desktop fan would apply at this width too. */
  .jh-celeb:nth-child(n) { transform: none; }
  /* Nothing to bring forward when they no longer overlap. */
  .jh-celeb:hover,
  .jh-celeb:focus-within { transform: none; box-shadow: 0 18px 44px rgba(11, 1, 0, .22); }
}

/* ---- Statement ---- */
.jh-statement { background: var(--primary); text-align: center; }
.jh-statement-text {
  max-width: 900px;
  margin: 0 auto;
  font-size: clamp(21px, 2.4vw, 30px);
  line-height: 1.45;
  color: var(--ink);
}

/* ---- Final CTA ---- */
.jh-cta-row { display: flex; align-items: center; }
.jh-cta-text h2 { margin: 0 0 16px; }
.jh-cta-text p { color: var(--muted); max-width: 460px; margin: 0 0 28px; }
.jh-cta-media img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  box-shadow: 0 2px 4px rgba(0, 0, 0, .15);
}

/* ---- Responsive ---- */
@media (max-width: 1199px) {
  .jh-slider-track { grid-auto-columns: calc((100% - 2 * var(--gap)) / 3); }
}
@media (max-width: 991px) {
  .jh-section { padding: 70px 0; }
  .jh-cta-row { flex-direction: column; align-items: stretch; }
  .jh-heading-row { flex-direction: column; align-items: flex-start; }
  .jh-cta-media { margin-top: 40px; }
  .jh-slider-track { grid-auto-columns: calc((100% - var(--gap)) / 2); }
}
@media (max-width: 600px) {
  .ba-gallery { grid-template-columns: 1fr; }
  .jh-slider-track { grid-auto-columns: 78%; }
}

/* The category cards link through to Treatments > Surgical / Non-Surgical /
   Wellness. The photograph is a second link to the same place, so it's hidden
   from assistive tech and taken out of the tab order — otherwise every card
   costs a keyboard user two stops to reach one destination. */
.jh-card-media {
  display: block;
  text-decoration: none;
}
.jh-card-media img { transition: transform .4s ease; }
.jh-card-media { overflow: hidden; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0, 0, 0, .08); }
.jh-card-media img { margin-bottom: 0; box-shadow: none; }
.jh-card:hover .jh-card-media img { transform: scale(1.03); }

.jh-card p { margin-bottom: 20px; }
.jh-card-btn { margin-top: 0; }

/* ---- Script lettering ------------------------------------------------
   "Clinica Joelle Egypt" and "We Change Lives" on the hero, and the motto
   again above the values. Real SVG outlines generated from Great Vibes
   (the closest free face to the reception sign), one path per glyph so the
   letters can be written one after another rather than all at once.

   Each path starts as an unfilled outline with its dash offset pushed to
   its full length, so nothing shows. js/home-effects.js measures each path
   and stages the timings.

   The finished letters are filled with the header logo's own gold: a
   single sweep across the whole phrase, bright at both ends and deepest in
   the middle, with a highlight three-quarters along. The stops were
   sampled straight off images/clinica-joelle-logo.png, and the gradient is
   userSpaceOnUse so it runs across the line rather than restarting inside
   every letter.

   The stroke is only the pen that traces the outline; it fades out as the
   gold arrives.
   --------------------------------------------------------------------- */
.jh-script { display: block; width: 100%; height: auto; overflow: visible; }
.jh-script path {
  /* --script-fill is set on each svg and points at its own gradient. */
  fill: var(--script-fill, currentColor);
  fill-opacity: 0;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
/* Suppressed while the script rewinds between passes, so the letters snap
   back to blank instead of un-writing themselves. */
[data-script-draw].is-resetting path { transition: none !important; }

/* --draw, --delay and --fill-delay are written per path by the script. */
[data-script-draw].is-drawing path {
  transition:
    stroke-dashoffset var(--draw, 700ms) cubic-bezier(.45, .05, .35, 1) var(--delay, 0ms),
    fill-opacity 420ms ease var(--fill-delay, 400ms),
    stroke-opacity 420ms ease var(--fill-delay, 400ms);
  stroke-dashoffset: 0 !important;
  fill-opacity: 1;
  /* The pen has done its job once the gold is in; leaving it would make
     the letters heavier than the typeface actually is. */
  stroke-opacity: 0;
}
/* "We Change Lives": the values heading. */
.jh-values-script {
  display: block;
  max-width: 620px;
  /* No bottom margin: the four values that used to sit under it are gone. */
  margin: 0 auto;
  color: var(--primary-deep);
  /* It is an h2, so it inherits the uppercase tracking the brand sets on
     headings — neither of which means anything to an SVG, but the
     screen-reader text inside would pick them up. */
  text-transform: none;
  letter-spacing: normal;
}

@media (max-width: 1100px) {
}
@media (max-width: 760px) {
  .jh-values-script { max-width: 82%; }
}

@media (prefers-reduced-motion: reduce) {
  .jh-fx [data-rise] { opacity: 1; transform: none; transition: none; }
  /* .is-drawn is the more specific selector, so it has to be named here
     or its 4-second delay survives into reduced motion. */
  .jh-fx .jh-signoff-rule,
  .jh-fx .jh-signoff-rule.is-drawn { transform: scaleX(1); transition: none; }
  /* No writing-on: the lettering is simply there. */
  .jh-script path {
    fill-opacity: 1 !important;
    stroke-opacity: 0 !important;
    stroke-dashoffset: 0 !important;
    transition: none !important;
  }
}

/* ---- Header nav, 1025px to 1149px ------------------------------------
   Eight top-level items at 15px of padding each side come to 742px, and
   between the logo and the account icon there is not quite that much —
   so "Contact Us" wrapped onto a second row and hung off the bottom of
   the header, over the hero. Below 1025px Stockie switches to the
   hamburger and the problem goes away on its own; this closes the band
   in between by tightening the item padding until all eight fit.
   --------------------------------------------------------------------- */
@media (min-width: 1025px) and (max-width: 1149px) {
  .site-header .main-nav .menu > li > a {
    padding-left: 8px;
    padding-right: 8px;
    font-size: 13.5px;
  }
}
