/*
 * Page-level styles for treatmehome.ae.
 *
 * design-system.css owns every component. Nothing here restyles one — these
 * are layout compositions and the few page-only patterns (ticker, sticky bar,
 * mobile nav) that the system deliberately doesn't ship. Everything is built
 * from design-system tokens; no raw colour, size or spacing value appears
 * below except the Google brand colours, which are not ours to change.
 *
 * All page-only classes are prefixed `tmh-` so they never collide with a
 * component class.
 */

body {
  margin: 0;
  background: var(--pink-100);
  color: var(--ink);
}

a { color: var(--ink); }
a:where(:not(.btn)):hover { color: var(--ink-60); }

/*
 * Phone type scale.
 *
 * The design system's scale is fluid, but its floors are set for a page that
 * has room — `--text-display` bottoms out at 2.75rem and `--text-h1` at
 * 2.25rem, which is 44px and 36px on a 390px screen. Headings at that size eat
 * the first screen before any content appears, which is one of the specific
 * faults in the audit of the old site.
 *
 * Overriding the tokens rather than the elements means every heading, in every
 * component, on every page comes down together — and the fluid scale takes back
 * over above phone width untouched. Body and small text are left alone: 16px
 * and 14px are already the comfortable reading sizes.
 */
@media (max-width: 40rem) {
  :root {
    --text-display: 2.25rem;   /* 36px */
    --text-h1: 1.875rem;       /* 30px */
    --text-h2: 1.625rem;       /* 26px */
    --text-h3: 1.375rem;       /* 22px */
    --text-h4: 1.25rem;        /* 20px */
    --text-lg: 1.0625rem;      /* 17px */
  }
}

/* ---------------------------------------------------------------- chrome  */

/*
 * The system's header centres the wordmark from 1024px, with nav left and
 * actions right. Below that the nav is hidden and `.tmh-mobile-nav` takes over.
 */
@media (min-width: 64rem) {
  .site-header__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
  }
  .site-header__inner > .site-nav { grid-column: 1; grid-row: 1; justify-self: start; }
  .site-header__inner > .site-header__brand { grid-column: 2; grid-row: 1; justify-self: center; }
  .site-header__inner > .site-header__actions { grid-column: 3; grid-row: 1; justify-self: end; }
  .site-header__actions .tmh-menu-toggle { display: none; }
}

/*
 * The header's own soft CTA is replaced by the icon variant — the page's one
 * signature button belongs on the booking action, and two pills side by side
 * in a 3.5rem bar is one too many.
 */
.site-header__cta { display: none !important; }

.tmh-header-cta { display: none; }
@media (min-width: 30rem) { .tmh-header-cta { display: inline-flex; } }

/*
 * The icon button's circle floods the pill on hover. In the header that reads
 * as a flash rather than a state change, so only the scale step is kept.
 */
.site-header .btn--icon:hover { transform: scale(0.95); }
.site-header .btn--icon:active { transform: scale(0.93); }

/*
 * The mobile menu is a full-screen overlay, not a block in the flow. As an
 * in-flow element it pushed the hero down the page, left the page scrollable
 * behind it and sat underneath the call/WhatsApp bar.
 *
 * It carries the page's own surface — Pink 100 under ink type — so opening it
 * reads as the page clearing rather than as a second screen arriving, and the
 * header above it keeps its colour throughout. The links sit centred in the
 * free space, one pill and the contact icons at the foot in thumb reach.
 *
 * --tmh-header-h is measured by site.js because the header's height depends
 * on which actions are visible at that width. 3.5rem is the system's own
 * min-height, used until the measurement lands and if script never runs.
 *
 * 100dvh rather than 100vh: on iOS the URL bar collapses on scroll and a vh
 * panel is left overhanging the viewport by exactly that much.
 */
.tmh-mobile-nav {
  position: fixed;
  top: var(--tmh-header-h, 3.5rem);
  left: 0;
  right: 0;
  height: calc(100dvh - var(--tmh-header-h, 3.5rem));
  z-index: var(--z-overlay);

  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-6) var(--gutter) calc(var(--space-6) + env(safe-area-inset-bottom));

  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-ui);
  text-align: center;

  /* The panel scrolls on short phones; the page behind it must not follow. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;

  opacity: 0;
  transition: opacity 220ms var(--ease);
}
.tmh-mobile-nav.is-open { opacity: 1; }
.tmh-mobile-nav[hidden] { display: none; }
@media (min-width: 64rem) { .tmh-mobile-nav { display: none; } }

/*
 * The links take the free space and centre within it. On a phone too short
 * to hold everything, flex: 1 0 auto keeps the list at its natural height
 * and lets the overlay scroll rather than crushing the rows into each other.
 */
.tmh-mobile-nav__links {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-1);
  width: 100%;
}

/*
 * Display serif, large and centred. The padding gives each row a hit area
 * well past 44px without a rule between them — the type carries the rhythm.
 */
.tmh-mobile-nav__links a {
  display: block;
  padding: var(--space-2) var(--space-4);

  font-family: var(--font-display);
  font-size: clamp(1.75rem, 7vw, 2.375rem);
  line-height: 1.3;
  color: var(--color-text-muted);
  text-decoration: none;
  transition: color var(--duration) var(--ease), opacity var(--duration) var(--ease);
}
.tmh-mobile-nav__links a:hover,
.tmh-mobile-nav__links a:focus-visible { color: var(--color-text); }
.tmh-mobile-nav__links a:active { opacity: 0.6; }

/* The page you are on: full presence, and the system's accent dot beneath. */
.tmh-mobile-nav__links a[aria-current="page"] { color: var(--color-text); }
.tmh-mobile-nav__links a[aria-current="page"] span { position: relative; }
.tmh-mobile-nav__links a[aria-current="page"] span::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -0.45em;
  width: 0.3em;
  height: 0.3em;
  margin-left: -0.15em;
  border-radius: 50%;
  background: var(--ink);
}
/* High Contrast strips backgrounds and colour differences; an underline survives. */
@media (forced-colors: active) {
  .tmh-mobile-nav__links a[aria-current="page"] { text-decoration: underline; text-underline-offset: 0.2em; }
}

