/* ==========================================================================
   Stylez By Gary — site styles
   Mobile-first. Navy (#0D2854, sampled from the logo) + white.
   Sections in source order: tokens, reset, layout, buttons, header, footer,
   hero, cards, services, reviews, gallery, booking, contact, utilities.
   ========================================================================== */

/* --------------------------------------------------------------- Tokens -- */
:root {
  /* Brand */
  --navy: #0D2854;          /* exact navy from Gary-Logo.png */
  --navy-dark: #081B3A;
  --navy-mid: #1B4079;      /* lighter royal blue, for links + accents */
  --navy-tint: #F3F6FB;     /* barely-there navy wash for alternating bands */

  /* Text */
  --ink: #0F1B2D;          /* 15.8:1 on white */
  --body: #4B5768;         /*  7.3:1 on white */
  --muted: #5E6A80;        /*  5.5:1 on white, 5.0:1 on --navy-tint.
                              Was #77839A, which measured 3.8:1 and failed. */
  --gold: #B45309;         /*  5.0:1 on white. Star ratings. The usual bright
                              amber (#E8A020) measures 2.2:1. */
  --on-navy: #FFFFFF;
  --on-navy-soft: #C3D0E4;

  /* Surfaces */
  --white: #FFFFFF;
  --line: #E4E9F1;         /* hairline dividers - decorative, not a control */
  --line-strong: #CBD5E5;
  --border-control: #7C8FAD; /* 3.3:1 on white. Outlines of real controls
                              (secondary buttons) need 3:1 to read as controls. */

  /* Focus ring. The navy ring is invisible on navy, so dark surfaces
     override it with white further down. */
  --focus: var(--navy-mid);
  --focus-on-dark: #FFFFFF;

  /* Shape */
  --radius: 12px;
  --radius-lg: 18px;
  --shadow-sm: 0 1px 2px rgba(13, 40, 84, .06);
  --shadow: 0 6px 24px rgba(13, 40, 84, .08);
  --shadow-lg: 0 18px 48px rgba(13, 40, 84, .12);

  /* Rhythm */
  --wrap: 1120px;
  --wrap-narrow: 760px;
  --gutter: 20px;
  --section-y: 64px;

  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

@media (min-width: 768px) {
  :root { --gutter: 32px; --section-y: 96px; }
}

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

/* No CSS scroll-behavior: ScrollTrigger reads scroll position directly and
   native smooth scrolling can desync it. animations.js does anchor scrolling
   with scrollIntoView instead, so reduced-motion can opt out explicitly. */
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  color: var(--body);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Sticky header must not cover in-page anchor targets (#booking, #reviews). */
[id] { scroll-margin-top: 90px; }

h1, h2, h3, h4 {
  margin: 0 0 .5em;
  color: var(--ink);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -.02em;
}

h1 { font-size: clamp(2.1rem, 6.2vw, 3.5rem); }
h2 { font-size: clamp(1.65rem, 4.2vw, 2.4rem); }
h3 { font-size: 1.3rem; letter-spacing: -.01em; }   /* 20.8px vs 17px body */

p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

a { color: var(--navy-mid); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--navy); }

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

ul, ol { margin: 0 0 1.1em; padding-left: 1.2em; }

hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: 4px;
}

/* A navy ring on a navy background measures 1.4:1 - effectively invisible.
   Dark surfaces get a white ring instead. */
.section--navy :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--focus-on-dark);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

/* --------------------------------------------------------------- Layout -- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap--narrow { max-width: var(--wrap-narrow); }

.section { padding-block: var(--section-y); }
.section--tint { background: var(--navy-tint); }
.section--navy { background: var(--navy); color: var(--on-navy-soft); }
.section--navy h2, .section--navy h3 { color: var(--on-navy); }

.section-head { max-width: 620px; margin-bottom: 40px; }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head p { font-size: 1.05rem; }
.section-head p:last-child { margin-bottom: 0; }

.eyebrow {
  display: block;
  margin-bottom: 14px;
  color: var(--navy-mid);
  font-size: .875rem;      /* 14px floor; was .78rem = 12.5px */
  font-weight: 600;
  letter-spacing: .16em;   /* echoes the "BY GARY" lockup */
  text-transform: uppercase;
}

.section--navy .eyebrow { color: var(--on-navy-soft); }

.lede { font-size: 1.1rem; color: var(--body); }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  padding: 12px 20px;
  background: var(--navy);
  color: var(--white);
  font-weight: 600;
}
.skip-link:focus { left: 8px; top: 8px; color: var(--white); }

/* -------------------------------------------------------------- Buttons -- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 50px;             /* exceeds the 44px minimum target */
  min-width: 44px;
  padding: 13px 26px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  font: inherit;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .18s ease, color .18s ease,
              border-color .18s ease, transform .18s ease;
}
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--navy); border-color: var(--navy); color: var(--white); }
.btn--primary:hover { background: var(--navy-dark); border-color: var(--navy-dark); color: var(--white); }

.btn--ghost { background: transparent; border-color: var(--border-control); color: var(--navy); }
.btn--ghost:hover { border-color: var(--navy); background: var(--navy-tint); color: var(--navy); }

.btn--light { background: var(--white); border-color: var(--white); color: var(--navy); }
.btn--light:hover { background: var(--on-navy-soft); border-color: var(--on-navy-soft); color: var(--navy-dark); }

.btn--outline-light { background: transparent; border-color: rgba(255,255,255,.45); color: var(--white); }
.btn--outline-light:hover { border-color: var(--white); background: rgba(255,255,255,.1); color: var(--white); }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; }
.btn-row--center { justify-content: center; }

.btn .icon { width: 18px; height: 18px; flex: none; }

/* --------------------------------------------------------------- Header -- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}

/* One flex row on desktop; on mobile the nav wraps to a full-width second
   line that stays hidden until the toggle opens it. */
.site-header__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 72px;
}

.brand {
  display: inline-flex;
  align-items: center;
  flex: none;
  min-height: 44px;   /* the 40px logo alone left a 40px-tall target */
}
/* Horizontal lockup, 4.39:1 — 40px tall is ~176px wide, which still leaves
   room for the toggle on a 320px screen. */
.brand img { height: 40px; width: auto; }

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-right: -8px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: var(--radius);
  color: var(--navy);
  font: inherit;      /* otherwise the visually-hidden label inherits 13px */
  cursor: pointer;
}
.nav-toggle:hover { background: var(--navy-tint); }

/* The two icons are stacked on top of each other and cross-faded, rather than
   swapped with display:none — display cannot be transitioned, so the old swap
   was necessarily instant. Centring uses negative margins, not a translate,
   so the rotate below has the transform property to itself. Both SVGs are
   aria-hidden; the button's name comes from its visually-hidden "Menu" span,
   so having both in the DOM at once changes nothing for assistive tech. */
.nav-toggle { position: relative; }
.nav-toggle .icon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px;
  transition: opacity .22s ease, transform .28s cubic-bezier(.2, .7, .3, 1);
}
.nav-toggle .icon--menu  { opacity: 1; transform: rotate(0deg); }
.nav-toggle .icon--close { opacity: 0; transform: rotate(-90deg); }
.site-header[data-nav-open="true"] .nav-toggle .icon--menu  { opacity: 0; transform: rotate(90deg); }
.site-header[data-nav-open="true"] .nav-toggle .icon--close { opacity: 1; transform: rotate(0deg); }

/* Mobile: collapsed panel below the bar.
   Still display:none when closed — that genuinely removes the links from the
   tab order, which opacity/visibility alone would not do reliably. The open
   state animates with @keyframes rather than a transition, because a
   transition cannot run off a display change. Closing is instant by design:
   the ask was an OPEN animation, and animating a close means keeping the
   panel around after the click, which is what makes menus feel laggy. */
.site-nav {
  display: none;
  flex-basis: 100%;
  padding-bottom: 24px;
}
.site-header[data-nav-open="true"] .site-nav { display: block; }