/*
 * The rows arrive one after another rather than all at once. Cheap, and it
 * gives the overlay a direction — top of the list first, the foot last.
 * Fill mode backwards, not both: both would pin opacity and transform after
 * the reveal and silence every :hover and :active rule on the rows.
 */
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a,
.tmh-mobile-nav.is-open .tmh-mobile-nav__foot > * { animation: tmh-nav-in 320ms var(--ease) backwards; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a:nth-child(1) { animation-delay: 60ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a:nth-child(2) { animation-delay: 110ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a:nth-child(3) { animation-delay: 160ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a:nth-child(4) { animation-delay: 210ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a:nth-child(5) { animation-delay: 260ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__foot > :nth-child(1) { animation-delay: 320ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__foot > :nth-child(2) { animation-delay: 370ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__foot > :nth-child(3) { animation-delay: 420ms; }

@keyframes tmh-nav-in {
  from { opacity: 0; transform: translateY(0.75rem); }
  to   { opacity: 1; transform: none; }
}

/* One pill, the contact icons, a line of voice. Centred, in thumb reach. */
.tmh-mobile-nav__foot {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  width: 100%;
}
.tmh-mobile-nav__cta {
  width: 100%;
  max-width: 20rem;
}

/*
 * Icon circles, the system's accent motif as it stands on a light surface:
 * a Pink 200 wash ringed in Pink 300, the glyph in ink. 48px each — the
 * target is the circle.
 */
.tmh-mobile-nav__contact {
  display: flex;
  justify-content: center;
  gap: var(--space-3);
}
.tmh-mobile-nav__contact a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--color-surface-soft);
  border: 1px solid var(--color-accent);
  color: var(--color-text);
  font-size: 0.875rem; /* .icon--lg is 1.5em → 21px glyph */
  transition: background-color var(--duration) var(--ease), transform var(--duration) var(--ease);
}
.tmh-mobile-nav__contact a:hover { background: var(--color-accent); }
.tmh-mobile-nav__contact a:active { transform: scale(0.93); }

.tmh-mobile-nav__tagline {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/*
 * A phone on its side has less height than it has width in portrait. Tighter
 * type, the pill beside the icons and no tagline: the whole menu fits the
 * viewport instead of asking for a scroll to reach the booking button.
 */
@media (max-height: 30rem) {
  .tmh-mobile-nav { gap: var(--space-4); padding-block: var(--space-3) calc(var(--space-3) + env(safe-area-inset-bottom)); }
  .tmh-mobile-nav__links { gap: 0; }
  .tmh-mobile-nav__links a {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 2.75rem; /* the 44px target holds even here */
    font-size: 1.375rem;
    line-height: 1.2;
    padding-block: var(--space-1);
  }
  .tmh-mobile-nav__links a[aria-current="page"] span::after { bottom: -0.2em; }
  .tmh-mobile-nav__foot { flex-direction: row; flex-wrap: wrap; justify-content: center; gap: var(--space-4); }
  .tmh-mobile-nav__cta { width: auto; }
  .tmh-mobile-nav__tagline { display: none; }
}

/*
 * With the overlay open the page beneath is inert, so its sticky call bar
 * would be a dead pair of buttons over live content. The overlay carries
 * its own.
 */
body.tmh-nav-open .tmh-sticky { display: none; }

/*
 * The header joins the overlay while it is open: the same Pink 100, opaque
 * rather than blurred so the rows scrolling under it do not show through.
 * Its own booking pill goes — the overlay carries the one CTA, and a second
 * one in the bar above it is noise.
 *
 * Also fixed, not sticky: the scroll lock pins the body at a negative offset,
 * which leaves a *sticky* header at its static position — the top of the
 * document, i.e. above the viewport — so the menu would open having just
 * scrolled its own close button off-screen.
 */
.site-header {
  transition: background-color 220ms var(--ease);
}
body.tmh-nav-open .site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: var(--color-bg);
  backdrop-filter: none;
}
body.tmh-nav-open .tmh-header-cta { display: none; }

@media (prefers-reduced-motion: reduce) {
  .tmh-mobile-nav, .site-header { transition: none; }
  .tmh-mobile-nav.is-open .tmh-mobile-nav__links a,
  .tmh-mobile-nav.is-open .tmh-mobile-nav__foot > * { animation: none; }
}

/*
 * The sticky bar's own height, so the footer can reserve space for it rather
 * than guessing: one control plus the bar's vertical padding.
 */
:root { --tmh-sticky-height: calc(var(--control-height) + var(--space-6)); }

/* Call and WhatsApp within thumb reach, on phones only. */
.tmh-sticky {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: var(--z-sticky);
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom));
  background: var(--white);
  border-top: 1px solid var(--ink-08);
}
.tmh-sticky > * { flex: 1; }
@media (min-width: 40rem) { .tmh-sticky { display: none; } }

/*
 * Out of the way while the hero’s own buttons are on screen — site.js sets
 * the class. Slid down rather than display: none so it leaves and returns
 * instead of blinking, and hidden with it so nothing off the bottom of the
 * screen can still be tapped or tabbed to. Visibility waits for the slide on
 * the way out and does not on the way back.
 */
.tmh-sticky {
  transition: transform var(--duration) var(--ease), visibility 0s;
}
body.tmh-hero-cta-inview .tmh-sticky {
  transform: translateY(100%);
  visibility: hidden;
  transition: transform var(--duration) var(--ease), visibility 0s var(--duration);
}
@media (prefers-reduced-motion: reduce) {
  .tmh-sticky, body.tmh-hero-cta-inview .tmh-sticky { transition: none; }
}

footer.tmh-footer {
  background: var(--white);
  border-top: 1px solid var(--ink-08);
  padding-top: var(--space-24);
  /*
   * `.site-footer` already reserves room for the sticky bar; overriding
   * padding-bottom throws that away, so it is put back here. Without it the
   * last line of the footer sits underneath the call/WhatsApp bar.
   */
  padding-bottom: calc(var(--space-16) + var(--tmh-sticky-height) + env(safe-area-inset-bottom));
}
@media (min-width: 40rem) {
  footer.tmh-footer { padding-bottom: var(--space-16); }
}
.tmh-footer .site-footer__grid { grid-template-columns: 1fr; }
@media (min-width: 40rem) {
  .tmh-footer .site-footer__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 64rem) {
  .tmh-footer .site-footer__grid { grid-template-columns: 1.3fr repeat(3, 1fr); }
}
.tmh-footer .site-footer__bottom .cluster {
  flex-wrap: nowrap;
  align-items: center;
  white-space: nowrap;
}

.tmh-contact {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-5);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
}
.tmh-contact > div { display: flex; align-items: center; gap: var(--space-3); }
.tmh-contact a { text-decoration: none; }

/* Reused for the footer contact rows and the category-row chevrons. */
.tmh-bubble {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-pill);
  background: var(--pink-200);
  color: var(--ink);
}
.tmh-bubble--lg { width: 2.5rem; height: 2.5rem; }

/* ------------------------------------------------------------------ hero  */

.tmh-hero {
  background: var(--pink-100);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
  align-items: stretch;
}

.tmh-hero__copy {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: clamp(2rem, 3.4vw, 3rem) var(--gutter);
}
.tmh-hero__copy > div { max-width: 34rem; }

.tmh-hero h1 {
  margin: var(--space-4) 0 var(--space-2);
  max-width: 13ch;
  text-wrap: balance;
}
.tmh-hero .lead { max-width: 32rem; margin-top: var(--space-4); }
.tmh-hero .cluster { margin-top: var(--space-6); }

/*
 * The Google rating, in the slot the price line used to hold. Deliberately
 * not a link: the hero is down to two calls to action and a third thing to
 * tap would undo that. The mark keeps Google’s own fills, for the same
 * reason it does in the reviews card — a recoloured Google logo
 * misrepresents where the rating came from.
 */
.tmh-hero__rating {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.tmh-hero__rating strong { font-weight: 600; color: var(--color-text); }

.tmh-hero__photo {
  width: 100%;
  height: 100%;
  min-height: clamp(26rem, 42vw, 38rem);
  /*
   * The source is a 2:3 portrait, so at any real column width its intrinsic
   * height exceeds the space available — this cap, not the min-height, is what
   * actually sets the hero's height on a laptop or desktop.
   */
  max-height: 44rem;
  object-fit: cover;
  /* The shoulders, not the head — 50% would centre on the pillow. */
  object-position: 50% 45%;
}

/*
 * 52rem is where the hero's own `auto-fit, minmax(min(100%, 26rem), 1fr)`
 * finds room for two columns — not an invented breakpoint, the component's own.
 * Once the photo is beside the copy rather than stacked above it, it can afford
 * more height, and the extra air around the headline is the point.
 *
 * The `88vh` term stops a very short window from getting a hero taller than
 * itself. It is set so that no viewport ends up shorter than it was before this
 * increase — the cap only ever adds height, never takes it away.
 */
@media (min-width: 52rem) {
  .tmh-hero__photo { max-height: min(50rem, 88vh); }
}

/* ---------------------------------------------------------------- ticker  */

.tmh-trust {
  padding: var(--space-3) 0;
  background: var(--pink-200);
  border-top: 1px solid var(--ink-08);
  border-bottom: 1px solid var(--ink-08);
}

.tmh-ticker {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.tmh-ticker__track {
  display: flex;
  align-items: center;
  gap: var(--space-10);
  width: max-content;
  animation: tmh-ticker 40s linear infinite;
}
.tmh-ticker:hover .tmh-ticker__track { animation-play-state: paused; }

.tmh-ticker__set { display: flex; align-items: center; gap: var(--space-10); }

.tmh-ticker__item {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  white-space: nowrap;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-tight);
  color: var(--ink-60);
}
.tmh-ticker__item::before {
  content: '';
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--ink-40);
}

/*
 * The track holds the list twice, so one full set plus the gap between the two
 * sets is exactly the distance back to the start.
 */
@keyframes tmh-ticker {
  from { transform: translateX(0); }
  to { transform: translateX(calc(-50% - var(--space-10) / 2)); }
}

@media (prefers-reduced-motion: reduce) {
  .tmh-ticker__track { animation: none; }
}

/* ----------------------------------------------------------- ritual cards */

.tmh-cards { margin-top: var(--space-10); align-items: stretch; }

/* Card is the styled surface; this stretches its contents to the full height
   so every footer in the row lands on the same line. */
.tmh-card-body { display: flex; flex-direction: column; height: 100%; }

.tmh-ritual__meta {
  display: block;
  margin: var(--space-3) 0 var(--space-2);
  color: var(--ink-40);
  font-variant-numeric: tabular-nums;
}

.tmh-ritual__title {
  margin: 0 0 var(--space-3);
  font-size: var(--text-h4);
  line-height: 1.2;
  /* Two lines' worth, so one- and two-line names still align their footers. */
  min-height: 2.4em;
  text-wrap: balance;
}

.tmh-ritual__desc { margin: 0; flex: 1; text-wrap: pretty; }

/*
 * The hard <br> inside ritual titles balances the four-across desktop row;
 * below 30rem the grid is a single column, where it splits short names
 * ("Cleopatra / Ritual") for no reason — and the two-line min-height
 * reserved for footer alignment just leaves a blank line.
 */
@media (max-width: 29.999rem) {
  .tmh-ritual__title br { display: none; }
  .tmh-ritual__title { min-height: 0; }
}

/* ------------------------------------------------------------- menu cards */

/*
 * A taller photo than `.card__media` gives: these three are the page's proof
 * that a stranger arriving at your door brings a real spa with her.
 */
.tmh-photo {
  width: calc(100% + var(--space-6) * 2);
  margin: calc(var(--space-6) * -1) calc(var(--space-6) * -1) var(--space-6);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--pink-200);
}
.tmh-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }

/*
 * The ceiling is 1.15rem, not 1.35rem, because the 1.55vw between them grows
 * against a column that does not. These cards sit in a container with a
 * max-width, so past about 1084px the viewport keeps widening, the type keeps
 * following it and the card stays where it is — at 1440 the longest of the
 * three titles wanted 45px more than its column had, and wrapped.
 *
 * 1.15rem is the largest step that keeps "Himalayan Salt Stone Massage" on one
 * line at every width it is read at. Measured, not guessed: 1.2rem still spills
 * at 1440.
 */
.tmh-treatment__title {
  margin: var(--space-4) 0 var(--space-3);
  font-size: clamp(1.05rem, 1.55vw, 1.15rem);
  line-height: 1.3;
}

.tmh-treatment__desc { margin: 0 0 var(--space-4); text-wrap: pretty; }

/*
 * Line the three cards up row by row.
 *
 * A title that wraps to two lines pushed its own description, benefits and
 * everything under it out of step with the cards beside it — the footers
 * already agreed, because the benefits block is a flex spacer, but nothing
 * between the photograph and the footer did.
 *
 * Subgrid rather than a reserved two-line height on the title: it takes its
 * measure from the tallest card in the row, so three one-line titles stay one
 * line and give nothing away, and it aligns the description and the benefits
 * too, which differ in length independently of the title.
 *
 * Only where the cards are actually side by side. Stacked on a phone there is
 * nothing to align, and subgrid there cost about 96px of empty room per card.
 * Below this width, and anywhere subgrid is unsupported, the flex column the
 * card already had is untouched.
 */