@media (max-width: 899.98px) {
  .site-header[data-nav-open="true"] .site-nav {
    animation: nav-panel-in .3s cubic-bezier(.2, .7, .3, 1) both;
  }

  /* Each row arrives just behind the one above it. The delays are short
     enough that the whole set has landed in ~0.25s — long enough to read as
     deliberate, short enough that nobody waits for the menu. */
  .site-header[data-nav-open="true"] .site-nav__list li,
  .site-header[data-nav-open="true"] .site-nav > .btn {
    animation: nav-item-in .34s cubic-bezier(.2, .7, .3, 1) both;
  }
  .site-header[data-nav-open="true"] .site-nav__list li:nth-child(1) { animation-delay: .04s; }
  .site-header[data-nav-open="true"] .site-nav__list li:nth-child(2) { animation-delay: .08s; }
  .site-header[data-nav-open="true"] .site-nav__list li:nth-child(3) { animation-delay: .12s; }
  .site-header[data-nav-open="true"] .site-nav__list li:nth-child(4) { animation-delay: .16s; }
  .site-header[data-nav-open="true"] .site-nav > .btn { animation-delay: .2s; }
}

@keyframes nav-panel-in {
  from { opacity: 0; transform: translateY(-10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes nav-item-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

/* Must come after the rules above — same specificity, so source order decides.
   Reduced motion drops the movement entirely rather than shortening it: the
   panel and every row appear at once, and the icon swaps instantly. */
@media (prefers-reduced-motion: reduce) {
  .nav-toggle .icon { transition: none; }
  .site-header[data-nav-open="true"] .site-nav,
  .site-header[data-nav-open="true"] .site-nav__list li,
  .site-header[data-nav-open="true"] .site-nav > .btn {
    animation: none;
  }
}

.site-nav__list {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  border-top: 1px solid var(--line);
}
.site-nav__list a {
  display: block;
  padding: 14px 2px;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  font-weight: 500;
  text-decoration: none;
}
.site-nav__list a:hover,
.site-nav__list a:focus-visible {
  color: var(--navy-mid);
  text-decoration: underline;   /* a cue that does not depend on colour */
  text-underline-offset: 4px;
}
.site-nav__list a[aria-current="page"] { color: var(--navy); font-weight: 600; }
.site-nav .btn { width: 100%; }

@media (min-width: 900px) {
  .site-header__bar { flex-wrap: nowrap; min-height: 84px; }
  .brand img { height: 46px; }
  .nav-toggle { display: none; }

  .site-nav {
    display: flex !important;   /* always visible on desktop */
    flex-basis: auto;
    align-items: center;
    gap: 34px;
    padding-bottom: 0;
  }
  .site-nav__list {
    display: flex;
    align-items: center;
    gap: 34px;
    margin: 0;
    border-top: 0;
  }
  .site-nav__list a {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 44px;      /* was 38px tall from padding alone */
    padding: 10px 4px;
    border-bottom: 0;
    font-size: .97rem;
  }
  .site-nav__list a[aria-current="page"]::after {
    content: "";
    position: absolute;
    left: 4px;
    right: 4px;
    bottom: 8px;           /* tracks the text, not the padded box */
    height: 2px;
    background: var(--navy);
  }
  .site-nav .btn { width: auto; min-height: 46px; padding: 11px 22px; }
}

/* --------------------------------------------------------------- Footer -- */
.site-footer {
  background: var(--navy);
  color: var(--on-navy-soft);
  padding-block: 56px 32px;
  font-size: .95rem;
}
/* Footer links were the same colour as the prose around them AND had no
   underline, so nothing at all marked them as links. Underlined by default;
   the padding brings each to a 44px target. */
.site-footer a {
  display: inline-block;
  padding: 11px 0;   /* 10px landed at 43.8px on the smaller footer-bottom type */
  color: var(--on-navy-soft);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.site-footer a:hover,
.site-footer a:focus-visible { color: var(--white); text-decoration-thickness: 2px; }

.site-footer__grid {
  display: grid;
  gap: 40px;
  margin-bottom: 40px;
}
@media (min-width: 700px) {
  .site-footer__grid { grid-template-columns: repeat(2, 1fr); gap: 40px 48px; }
}
@media (min-width: 1000px) {
  .site-footer__grid { grid-template-columns: 1.4fr 1fr 1.05fr 1fr; }
}

.site-footer__logo { height: 52px; width: auto; margin-bottom: 18px; }

.site-footer h3 {
  margin-bottom: 14px;
  color: var(--white);
  font-size: .875rem;     /* 14px floor; was .8rem = 12.8px */
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li + li { margin-top: 8px; }   /* keeps 8px clear between stacked targets */

/* The footer is the only place opening hours appear now that the contact page
   is gone, so they get a real table rather than a squashed one-liner. */
.footer-hours { width: 100%; border-collapse: collapse; font-size: .95rem; }
.footer-hours th,
.footer-hours td { padding: 4px 0; color: var(--on-navy-soft); font-weight: 400; }
.footer-hours th { text-align: left; }
.footer-hours td { text-align: right; white-space: nowrap; }

.site-footer__note {
  margin: 14px 0 0;
  color: var(--white);
  font-size: .95rem;
  font-weight: 600;
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  justify-content: space-between;
  padding-top: 24px;
  border-top: 1px solid rgba(255, 255, 255, .16);
  font-size: .9rem;       /* 14.4px; was .87rem = 13.9px */
  color: var(--on-navy-soft);
}

/* ----------------------------------------------------------------- Hero -- */
.hero { padding-block: 56px 64px; }
@media (min-width: 768px) { .hero { padding-block: 96px 104px; } }

.hero__inner { max-width: 780px; }
.hero h1 { margin-bottom: .35em; }
.hero__lede {
  max-width: 56ch;
  margin-bottom: 32px;
  font-size: clamp(1.05rem, 2.2vw, 1.2rem);
}
.hero .btn-row { margin-bottom: 32px; }

.hero__proof {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  font-size: .93rem;
  color: var(--muted);
}

/* ------------------------------------------------------- Cards & grids  -- */
.grid { display: grid; gap: 20px; }
@media (min-width: 640px) { .grid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 860px) {
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid { gap: 24px; }
}

.card {
  padding: 28px 24px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.card p:last-child { margin-bottom: 0; }
.card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: 18px;
  border-radius: 12px;
  background: var(--navy-tint);
  color: var(--navy);
}
.card__icon .icon { width: 22px; height: 22px; }

/* ------------------------------------------------------------- Services -- */
.service-list { list-style: none; margin: 0; padding: 0; }

.service-list li {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 18px 0;
  border-bottom: 1px solid var(--line);
}
.service-list li:first-child { border-top: 1px solid var(--line); }

.service-list__name { font-weight: 600; color: var(--ink); }
.service-list__desc { display: block; font-size: .92rem; font-weight: 400; color: var(--muted); }

.service-list__dots {
  flex: 1 1 auto;
  min-width: 12px;
  height: 1px;
  margin-bottom: 5px;
  border-bottom: 1px dotted var(--line-strong);
}

.service-list__price { flex: none; font-weight: 600; color: var(--navy); white-space: nowrap; }

.service-group + .service-group { margin-top: 52px; }
.service-group h2 { font-size: 1.5rem; }  /* subsection: below h2, above h3 */

/* -------------------------------------------------------------- Reviews -- */
/* Ratings summary under the section heading. Two sources named separately. */
.rating-badge {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 4px 14px;
  margin: 22px 0 0;
  font-size: 1rem;
  color: var(--body);
}
.rating-badge__item { display: inline-flex; align-items: baseline; gap: 5px; }
.rating-badge strong { color: var(--ink); font-size: 1.2rem; font-weight: 700; }
.rating-badge__star { color: var(--gold); }
.rating-badge__sep { color: var(--muted); }   /* --line-strong measured 1.5:1 */

/* Which platform a quote came from, above each grid. The letter mark is set in
   the site's own type on brand navy - deliberately not a facsimile of either
   company's logo. */
.review-source {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 52px 0 22px;
  color: var(--navy-mid);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.review-source:first-of-type { margin-top: 0; }

/* Was a navy tile holding a single letter ("Y" / "G"). It now holds the real
   Yelp and Google brand marks, so the tile is white: both logos are supplied
   in their own brand colours and neither is legible on navy. Fixed box + a
   fixed inner size keeps the two marks optically equal even though their
   artwork has different proportions — Google's G is square, the Yelp burst is
   slightly taller than wide. */
.review-source__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: var(--white);
  border: 1px solid var(--line-strong);
  letter-spacing: 0;
}

.review-source__mark .brand-mark {
  display: block;
  width: 16px;
  height: 16px;
}

/* Brand artwork is filled, not stroked — the shared .icon rule sets a stroke
   and no fill, which would erase these entirely. */
.brand-mark {
  fill: currentColor;
  stroke: none;
}
.brand-mark path,
.brand-mark g { stroke: none; }

/* Two columns, not four. Real review quotes run several sentences; across
   four columns each card became a ~200px ribbon of text with the short
   reviews stretched to match the longest one. Two columns keeps a readable
   measure and 4 cards land as a tidy 2x2. */
.reviews { display: grid; gap: 20px; }
@media (min-width: 640px) { .reviews { grid-template-columns: repeat(2, 1fr); } }
/* Exactly three Google quotes, and they run shorter than the Yelp ones, so a
   three-up row fills cleanly instead of leaving an orphan. */
@media (min-width: 900px) { .reviews--google { grid-template-columns: repeat(3, 1fr); } }

.review {
  display: flex;
  flex-direction: column;
  padding: 28px 24px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.stars {
  display: inline-flex;
  gap: 3px;
  margin-bottom: 16px;
  color: var(--gold);      /* warm gold reads as a rating, not as brand navy */
  font-size: 1rem;
  line-height: 1;
  letter-spacing: .08em;
}

.review blockquote {
  flex: 1 1 auto;
  margin: 0 0 20px;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1.6;
}

.review figcaption { font-size: .9rem; color: var(--muted); }
.review__name { display: block; font-weight: 600; color: var(--ink); }

.reviews-cta { margin-top: 36px; text-align: center; }
.reviews-cta p { font-size: .92rem; color: var(--muted); }

/* -------------------------------------------------------------- Gallery -- */
.gallery {
  display: grid;
  gap: 14px;
  grid-template-columns: 1fr;
  grid-auto-flow: dense;   /* backfills the gap a spanning tile would leave */
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (min-width: 560px) { .gallery { grid-template-columns: repeat(2, 1fr); gap: 18px; } }
@media (min-width: 900px) { .gallery { grid-template-columns: repeat(3, 1fr); } }

.gallery__item {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--navy-tint);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  /* Hover stays in CSS on purpose - GSAP is reserved for the load and scroll
     sequences. A transition handles this better than a tween would. */
  transition: box-shadow .3s ease;

  /* Do NOT stretch a photo tile to match a taller row-mate. The pair tile is
     544px tall where a 4:5 tile is 425px; stretching the square balayage shot
     into that height squeezed it to a 0.62 ratio and cover-cropped 38% of its
     width - clipping the hair, which is the whole point of the photo.
     Placeholders stretch instead (below): an empty box can absorb the
     raggedness, a photograph cannot. */
  align-self: start;
}

.gallery__item.is-empty { align-self: stretch; }

/* Shape comes from a padding-ratio spacer rather than `aspect-ratio`.
   aspect-ratio makes the height definite, which cancels the grid's default
   stretch; forcing height back caused the width to be derived from the height
   and overflow the column. A spacer sets a MINIMUM height while leaving the
   height itself auto, so a tile still stretches to match a taller row-mate. */
.gallery__item::before { content: ""; display: block; padding-top: 125%; }   /* 4:5 */

.gallery__item img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .3s ease;
}

/* Zoom the photo inside its frame rather than scaling the tile, so hovering
   one slot never overlaps its neighbours. */
.gallery__item:hover img,
.gallery__item:focus-within img { transform: scale(1.03); }
.gallery__item:hover,
.gallery__item:focus-within { box-shadow: var(--shadow); }

/* Nothing to zoom or lift while a slot is still a placeholder. */
.gallery__item.is-empty:hover { box-shadow: var(--shadow-sm); }

/* Must come after the :hover rules above - same specificity, so source order
   is what decides. Snapping instantly to a scaled state is still motion, so
   reduced motion drops the zoom entirely rather than just shortening it. */
@media (prefers-reduced-motion: reduce) {
  .gallery__item:hover img,
  .gallery__item:focus-within img { transform: none; }
}

/* A side-by-side before/after is landscape. Centre-cropping one into a 4:5
   tile cuts roughly a third of the width — which is exactly where the two
   faces are. This tile keeps the source ratio and spans two columns instead. */
.gallery__item--wide::before { padding-top: 82.76%; }   /* 348:288 */
@media (min-width: 560px) {
  .gallery__item--wide { grid-column: span 2; }
}

/* ------------------------------------------------- Before / after -- */
/* A before/after is one comparison, so it lives in one card rather than two
   tiles that merely sit next to each other. The pair tile spans two columns
   and holds both photos behind a single border, split by a hairline.
   78.12% = two 163x257 halves plus the 2px divider, so each half lands at
   almost exactly its source ratio and barely crops at all. */
.gallery__item--pair::before { padding-top: 78.12%; }
@media (min-width: 560px) {
  .gallery__item--pair { grid-column: span 2; }
}

.ba {
  position: absolute;
  inset: 0;
  display: flex;
  gap: 2px;
  background: var(--white);   /* shows through the gap as the divider */
}

.ba__half {
  position: relative;   /* containing block for the absolutely-filled img */
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  overflow: hidden;
}

/* Before/after labels are real text, never baked into the image files, so they
   stay translatable, selectable and legible at any zoom.
   A pill rather than a full-width band: it covers far less of the photo, which
   matters because the chin sits near the bottom edge of the men's "after" shot.
   The backdrop is a solid rgba rather than a gradient so the contrast ratio is
   an actual measurable number - 8.5:1 against the worst case (a white photo). */
.ba__label {
  position: absolute;
  bottom: 10px;
  left: 10px;
  padding: 6px 10px;
  border-radius: 999px;
  background: rgba(8, 27, 58, .82);
  color: var(--white);
  font-size: .875rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: .12em;   /* same label voice as .eyebrow */
  text-transform: uppercase;
  pointer-events: none;
}

/* The stitched collage is a single <img>; its seam was measured at 44%. */
.gallery__item--stitched .ba__label--stitch-right { left: calc(44% + 10px); }

/* Currently inert: inside the pair card each half is 0.638 and the sources are
   0.634, so cover crops 0px and there is nothing to reposition. Kept as a
   deliberate default - if the pair ratio is ever changed, these head-and-
   shoulders shots will bias toward the hair instead of centre-cropping it. */
.ba__half img { object-position: center 20%; }

/* Until the real photos are dropped into /gallery/, main.js flags each slot
   as empty so the grid reads as a deliberate placeholder, not a broken image. */
.gallery__item.is-empty img { display: none; }
.gallery__item.is-empty::after {
  content: "Photo coming soon";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  color: var(--muted);
  font-size: .875rem;      /* 14px floor; was .85rem = 13.6px */
  letter-spacing: .04em;
  text-align: center;
}

/* -------------------------------------------------------------- Booking -- */
.booking-panel {
  padding: 24px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
@media (min-width: 768px) { .booking-panel { padding: 32px; } }

/* The Vagaro embed replaces the contents of #booking-embed. min-height keeps
   the section from collapsing before the widget script loads. */
#booking-embed { min-height: 520px; }

.booking-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 520px;
  padding: 32px 24px;
  border: 2px dashed var(--line-strong);
  border-radius: var(--radius);
  text-align: center;
  color: var(--muted);
}
.booking-placeholder strong { color: var(--ink); font-size: 1.05rem; }
.booking-placeholder code {
  padding: 2px 6px;
  background: var(--navy-tint);
  border-radius: 5px;
  font-size: .85em;
  color: var(--navy);
}

/* ------------------------------------------------------------ Amenities -- */
.amenities {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 12px;
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
}

.amenities li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--navy-tint);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: .95rem;
  color: var(--body);
}

.amenities .icon { width: 16px; height: 16px; flex: none; color: var(--navy-mid); }

/* -------------------------------------------------------------- Contact -- */
.contact-grid { display: grid; gap: 40px; }
@media (min-width: 900px) { .contact-grid { grid-template-columns: 1fr 1fr; gap: 56px; } }

.detail-list { list-style: none; margin: 0; padding: 0; }
.detail-list > li {
  display: flex;
  gap: 16px;
  padding: 12px 0;    /* reduced: the links inside now carry their own padding */
  border-bottom: 1px solid var(--line);
}
.detail-list > li:first-child { border-top: 1px solid var(--line); }

.detail-list .icon { width: 20px; height: 20px; flex: none; margin-top: 4px; color: var(--navy-mid); }
.detail-list dt, .detail-list__label {
  display: block;   /* a bare <span> stayed inline, so the label sat on the
                       same line as its value and margin-bottom did nothing */
  margin-bottom: 2px;
  color: var(--ink);
  font-weight: 600;
  font-size: .95rem;
}
.detail-list a {
  display: inline-block;
  padding: 11px 0;    /* 20px-tall inline links -> 47px target */
  color: var(--navy-mid);
}

.hours { width: 100%; border-collapse: collapse; font-size: .97rem; }
.hours th, .hours td { padding: 11px 0; text-align: left; border-bottom: 1px solid var(--line); }
.hours th { font-weight: 500; color: var(--ink); }
.hours td { text-align: right; color: var(--body); white-space: nowrap; }
.hours tr:last-child th, .hours tr:last-child td { border-bottom: 0; }

/* ------------------------------------------------------------- CTA band -- */
.cta-band { text-align: center; }
.cta-band .wrap { max-width: 680px; }
.cta-band p { margin-bottom: 28px; font-size: 1.05rem; }

/* ------------------------------------------------------------ Utilities -- */
.icon { display: inline-block; vertical-align: middle; fill: none; stroke: currentColor;
        stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }

.visually-hidden {
  color: inherit;   /* never painted, but keeps it off contrast reports */
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.text-center { text-align: center; }
.mt-0 { margin-top: 0; }
.mt-24 { margin-top: 24px; }
.mt-32 { margin-top: 32px; }
.mt-40 { margin-top: 40px; }
.mb-0 { margin-bottom: 0; }

/* Comfortable reading measure for long-form copy and list-style menus. */
.measure { max-width: var(--wrap-narrow); }

.note { color: var(--muted); font-size: .95rem; }

/* A link inside running prose cannot be padded into a 44px block without
   wrecking the line spacing. Padding expands the clickable box; the matching
   negative margin cancels its effect on layout. */
.note a,
.rating-badge a,
.measure p a {
  /* 7px, not 2px: "Yelp" is only 34px of text, so 2px left it 38px wide -
     tall enough but too narrow. 7px clears 44px in both directions. */
  padding: 13px 7px;
  margin: -13px -7px;
}

/* ------------------------------------------------------- 404 / centered -- */
.centered-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding-block: 96px;
  min-height: 55vh;
}

/* ----------------------------------------------------------- Animation -- */
/* The `anim` class is added to <html> by a tiny inline script in each page's
   <head>, and ONLY when the visitor has not asked for reduced motion. Hiding
   these elements is therefore opt-in: if that script never runs, if the GSAP
   CDN is unreachable, or if reduced motion is set, nothing here applies and
   the page renders in its final state.
   A failsafe timer in the same inline script strips the class after 2s, so a
   slow or blocked CDN can never leave the page permanently blank.
   GSAP writes inline styles, which outrank these rules once it takes over. */
.anim [data-hero],
.anim [data-reveal],
.anim [data-reveal-children] > * {
  opacity: 0;
}


/* ------------------------------------------------------------------ *
   HEADSHOT PLACEHOLDER (About / Meet Gary)

   Deliberately a styled box, never an <img> pointing at a file that does
   not exist — a broken-image icon reads as a bug, this reads as a slot
   waiting to be filled. Same reasoning as the gallery placeholders, and it
   carries a visible label so it cannot ship unnoticed.
 * ------------------------------------------------------------------ */
.about-layout {
  display: grid;
  gap: 32px;
  align-items: start;
}

@media (min-width: 800px) {
  .about-layout {
    grid-template-columns: minmax(0, 260px) minmax(0, 1fr);
    gap: 48px;
  }
}

.headshot {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  max-width: 260px;
  margin: 0;
  padding: 24px;
  border: 1px dashed var(--border-control);
  border-radius: var(--radius);
  background: var(--navy-tint);
  color: var(--muted);
  text-align: center;
}

/* Portrait 4:5, the usual headshot crop. Same padding-ratio trick the gallery
   uses, for the same reason: it sets a minimum height without making the
   height definite. */
.headshot::before { content: ""; display: block; padding-top: 125%; }

.headshot__inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 24px;
}

/* Stroked, not filled. This SVG does not carry the shared .icon class, so
   without an explicit rule the paths default to a solid black fill. */
.headshot__avatar {
  width: 56px;
  height: 56px;
  color: var(--border-control);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.headshot__label {
  font-size: .9375rem;
  font-weight: 600;
  color: var(--body);
}

.headshot__note {
  margin: 0;
  font-size: .875rem;
  line-height: 1.45;
}