@media (min-width: 48rem) {
  @supports (grid-template-rows: subgrid) {
    /*
     * photograph, title, description, benefits, footer.
     *
     * row-gap must go to zero. The grid sets gap: --space-6 for the space
     * between cards, and once each card spans five row tracks that 24px lands
     * between all five of them as well — 96px of nothing added to every card,
     * which is what made the aligned version look so airy. The space between
     * card rows comes back as a margin on the card itself, which the grid
     * pulls off its own bottom edge so the last row adds no trailing gap.
     */
    .grid--3.tmh-cards {
      grid-template-rows: repeat(5, auto);
      row-gap: 0;
      margin-bottom: calc(var(--space-6) * -1);
    }
    .grid--3.tmh-cards > .card { margin-bottom: var(--space-6); }
    .grid--3.tmh-cards > .card {
      grid-row: span 5;
      display: grid;
      grid-template-rows: subgrid;
    }
    .grid--3.tmh-cards > .card > .tmh-card-body {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: span 5;
      height: auto;
    }
  }
}

.tmh-benefits {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--ink-60);
}
.tmh-benefits li { display: flex; gap: var(--space-2); align-items: baseline; }
.tmh-benefits li::before {
  content: '';
  flex: none;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--pink-300);
  /* Baseline alignment drops a 5px dot below the x-height. */
  transform: translateY(-2px);
}

/* ------------------------------------------------------- category rows    */

.tmh-catrows { display: grid; gap: var(--space-3); margin-top: var(--space-6); }

.tmh-catrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-6);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5) var(--space-6);
  text-decoration: none;
  color: var(--color-text);
  transition: box-shadow var(--duration) var(--ease),
              transform var(--duration) var(--ease);
}
.tmh-catrow:hover {
  color: var(--color-text);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.tmh-catrow__text { flex: 1 1 18rem; min-width: 0; }
.tmh-catrow__text h3 { margin: 0 0 var(--space-1); font-size: var(--text-h4); }
.tmh-catrow__text p { margin: 0; text-wrap: pretty; }
.tmh-catrow__count { min-width: 11rem; font-variant-numeric: tabular-nums; }
.tmh-catrow__price {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: var(--space-2);
  min-width: 8.5rem;
}

@media (prefers-reduced-motion: reduce) {
  .tmh-catrow, .tmh-catrow:hover { transition: none; transform: none; }
}

/* ------------------------------------------------------------- what arrives */

.tmh-arrives {
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  align-items: stretch;
}
.tmh-arrives__photo {
  width: 100%;
  height: 100%;
  min-height: 32rem;
  max-height: 54rem;
  object-fit: cover;
  display: block;
}
.tmh-arrives__copy {
  padding: clamp(2.5rem, 4.5vw, 3.6rem) var(--gutter);
  max-width: 36rem;
  justify-self: center;
  align-self: center;
}
.tmh-arrives__list {
  list-style: none;
  margin: var(--space-8) 0;
  padding: 0;
  display: grid;
  gap: var(--space-4);
  font-family: var(--font-body);
  font-size: var(--text-base);
}
.tmh-arrives__list li { display: flex; gap: var(--space-3); align-items: baseline; }

/* ---------------------------------------------------------------- founders */

.tmh-founders {
  margin-top: var(--space-12);
  display: grid;
  gap: var(--space-10) var(--space-12);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 32rem), 1fr));
}

/*
 * Portrait above the story on phones. The fixed 13rem portrait column left the
 * text a sliver on narrow screens, so the two columns only apply once there is
 * room for them.
 */
.tmh-founder {
  margin: 0;
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
  align-items: stretch;
}
@media (min-width: 40rem) {
  .tmh-founder {
    grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
    gap: var(--space-8);
  }
}
.tmh-founder img {
  width: 100%;
  height: 100%;
  min-height: 20rem;
  object-fit: cover;
  object-position: top center;
  display: block;
  border-radius: var(--radius-lg);
  background: var(--white);
}
.tmh-founder figcaption { display: flex; flex-direction: column; }
.tmh-founder__name { display: flex; flex-direction: column; gap: var(--space-1); }
.tmh-founder__name h3 { margin: 0; font-size: var(--text-h3); line-height: 1.05; }

.tmh-founder__quote {
  margin: var(--space-6) 0 0;
  padding-left: var(--space-5);
  border-left: 1px solid var(--ink-16);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  line-height: 1.5;
  letter-spacing: var(--tracking-heading);
  text-wrap: pretty;
  max-width: 30ch;
}
.tmh-founder__note {
  margin: var(--space-5) 0 0;
  padding-left: var(--space-5);
  max-width: 34ch;
  line-height: 1.7;
  text-wrap: pretty;
}

.tmh-founders__close {
  margin-top: var(--space-12);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-border);
}
.tmh-founders__close p {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-h3);
  letter-spacing: var(--tracking-heading);
  max-width: 24ch;
  text-wrap: pretty;
}

/* ---------------------------------------------------------------- reviews */

/*
 * The Google rating card sits beside the heading only where both fit; on phones
 * it drops below rather than squeezing "In their words" into a sliver.
 * `align-items: end` needs the header's own bottom margin gone, or the two
 * columns baseline against different edges.
 */
.tmh-stories__head {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: end;
}
.tmh-stories__head .section-header { margin-bottom: 0; }
@media (min-width: 48rem) {
  .tmh-stories__head {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-8);
  }
}

.tmh-rating {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  background: var(--white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5) var(--space-6);
  box-shadow: var(--shadow-sm);
}
.tmh-rating__score { display: grid; justify-items: center; gap: 2px; }
.tmh-rating__score b {
  font-family: var(--font-ui);
  font-size: 2.25rem;
  line-height: 1;
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  color: var(--ink);
}
.tmh-rating__rule { width: 1px; align-self: stretch; background: var(--color-border); }
.tmh-rating__source { display: grid; gap: var(--space-2); }
.tmh-rating__source > div { display: flex; align-items: center; gap: var(--space-2); }
.tmh-rating__source span,
.tmh-rating__source a { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--ink); }
.tmh-rating__source a:hover { opacity: 0.7; }

/* Google's own yellow. Outside the five-value palette by necessity — a
   recoloured star rating misrepresents the source. */
.tmh-stars { color: #f4b400; letter-spacing: 2px; font-size: 0.9rem; }
.tmh-rating .tmh-stars { font-size: 0.95rem; letter-spacing: 1px; }

.tmh-rail-wrap { margin-top: var(--space-10); position: relative; }

.tmh-rail {
  display: flex;
  gap: var(--space-5);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding: var(--space-2) var(--space-1) var(--space-6);
  margin: 0 calc(-1 * var(--space-1));
  scrollbar-width: none;
  align-items: stretch;
}
.tmh-rail::-webkit-scrollbar { display: none; }

.tmh-review {
  scroll-snap-align: start;
  flex: 0 0 clamp(280px, 84vw, 380px);
  background: var(--white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  display: grid;
  gap: var(--space-4);
  align-content: start;
  box-shadow: var(--shadow-sm);
}
.tmh-review__head { display: flex; align-items: center; gap: var(--space-3); }
.tmh-review__avatar {
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: var(--radius-pill);
  background: var(--pink-200);
  display: grid;
  place-items: center;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--ink);
}
.tmh-review__who { display: grid; gap: 1px; flex: 1; min-width: 0; }
.tmh-review__name { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--ink); }
.tmh-review__creds,
.tmh-review__when { font-family: var(--font-ui); font-size: var(--text-xs); color: var(--ink-60); }
.tmh-review__rating { display: flex; align-items: center; gap: var(--space-3); }
.tmh-review__quote {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.7;
  color: var(--ink-80);
  text-wrap: pretty;
}

.tmh-google-g { width: 18px; height: 18px; display: block; }

.tmh-stories__actions {
  margin-top: var(--space-8);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

/* -------------------------------------------------------------------- faq */

.tmh-faq { max-width: 46rem; }
.tmh-faq__list { margin-top: var(--space-8); }

/* ------------------------------------------------------------------ close */

.tmh-close { text-align: center; }
.tmh-close .cluster { justify-content: center; margin-top: var(--space-8); }

/* ================================================================= about  */

/*
 * The About page alternates a photo and a column of prose. One class, because
 * the design uses the identical grid five times over — 20rem is the point at
 * which two columns stop being readable and it drops to one.
 */
.tmh-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
.tmh-split--top { align-items: start; }

.tmh-split h1 { max-width: 18ch; }

/* 3:4 is the crop the Person component uses, so figures and portraits on this
   page share one silhouette. */
.tmh-figure {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--radius-lg);
  display: block;
}

.tmh-prose { max-width: 34rem; }
.tmh-prose h2 { margin-top: var(--space-3); }

.tmh-mission__note {
  max-width: 34rem;
  margin-top: var(--space-6);
}

.tmh-center { text-align: center; }
.tmh-center h2 { margin-inline: auto; max-width: 20ch; }
.tmh-center .cluster { justify-content: center; margin-top: var(--space-8); }

/* ================================================================== book  */

.tmh-book__lead { max-width: 36rem; }
.tmh-book__trust { margin-top: var(--space-8); max-width: 46rem; }
/* On phones the wrapping row breaks unevenly; a plain stack reads better. */
@media (max-width: 40rem) { .tmh-book__trust { flex-direction: column; gap: var(--space-3); } }

.tmh-steps {
  list-style: none;
  counter-reset: step;
  margin: var(--space-10) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: var(--space-6);
  max-width: 46rem;
}
.tmh-steps li { display: grid; gap: var(--space-2); }
.tmh-steps li > span:last-child { font-family: var(--font-body); }

.tmh-book__panel { max-width: 52rem; }

/* The booking panel: the way to book now that there is no calendar. */
.tmh-book__contact p { max-width: 34rem; }
.tmh-book__contact .cluster { margin: var(--space-5) 0 var(--space-3); }
.tmh-book__policy { max-width: 34rem; margin-top: var(--space-8); }

/* ============================================================== services  */

.tmh-figure--wide { aspect-ratio: 4 / 3; }

/*
 * The nails photo in the dark band is a full-length portrait rather than a
 * crop, so it is contained instead of covered — cropping it to the band would
 * cut the subject in half.
 */
.tmh-figure--contain {
  aspect-ratio: 2 / 3;
  object-fit: contain;
}

.tmh-jump { margin-top: var(--space-8); }

/* Section opener: heading beside a photo, above the grid of treatments. */
.tmh-opener { margin-bottom: var(--space-12); }

.tmh-grid { margin-top: var(--space-10); }

/* A sub-header that follows a card grid (Nail packages, Nail add-on) needs
   its own breathing room — .section-header only carries margin-bottom. */
.grid + .section-header, .tmh-grid + .section-header { margin-top: var(--space-16); }

/*
 * A treatment card. The tag row is pushed to the bottom so that every card in a
 * row lands its price and Book button on the same line, whatever the length of
 * the name above it.
 */
.tmh-item { display: flex; flex-direction: column; }
.tmh-item > h3 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-h4);
  line-height: var(--leading-tight);
  text-wrap: balance;
}
.tmh-item > p { margin: 0 0 var(--space-4); text-wrap: pretty; }
.tmh-item > .cluster { margin-top: auto; gap: var(--space-2); }

.tmh-couples { margin-top: var(--space-10); max-width: 24rem; }

/* ========================================================== craftsmanship  */

/* A numbered pair of points, set against the photo beside them. */
.tmh-points { display: grid; gap: var(--space-12); }
.tmh-points h3 { margin: var(--space-2) 0 var(--space-3); }
.tmh-points p { margin: 0; max-width: 34rem; }
.tmh-points .meta { display: block; }

.tmh-craft-nails p { max-width: 34rem; }
.tmh-craft-nails__note { margin: var(--space-6) 0 0; }
.tmh-craft-nails__line { margin: var(--space-8) 0 0; }
.tmh-craft-nails__cta { margin-top: var(--space-8); }

/* ================================================== offer popup  */

/*
 * The limited-time offer dialog. Injected by assets/popup.js — no page carries
 * markup for it, so with scripting off nothing here has anything to style.
 *
 * Type only, on the page's own Pink 100: it reads as a note from the house
 * rather than an ad, which is the whole reason it can interrupt at all. The
 * one action is a WhatsApp pill; the design system's own components carry it
 * (.eyebrow, .price, .btn), so this block is position and scale and nothing
 * else.
 */

.tmh-offer {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;

  /* env() so a notched phone in landscape can't tuck the card under a rounded
     corner or the home indicator. */
  padding: max(var(--space-4), env(safe-area-inset-top))
           max(var(--space-4), env(safe-area-inset-right))
           max(var(--space-4), env(safe-area-inset-bottom))
           max(var(--space-4), env(safe-area-inset-left));
}

.tmh-offer__scrim {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ink) 42%, transparent);
  opacity: 0;
  transition: opacity var(--duration-slow) var(--ease);
}

.tmh-offer.is-open .tmh-offer__scrim { opacity: 1; }

.tmh-offer__card {
  position: relative;
  width: 100%;
  max-width: 26rem;

  /*
   * Never taller than the space it was given. A phone held sideways is about
   * 360px of height; without this the pill sits below the fold of a dialog
   * that has taken the page's scroll away, and the offer is unclaimable.
   */
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;

  /*
   * Asymmetric on purpose. The close button is a 44px target inset from the
   * corner, and on a phone the label below it wraps to two lines and runs the
   * full width of the card — so the top padding has to clear the button
   * outright rather than tuck under it.
   */
  padding: var(--space-16) var(--space-6) var(--space-10);
  text-align: center;

  background: var(--pink-100);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);

  opacity: 0;
  transform: translateY(0.875rem) scale(0.985);
  transition: opacity var(--duration-slow) var(--ease),
              transform var(--duration-slow) var(--ease);
}

.tmh-offer.is-open .tmh-offer__card {
  opacity: 1;
  transform: none;
}

/*
 * At 30rem the card has hit its 26rem ceiling: the label fits on one line, it
 * no longer reaches the close button, and the padding can even up.
 */
@media (min-width: 30rem) {
  .tmh-offer__card { padding: var(--space-10); }
}

/*
 * Close. 44px of target inside a 36px circle — the visual size the corner of a
 * card can carry, the tap size a thumb needs.
 */
.tmh-offer__close {
  position: absolute;
  top: var(--space-3);
  inset-inline-end: var(--space-3);

  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;

  color: var(--color-text);
  background: none;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color var(--duration) var(--ease),
              color var(--duration) var(--ease);
}

.tmh-offer__close:hover { background: var(--pink-200); }

/* Nineteen tracked uppercase characters — one line on any phone. It names
   the offer so the number below it does not have to. */
.tmh-offer__eyebrow {
  margin: 0 0 var(--space-3);
  font-size: var(--text-xs);
  line-height: var(--leading-tight);
}


/*
 * The discount is the loudest thing on the card and the only thing at this
 * size. Instrument Sans at 700 rather than the serif: a grotesque carries a
 * numeral harder than a text face does, and it ties the number to the label
 * above it and the button below, leaving the serif to the one line of prose.
 * The 700 is a weight added to a family the page already fetches, not a
 * fourth family — Anton or Inter would each have cost a new request, and
 * Anton would have made a luxury card read like a clearance poster.
 */
.tmh-offer__price {
  margin: var(--space-4) 0 0;
  font-family: var(--font-ui);
  font-size: var(--text-display);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--tracking-tight);
}

/* The unit is not the number: same family, quiet weight, and enough air that
   the two don't read as one word. */
.tmh-offer__price span {
  margin-inline-start: var(--space-2);
  font-size: var(--text-lg);
  font-weight: 500;
  color: var(--color-text-muted);
  letter-spacing: 0;
}


/*
 * What the discount actually buys, and the only place the real price appears.
 * A step up from body size and at full ink: it is doing the persuading now
 * that the heading is a number, so it cannot read as small print.
 */
.tmh-offer__sub {
  /* No measure of its own: the card is already narrower than a comfortable
     line, and text-wrap: pretty keeps the last line from stranding a word. */
  margin: var(--space-5) 0 0;
  font-size: var(--text-lg);
  line-height: var(--leading-body);
  color: var(--color-text);
  text-wrap: pretty;
}

.tmh-offer__cta { margin-top: var(--space-6); }

.tmh-offer__dismiss {
  display: block;
  margin: var(--space-4) auto 0;
  padding: var(--space-2);

  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-decoration: underline;
  text-underline-offset: 0.2em;

  background: none;
  border: 0;
  cursor: pointer;
  transition: color var(--duration) var(--ease);
}

.tmh-offer__dismiss:hover { color: var(--color-text); }

/*
 * Short viewports — a phone in landscape, or a laptop with a browser bar and a
 * bookmarks bar. The card keeps every element; it gives up the air between
 * them, which is cheaper than a scrollbar inside a dialog.
 */
@media (max-height: 34rem) {
  .tmh-offer__card { padding: var(--space-8) var(--space-6) var(--space-6); }
  .tmh-offer__price { margin-top: var(--space-1); font-size: var(--text-h1); }
  .tmh-offer__sub { margin-top: var(--space-3); }
  .tmh-offer__cta { margin-top: var(--space-4); }
  .tmh-offer__dismiss { margin-top: var(--space-1); }
}

/*
 * With the dialog open the page beneath is inert, so the sticky call bar would
 * be a dead pair of buttons over live content — and on a short screen it eats
 * the space the card needs. The same rule the mobile nav uses.
 */
body.tmh-offer-open .tmh-sticky { display: none; }

@media (prefers-reduced-motion: reduce) {
  .tmh-offer__scrim,
  .tmh-offer__card { transition: none; }
  .tmh-offer__card { transform: none; }
}

/* ===================================================== header dropdown  */

/*
 * The two landing pages hang off Services in the main nav.
 *
 * No JavaScript. The panel opens on :hover and on :focus-within, and the
 * desktop nav only exists from 64rem up, where a pointer is a safe
 * assumption — below that the menu sheet carries the same two links as rows
 * of its own. Keyboard order works because the trigger sits outside the
 * panel: focusing it opens the panel, and the next Tab can then reach inside.
 */
.tmh-navdrop { position: relative; display: inline-flex; }

.tmh-navdrop__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.tmh-navdrop__caret {
  width: 1em;
  height: 1em;
  transition: transform var(--duration) var(--ease);
}
.tmh-navdrop:hover .tmh-navdrop__caret,
.tmh-navdrop:focus-within .tmh-navdrop__caret { transform: rotate(180deg); }

.tmh-navdrop__panel {
  position: absolute;
  top: 100%;
  /*
   * Anchored to the trigger's leading edge, not centred on it. Services is
   * the first item in the nav, and at 64rem — the width the desktop nav
   * appears at — the gutter leaves it 41px from the edge, where a centred
   * 14rem panel hangs 35px off the side of the screen.
   */
  left: 0;
  z-index: var(--z-raised);
  min-width: 14rem;

  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-3);
  padding: var(--space-3);

  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);

  /*
   * visibility, not display: it animates, and it takes the links out of the
   * tab order and the accessibility tree while the panel is shut. On the way
   * out it waits for the fade; on the way back it does not.
   */
  opacity: 0;
  visibility: hidden;
  transform: translateY(calc(var(--space-2) * -1));
  transition: opacity var(--duration) var(--ease),
              transform var(--duration) var(--ease),
              visibility 0s var(--duration);
}

/*
 * Fills the offset between trigger and panel. Without it the pointer leaves
 * the hover area on its way down and the panel closes under the cursor.
 */
.tmh-navdrop__panel::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--space-3) * -1);
  height: var(--space-3);
}

.tmh-navdrop:hover .tmh-navdrop__panel,
.tmh-navdrop:focus-within .tmh-navdrop__panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity var(--duration) var(--ease),
              transform var(--duration) var(--ease),
              visibility 0s;
}

/* Rows inside the panel read as a list, not as more top-level nav. */
.site-nav .tmh-navdrop__panel a {
  /* space-3 rather than space-2: it is what takes the row past 44px. */
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  white-space: nowrap;
  color: var(--color-text);
  transition: background-color var(--duration) var(--ease), color var(--duration) var(--ease);
}
.site-nav .tmh-navdrop__panel a:hover,
.site-nav .tmh-navdrop__panel a:focus-visible,
.site-nav .tmh-navdrop__panel a[aria-current="page"] { background: var(--color-surface-soft); }

@media (prefers-reduced-motion: reduce) {
  .tmh-navdrop__caret,
  .tmh-navdrop__panel,
  .tmh-navdrop:hover .tmh-navdrop__panel,
  .tmh-navdrop:focus-within .tmh-navdrop__panel { transition: none; }
}

/*
 * The same two links in the phone sheet, set below Services and subordinate
 * to it: the UI face at reading size against the display serif of the rows
 * above. The block padding is what carries each one past 44px, since the
 * type is no longer doing it.
 */
.tmh-mobile-nav__links a.tmh-mobile-nav__sub {
  font-family: var(--font-ui);
  font-size: var(--text-lg);
  letter-spacing: var(--tracking-tight);
  padding-block: var(--space-3);
}

/* The sheet's stagger was written for five rows; there are seven now. */
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a:nth-child(6) { animation-delay: 310ms; }
.tmh-mobile-nav.is-open .tmh-mobile-nav__links a:nth-child(7) { animation-delay: 360ms; }

/* ======================================================= landing pages  */

/*
 * /body-sculpting and /couples-massage. Both pages are built from the site's
 * own components; what lives here is the handful of things a single-action
 * page needs and the rest of the site does not — chiefly the frames standing
 * in for client photography and video that has not arrived yet, and the two
 * galleries built around them.
 */

/* The hero's microcopy line, in the slot the homepage gives its Google
   rating. Type comes from `.meta`; only the offset is new. */
.tmh-lp-hero__meta { margin: var(--space-5) 0 0; }

/*
 * Three treatments across on a laptop. Below that `grid--3`'s own auto-fit
 * takes over — two columns on a tablet, one on a phone. Only the laptop end
 * needs saying: auto-fit would give the container room for a fourth track and
 * leave the three cards short of the full width.
 */
@media (min-width: 64rem) {
  .tmh-lp-treatments { grid-template-columns: repeat(3, 1fr); }
}

/* The promise a treatment or package opens on, set between its name and its
   description. Body face at lead size — it is a headline, not small print. */
.tmh-lp-card__line {
  margin: 0 0 var(--space-3);
  font-family: var(--font-body);
  font-size: var(--text-lg);
  line-height: var(--leading-tight);
  color: var(--color-text);
  text-wrap: pretty;
}

/*
 * A card whose call to action is the page's own "Book Now on WhatsApp". That
 * label is four times the length of the site's "Book", and beside it in a
 * `.card__footer` row the price gets squeezed until "299 AED" breaks in two.
 * So the footer stacks here: the price on its line, the button full width
 * under it — which also gives the one action on the page the whole card width
 * to be tapped on.
 */
.tmh-lp-cta-card .card__footer {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-4);
}
.tmh-lp-cta-card .card__footer .price { white-space: nowrap; }
/* The benefit list runs straight into the tag row on a card tall enough that
   the tag row's auto margin has no slack to give. */
.tmh-lp-cta-card .tmh-benefits { margin-bottom: var(--space-5); }
.tmh-lp-cta-card .card__footer .btn { justify-content: center; }

/*
 * Every link in the chrome of these two pages clears 44px. The site header's
 * logo is 18px of artwork, its pill and its menu toggle are `.btn--sm` at
 * 40px, and the footer's contact rows are single lines of type — fine inside
 * a full site, thin for a page whose entire job is being tapped.
 */
.tmh-lp-head .site-header__brand { padding-block: var(--space-4); }
.tmh-lp-head .tmh-header-cta,
.tmh-lp-head .tmh-menu-toggle { min-height: var(--control-height); }
.tmh-lp-footer .tmh-contact a {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-height);
}

/* What a package saves, above the price rather than inside it — `.price` is
   tabular and one weight, and a saving is neither. */
.tmh-lp-save {
  margin: 0 0 var(--space-4);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/*
 * Reasons to book, each line opening on its own claim. `.tmh-benefits` is the
 * same shape but sized for the inside of a card, and `.trust` holds a few
 * words per item rather than a sentence.
 */
.tmh-lp-reasons {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-5);
  max-width: 44rem;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
}
.tmh-lp-reasons li { display: flex; gap: var(--space-3); align-items: baseline; }
.tmh-lp-reasons .icon { flex: none; color: var(--color-text-muted); }
.tmh-lp-reasons b { font-weight: 600; }

/* A closing aside under a section — the single-session price under the
   packages, the results disclaimer under the gallery. */
.tmh-lp-note { margin: var(--space-10) 0 0; max-width: 44rem; }
.tmh-lp-note > p { margin: 0 0 var(--space-5); }
.tmh-lp-note > :last-child { margin-bottom: 0; }

/*
 * The hero headline. `.tmh-hero h1` caps at 13ch, set for the homepage's
 * four-word headline; these two run to a sentence, and 13ch turns a sentence
 * into a column.
 */
.tmh-lp-hero h1 { max-width: 22ch; }

/* -------------------------------------------------- trimmed footer  */

/*
 * One column, because there is no sitemap to lay out — a landing page's
 * footer carries the contact details and the terms and nothing to click
 * away to. `.tmh-footer` would otherwise hold a four-track grid open for a
 * single block.
 */
.tmh-lp-footer { padding-top: var(--space-16); }
.tmh-lp-footer .tmh-contact { max-width: 22rem; }
.tmh-lp-footer__policy { margin: var(--space-8) 0 0; max-width: 44rem; }

/* ------------------------------------------------------ client clip  */

/*
 * The couples clip. Filmed on a phone, so it is portrait, which is the
 * silhouette `.tmh-figure` already cuts — the video carries that class and
 * needs nothing of its own but a clipped corner radius, since a poster
 * painted by the element itself ignores the border-radius without it.
 *
 * It does not autoplay. The file is 4MB, on a page whose first job is to
 * load fast for paid traffic, so `preload="none"` means it costs nothing at
 * all until someone presses play.
 */
.tmh-lp-clip { margin: 0; }
.tmh-lp-clip video {
  overflow: hidden;
  background: var(--color-surface-soft);
}
.tmh-lp-clip figcaption {
  margin-top: var(--space-3);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/* -------------------------------------------- awaiting client assets  */

/*
 * The frame that stands where a client photo or video will go. Dashed and
 * labelled deliberately: an empty box that looks finished is a box that
 * ships. Each one is a single element to swap for an <img> or a <video>.
 */
.tmh-lp-slot {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-2);
  padding: var(--space-4);
  text-align: center;

  background: var(--color-surface-soft);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
}
.tmh-lp-slot__label {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--color-text-muted);
}
.tmh-lp-slot__what {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--color-text);
}

/* ------------------------------------------------- before & after  */

.tmh-lp-gallery {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

.tmh-lp-ba { margin: 0; }

/* Before beside after, never one without the other — the pairing is what
   makes the comparison a comparison. */
.tmh-lp-ba__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
}
/*
 * Half of a 320px screen is not enough to hold the word "Placeholder" at
 * label tracking, so on these frames it moves to the caption and each half
 * carries only which side it is.
 */
.tmh-lp-ba__pair .tmh-lp-slot { aspect-ratio: 3 / 4; }
.tmh-lp-ba figcaption {
  margin-top: var(--space-3);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* ---------------------------------------------------- video reviews  */

.tmh-lp-videos {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  max-width: 46rem;
}

.tmh-lp-video { display: flex; flex-direction: column; gap: var(--space-4); }
/* Portrait, because a review filmed on a phone is portrait. */
.tmh-lp-video .tmh-lp-slot { aspect-ratio: 4 / 5; }
.tmh-lp-video__who {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.tmh-lp-video__name {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--color-text);
}

/* ================================================== design-system patches  */

/*
 * `.section--dark` recolours headings and the eyebrow but leaves `.text-muted`
 * at --ink-60 — dark brown at 60% on a dark brown ground, which is invisible.
 * It first bit the lead paragraph in the Craftsmanship nails band.
 *
 * This belongs in design-system.css; it lives here until it goes upstream.
 */
.section--dark .text-muted {
  color: color-mix(in srgb, var(--color-text-inverse) 72%, transparent);
}

/*
 * `.grid--2` is `auto-fit, minmax(20rem, 1fr)`, which resolves to *three*
 * columns inside the 73.5rem container — so four cards land 3 + 1. Where a
 * design asks for two across, say two across.
 */
@media (min-width: 64rem) {
  .tmh-pairs { grid-template-columns: repeat(2, 1fr); }
}
