/*
Theme Name: Glow by Phoebe
Theme URI: https://test.kingslandsolutions.com/
Description: Photography-led child theme for Glow by Phoebe Med Spa. Design system, header/footer and page components.
Author: Davidoff Media
Template: twentytwentyfive
Version: 1.0.2
Text Domain: glow-child
*/

/* ============================================================
   1. DESIGN TOKENS
   ============================================================ */
:root{
  --c-tint-3:#fdeff2;
  --c-tint-2:#fdecf0;
  --c-tint-1:#fde1e7;
  --c-accent:#f0a6b6;
  --c-mid:#6b616e;
  --c-ink:#332928;
  --c-white:#fff;
  --c-error:#a8322d;
  --c-success:#2c5f45;

  --f-display:"Playfair Display",Georgia,"Times New Roman",serif;
  --f-script:"Great Vibes","Playfair Display",cursive;
  --f-ui:"Montserrat",system-ui,-apple-system,"Segoe UI",sans-serif;

  --t-h1:52px; --t-h2:36px; --t-h3:23px; --t-body:16px; --t-label:12px;
  --lh-head:1.15; --lh-body:1.7;

  --content:1180px;
  --gutter:28px;
  --radius-pill:100px;
  --radius-card:0;
  --space-band:110px;
  --shadow-card:0 18px 44px -28px rgba(51,41,40,.34);
}
@media (max-width:1024px){
  :root{ --t-h1:36px; --t-h2:28px; --t-h3:21px; --space-band:76px; --gutter:24px; }
}
@media (max-width:767px){
  :root{ --t-h1:29px; --t-h2:24px; --t-h3:20px; --t-body:16px; --space-band:60px; --gutter:20px; }
}

html,body{ overflow-x:hidden; }
body{
  font-family:var(--f-ui);
  font-size:var(--t-body);
  line-height:var(--lh-body);
  color:var(--c-ink);
  background:var(--c-white);
  -webkit-font-smoothing:antialiased;
}
img{ max-width:100%; height:auto; display:block; }

/* Kill Twenty Twenty-Five's duplicate page title */
body.page .wp-block-post-title,
body.home .wp-block-post-title{ display:none; }

/* ============================================================
   2. TYPE
   ============================================================ */
h1,h2,h3,h4,.gp-display{ font-family:var(--f-display); font-weight:400; line-height:var(--lh-head); color:var(--c-ink); letter-spacing:-.01em; }
h1{ font-size:var(--t-h1); }
h2{ font-size:var(--t-h2); }
h3{ font-size:var(--t-h3); }

.gp-eyebrow{
  font-family:var(--f-ui); font-size:var(--t-label); font-weight:600;
  letter-spacing:.22em; text-transform:uppercase; color:var(--c-mid);
  margin:0 0 14px;
}
.gp-lead{ font-size:18px; line-height:1.65; color:var(--c-mid); max-width:62ch; }
.gp-rule{ display:block; width:56px; height:1px; background:var(--c-accent); margin:18px 0 26px; }
.gp-center .gp-rule, .gp-band--center .gp-rule{ margin-inline:auto; }
.gp-price{ font-family:var(--f-display); font-size:22px; color:var(--c-ink); }
.gp-price small{ font-family:var(--f-ui); font-size:12px; letter-spacing:.1em; text-transform:uppercase; color:var(--c-mid); display:block; margin-top:2px; }

/* ============================================================
   3. BUTTONS
   ============================================================ */
.gp-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  font-family:var(--f-ui); font-size:var(--t-label); font-weight:600;
  letter-spacing:.16em; text-transform:uppercase; text-decoration:none;
  padding:16px 34px; min-height:50px; border-radius:var(--radius-pill);
  border:1px solid transparent; cursor:pointer;
  transition:background .18s ease,color .18s ease,border-color .18s ease,transform .12s ease;
}
.gp-btn--primary{ background:var(--c-mid); color:var(--c-white); }
.gp-btn--primary:hover{ background:var(--c-ink); color:var(--c-white); }
.gp-btn--ghost{ background:transparent; color:var(--c-ink); border-color:var(--c-ink); }
.gp-btn--ghost:hover{ background:var(--c-ink); color:var(--c-white); }
.gp-btn--light{ background:var(--c-white); color:var(--c-ink); }
.gp-btn--light:hover{ background:var(--c-tint-1); }
.gp-btn--outline-light{ background:transparent; color:var(--c-white); border-color:rgba(255,255,255,.75); }
.gp-btn--outline-light:hover{ background:var(--c-white); color:var(--c-ink); }
.gp-btn:active{ transform:translateY(1px); }
.gp-btns{ display:flex; flex-wrap:wrap; gap:14px; margin-top:30px; }

/* ============================================================
   4. FULL-BLEED BANDS
   ============================================================ */
.gp-band,.gp-hero,.gp-photoband{
  /* These sit directly in a flow-layout <main>, so they already span the
     full width. Do not reintroduce 100vw here: it includes the scrollbar
     and pushes the page ~15px wide on Windows. */
  box-sizing:border-box;
}
.gp-band{ padding:var(--space-band) var(--gutter); background:var(--c-white); }
.gp-band__inner{ max-width:var(--content); margin-inline:auto; }
.gp-band--tint{ background:var(--c-tint-3); }
.gp-band--tint2{ background:var(--c-tint-2); }
.gp-band--deep{ background:var(--c-tint-1); }
.gp-band--ink{ background:var(--c-mid); }
.gp-band--ink :is(h1,h2,h3,h4,p,li,.gp-eyebrow,.gp-lead){ color:var(--c-white); }
.gp-band--ink .gp-eyebrow,.gp-band--ink .gp-lead{ color:rgba(255,255,255,.82); }
.gp-band--ink .gp-rule{ background:rgba(255,255,255,.5); }
.gp-band--center{ text-align:center; }
.gp-band--center .gp-lead{ margin-inline:auto; }
.gp-band__head{ max-width:720px; margin:0 0 52px; }
.gp-band--center .gp-band__head{ margin-inline:auto; }

/* ============================================================
   5. HERO — photography led
   ============================================================ */
.gp-hero{
  position:relative; display:flex; align-items:flex-end;
  min-height:min(86vh,760px);
  padding:0 var(--gutter) clamp(56px,7vw,96px);
  background:var(--c-ink) center/cover no-repeat;
  isolation:isolate; overflow:hidden;
}
.gp-hero__media{ position:absolute; inset:0; z-index:-2; }
.gp-hero__media img,.gp-hero__media video{
  width:100%; height:100%; object-fit:cover; object-position:center 28%;
}
.gp-hero::after{
  content:""; position:absolute; inset:0; z-index:-1;
  background:linear-gradient(105deg,rgba(37,29,32,.74) 0%,rgba(37,29,32,.5) 42%,rgba(37,29,32,.12) 72%,rgba(37,29,32,0) 100%);
}
.gp-hero__inner{ position:relative; max-width:var(--content); width:100%; margin-inline:auto; }
.gp-hero__copy{ max-width:620px; }
.gp-hero :is(h1,p,.gp-eyebrow){ color:var(--c-white); }
.gp-hero .gp-eyebrow{ color:rgba(255,255,255,.86); }
.gp-hero h1{ margin:0 0 20px; text-shadow:0 2px 26px rgba(0,0,0,.28); }
.gp-hero__lead{ font-size:18px; line-height:1.62; color:rgba(255,255,255,.93); max-width:52ch; margin:0; }
.gp-hero .gp-rule{ background:var(--c-accent); }
.gp-hero--short{ min-height:min(58vh,480px); }
@media (max-width:767px){
  .gp-hero{ min-height:70vh; align-items:flex-end; }
  .gp-hero::after{ background:linear-gradient(to top,rgba(37,29,32,.82) 0%,rgba(37,29,32,.5) 55%,rgba(37,29,32,.24) 100%); }
  .gp-hero__lead{ font-size:16px; }
}

/* ============================================================
   6. CARDS — image on top, equal height
   ============================================================ */
.gp-cards{ display:grid; gap:30px; grid-template-columns:repeat(3,1fr); }
.gp-cards--2{ grid-template-columns:repeat(2,1fr); }
.gp-cards--4{ grid-template-columns:repeat(4,1fr); }
@media (max-width:1024px){ .gp-cards,.gp-cards--4{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:640px){ .gp-cards,.gp-cards--2,.gp-cards--4{ grid-template-columns:1fr; } }

.gp-card{
  display:flex; flex-direction:column; height:100%;
  background:var(--c-white); border:1px solid var(--c-tint-1);
  border-radius:var(--radius-card); overflow:hidden;
  transition:box-shadow .22s ease,transform .22s ease,border-color .22s ease;
}
.gp-card:hover{ box-shadow:var(--shadow-card); transform:translateY(-3px); border-color:var(--c-accent); }
.gp-card__media{ position:relative; aspect-ratio:4/3; overflow:hidden; background:var(--c-tint-2); }
.gp-card__media img{ width:100%; height:100%; object-fit:cover; transition:transform .5s ease; }
.gp-card:hover .gp-card__media img{ transform:scale(1.04); }
.gp-card__body{ display:flex; flex-direction:column; flex:1 1 auto; padding:28px 26px 30px; }
.gp-card__body h3{ margin:0 0 12px; }
.gp-card :is(p,li){ color:var(--c-ink); font-size:15px; margin:0 0 14px; }
.gp-card__foot{ margin-top:auto; padding-top:18px; display:flex; align-items:center; justify-content:space-between; gap:14px; flex-wrap:wrap; }
.gp-card__link{
  font-family:var(--f-ui); font-size:var(--t-label); font-weight:600;
  letter-spacing:.16em; text-transform:uppercase; text-decoration:none;
  color:var(--c-mid); border-bottom:1px solid var(--c-accent); padding-bottom:3px;
}
.gp-card__link:hover{ color:var(--c-ink); border-color:var(--c-ink); }

/* Plain (no photo) card, for FAQ / value tiles */
.gp-tile{ background:var(--c-white); border:1px solid var(--c-tint-1); padding:32px 28px; height:100%; }
.gp-band--tint .gp-tile,.gp-band--tint2 .gp-tile{ background:var(--c-white); }
.gp-tile h3{ margin:0 0 10px; }
.gp-tile p{ margin:0; color:var(--c-ink); font-size:15px; }
.gp-tile__num{ font-family:var(--f-display); font-size:34px; color:var(--c-accent); display:block; margin-bottom:8px; }

/* ============================================================
   7. SPLIT — image beside text
   ============================================================ */
.gp-split{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(36px,5vw,76px); align-items:center; }
.gp-split--narrow-media{ grid-template-columns:5fr 6fr; }
.gp-split__media{ position:relative; }
.gp-split__media img{ width:100%; height:100%; object-fit:cover; }
.gp-split__media--tall img{ aspect-ratio:4/5; }
.gp-split--flip .gp-split__media{ order:2; }
@media (max-width:900px){
  .gp-split,.gp-split--narrow-media{ grid-template-columns:1fr; gap:34px; }
  .gp-split--flip .gp-split__media{ order:0; }
}
.gp-split__media::after{
  content:""; position:absolute; inset:auto -14px -14px auto;
  width:52%; height:46%; border:1px solid var(--c-accent); z-index:-1;
}
.gp-split__body h2{ margin:0 0 4px; }

/* ============================================================
   8. PHOTO CTA BAND
   ============================================================ */
.gp-photoband{
  position:relative; display:flex; align-items:center; justify-content:center;
  min-height:420px; padding:var(--space-band) var(--gutter);
  text-align:center; background:var(--c-ink) center/cover no-repeat;
  isolation:isolate; overflow:hidden;
}
.gp-photoband__media{ position:absolute; inset:0; z-index:-2; }
.gp-photoband__media img{ width:100%; height:100%; object-fit:cover; }
.gp-photoband::after{ content:""; position:absolute; inset:0; z-index:-1; background:rgba(37,29,32,.56); }
.gp-photoband__inner{ position:relative; max-width:720px; }
.gp-photoband :is(h2,p,.gp-eyebrow){ color:var(--c-white); }
.gp-photoband .gp-eyebrow{ color:rgba(255,255,255,.84); }
.gp-photoband p{ color:rgba(255,255,255,.92); font-size:17px; }
.gp-photoband .gp-rule{ background:var(--c-accent); margin-inline:auto; }
.gp-photoband .gp-btns{ justify-content:center; }

/* ============================================================
   9. BEFORE / AFTER GRID
   ============================================================ */
.gp-ba{ display:grid; gap:26px; grid-template-columns:repeat(4,1fr); }
@media (max-width:1024px){ .gp-ba{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:520px){ .gp-ba{ grid-template-columns:1fr; } }
.gp-ba__item{ background:var(--c-tint-3); border:1px solid var(--c-tint-1); }
.gp-ba__item img{ width:100%; aspect-ratio:4/5; object-fit:contain; background:var(--c-tint-3); }
.gp-ba__cap{
  font-family:var(--f-ui); font-size:12px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--c-mid); padding:14px 16px; margin:0; border-top:1px solid var(--c-tint-1);
  background:var(--c-white);
}
.gp-note{ font-size:13px; color:var(--c-mid); margin-top:26px; }

/* ============================================================
   10. HEADER
   ============================================================ */
.gp-topbar{
  background:var(--c-mid); color:var(--c-white);
  font-family:var(--f-ui); font-size:12px; letter-spacing:.1em; text-transform:uppercase;
  text-align:center; padding:11px var(--gutter);
}
.gp-topbar a{ color:var(--c-white); text-decoration:underline; text-underline-offset:3px; }

.gp-header{ background:var(--c-white); border-bottom:1px solid var(--c-tint-1); position:relative; z-index:20; }
.gp-header__bar{
  max-width:var(--content); margin-inline:auto; padding:20px var(--gutter);
  display:flex; align-items:center; justify-content:space-between; gap:28px;
}
.gp-wordmark{ text-decoration:none; display:block; line-height:1; flex:0 0 auto; }
.gp-wordmark__script{
  font-family:var(--f-script); font-size:44px; color:var(--c-mid);
  display:block; line-height:1;
}
.gp-wordmark__sub{
  font-family:var(--f-ui); font-size:9.5px; font-weight:600;
  letter-spacing:.34em; text-transform:uppercase; color:var(--c-ink);
  display:block; margin-top:5px; padding-left:3px;
}
.gp-nav{ display:flex; align-items:center; gap:30px; flex-wrap:wrap; justify-content:flex-end; }
.gp-nav a{
  font-family:var(--f-ui); font-size:12px; font-weight:600;
  letter-spacing:.13em; text-transform:uppercase; text-decoration:none;
  color:var(--c-ink); padding:6px 0; border-bottom:1px solid transparent;
}
.gp-nav a:hover{ border-color:var(--c-accent); }
.gp-nav__cta{ margin-left:6px; }
@media (max-width:1100px){ .gp-nav{ gap:20px; } .gp-nav a{ font-size:11px; letter-spacing:.1em; } }
@media (max-width:900px){
  .gp-header__bar{ flex-direction:column; align-items:center; gap:16px; padding:18px var(--gutter); }
  .gp-nav{ justify-content:center; gap:16px 18px; }
  .gp-wordmark{ text-align:center; }
  .gp-wordmark__script{ font-size:38px; }
}

/* ============================================================
   11. FOOTER
   ============================================================ */
/* The footer takes the topbar's mauve rather than the near-black
   --c-ink, so the two ends of the page are the same colour. That
   ground is a good deal lighter, so the white text alphas below are
   lifted to hold their contrast against it. */
.gp-footer{ background:var(--c-mid); color:rgba(255,255,255,.9); padding:76px var(--gutter) 34px; }
.gp-footer__inner{ max-width:var(--content); margin-inline:auto; }
.gp-footer__cols{ display:grid; grid-template-columns:1.4fr 1fr 1fr 1.1fr; gap:44px; }
@media (max-width:900px){ .gp-footer__cols{ grid-template-columns:1fr 1fr; gap:34px; } }
@media (max-width:560px){ .gp-footer__cols{ grid-template-columns:1fr; } }
.gp-footer h4{
  font-family:var(--f-ui); font-size:11px; font-weight:600; letter-spacing:.22em;
  text-transform:uppercase; color:var(--c-accent); margin:0 0 18px;
}
.gp-footer ul{ list-style:none; margin:0; padding:0; }
.gp-footer li{ margin:0 0 10px; }
.gp-footer a{ color:rgba(255,255,255,.9); text-decoration:none; font-size:14px; }
.gp-footer a:hover{ color:var(--c-white); text-decoration:underline; text-underline-offset:3px; }
.gp-footer p{ font-size:14px; line-height:1.7; margin:0 0 12px; color:rgba(255,255,255,.85); }
.gp-footer .gp-wordmark__script{ color:var(--c-white); font-size:40px; }
.gp-footer .gp-wordmark__sub{ color:rgba(255,255,255,.8); }
.gp-footer__base{
  margin-top:56px; padding-top:24px; border-top:1px solid rgba(255,255,255,.24);
  display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap;
  font-size:12px; color:rgba(255,255,255,.78);
}
.gp-footer__dis{ font-size:12px; line-height:1.6; color:rgba(255,255,255,.72); max-width:70ch; margin-top:18px; }

/* ============================================================
   12. PRICING LIST
   ============================================================ */
.gp-pricing{ list-style:none; margin:0; padding:0; border-top:1px solid var(--c-tint-1); }
.gp-pricing li{
  display:flex; justify-content:space-between; align-items:baseline; gap:20px;
  padding:18px 0; border-bottom:1px solid var(--c-tint-1); margin:0;
}
.gp-pricing__name{ font-family:var(--f-display); font-size:18px; color:var(--c-ink); }
.gp-pricing__name span{ display:block; font-family:var(--f-ui); font-size:13px; color:var(--c-mid); margin-top:3px; }
.gp-pricing__amt{ font-family:var(--f-ui); font-size:15px; font-weight:600; letter-spacing:.04em; color:var(--c-ink); white-space:nowrap; text-align:right; }
.gp-pricing__amt small{ display:block; font-weight:500; font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--c-mid); margin-top:3px; }

/* ============================================================
   13. FAQ
   ============================================================ */
.gp-faq{ border-bottom:1px solid var(--c-tint-1); }
.gp-faq summary{
  cursor:pointer; list-style:none; padding:22px 40px 22px 0; position:relative;
  font-family:var(--f-display); font-size:19px; color:var(--c-ink);
}
.gp-faq summary::-webkit-details-marker{ display:none; }
.gp-faq summary::after{
  content:"+"; position:absolute; right:6px; top:50%; transform:translateY(-50%);
  font-family:var(--f-ui); font-size:22px; color:var(--c-accent); line-height:1;
}
.gp-faq[open] summary::after{ content:"\2013"; }
.gp-faq__a{ padding:0 0 24px; }
.gp-faq__a p{ margin:0 0 12px; font-size:15px; color:var(--c-ink); }

/* ============================================================
   14. BOOKING FORM (Contact Form 7)
   ============================================================ */
.gp-booking{ background:var(--c-white); border:1px solid var(--c-accent); padding:34px; }
.gp-band--tint .gp-booking,.gp-band--tint2 .gp-booking{ background:var(--c-white); }
@media (max-width:767px){ .gp-booking{ padding:24px 20px; } }
.gp-form-intro{ font-family:var(--f-display); font-size:var(--t-h3); line-height:var(--lh-head); color:var(--c-ink); margin:0 0 22px; }
.gp-form-grid{ display:grid; grid-template-columns:1fr 1fr; gap:16px; }
.gp-form-grid > p{ display:flex; flex-direction:column; gap:6px; margin:0; }
.gp-form-grid > p > .gp-field{ display:contents; }
.gp-form-grid > p:has(.gp-field--full),.gp-form-grid > .gp-field--full{ grid-column:1 / -1; }
@media (max-width:767px){ .gp-form-grid{ grid-template-columns:1fr; } .gp-form-grid > p:has(.gp-field--full){ grid-column:auto; } }
.gp-booking form p{ margin:0; }
.gp-booking form br{ display:none; }
.gp-field label{
  font-family:var(--f-ui); font-size:11px; font-weight:600; letter-spacing:.14em;
  text-transform:uppercase; color:var(--c-mid);
}
.gp-booking .wpcf7-form-control-wrap{ display:block; }
.gp-booking :is(input[type=text],input[type=tel],input[type=email],select,textarea){
  width:100%; box-sizing:border-box; font-family:var(--f-ui); font-size:16px; line-height:1.4;
  color:var(--c-ink); background:var(--c-white); border:1px solid var(--c-tint-1);
  border-radius:0; padding:13px 14px; min-height:48px; appearance:none;
  transition:border-color .15s ease,box-shadow .15s ease;
}
.gp-booking textarea{ min-height:96px; resize:vertical; }
.gp-booking select{
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%236b616e' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 14px center; background-size:12px 8px;
  padding-right:40px; cursor:pointer;
}
.gp-booking :is(input,select,textarea):focus-visible{
  outline:none; border-color:var(--c-mid); box-shadow:0 0 0 3px rgba(107,97,110,.2);
}
.gp-booking ::placeholder{ color:var(--c-mid); opacity:.5; }
.gp-submit{ margin:24px 0 0; }
.gp-booking input[type=submit]{
  font-family:var(--f-ui); font-size:var(--t-label); font-weight:600; letter-spacing:.16em;
  text-transform:uppercase; color:var(--c-white); background:var(--c-mid); border:0;
  border-radius:var(--radius-pill); padding:16px 34px; min-height:50px; width:100%;
  cursor:pointer; transition:background .18s ease;
}
@media (min-width:768px){ .gp-booking input[type=submit]{ width:auto; min-width:280px; } }
.gp-booking input[type=submit]:hover{ background:var(--c-ink); }
.gp-form-fineprint{ font-family:var(--f-ui); font-size:12px; line-height:1.5; color:var(--c-mid); margin:14px 0 0; }
.gp-booking .wpcf7-not-valid{ border-color:var(--c-error) !important; }
.gp-booking .wpcf7-not-valid-tip{ font-size:12.5px; color:var(--c-error); margin-top:5px; }
.gp-booking .wpcf7-response-output{
  font-family:var(--f-ui); font-size:14px; line-height:1.5;
  margin:20px 0 0 !important; padding:14px 16px !important;
  border:1px solid currentColor !important; border-radius:0;
}
.gp-booking form.sent .wpcf7-response-output{ color:var(--c-success); }
.gp-booking form:is(.invalid,.unaccepted,.failed,.spam) .wpcf7-response-output{ color:var(--c-error); }

/* Split service hero: copy left, form right */
.gp-servicetop{ display:grid; grid-template-columns:1fr minmax(400px,44%); gap:clamp(32px,4vw,60px); align-items:start; }
@media (max-width:960px){ .gp-servicetop{ grid-template-columns:1fr; gap:34px; } }

@media (prefers-reduced-motion:reduce){ *{ transition:none !important; animation:none !important; } }

/* ============================================================
   15. LAYOUT CORRECTIONS

   templates/page.html uses a FLOW layout for <main> and post-content
   (layout:default, not constrained). Two things forced that:

   1. WP's constrained-layout rule sets margin-left/right:auto !important
      on every child, which beat any full-bleed rule on specificity alone.
   2. post-content was itself capped at contentSize and centred, so a child
      could not reach the viewport edge by cancelling root padding — the
      offset was (root padding + half the leftover), which changes with
      viewport width.

   In flow layout the bands simply fill <main>, and each one applies its
   own gutter with .gp-band__inner capping the readable column. No negative
   margins, no 100vw, no scrollbar overflow.
   ============================================================ */
.gp-main, .gp-main > .wp-block-post-content{ padding-left:0; padding-right:0; max-width:none; }
.gp-band, .gp-hero, .gp-photoband{ width:auto; max-width:none; margin-left:0; margin-right:0; }

/* Any ordinary block added in the editor later still gets a readable
   column instead of running edge to edge. */
.gp-main > .wp-block-post-content > *:not(.gp-band):not(.gp-hero):not(.gp-photoband){
  max-width:var(--content);
  margin-inline:auto;
  padding-inline:var(--gutter);
}

/* Kept in case content is ever placed back inside a constrained container. */
.wp-block-post-content.is-layout-constrained > :is(.gp-band,.gp-hero,.gp-photoband){
  width:auto;
  max-width:none;
  margin-left:calc(var(--wp--style--root--padding-left,0px) * -1) !important;
  margin-right:calc(var(--wp--style--root--padding-right,0px) * -1) !important;
}

/* Buttons must never wrap or shrink. `.gp-nav a` is (0,1,1) and was beating
   `.gp-btn` (0,1,0) on padding and font-size, collapsing the CTA to a disc. */
.gp-btn{ white-space:nowrap; flex:0 0 auto; }
.gp-nav a.gp-btn{
  padding:14px 28px;
  font-size:var(--t-label);
  border-bottom:0;
  border-radius:var(--radius-pill);
}
.gp-nav a.gp-btn--primary{ color:var(--c-white); background:var(--c-mid); }
.gp-nav a.gp-btn--primary:hover{ background:var(--c-ink); border-color:transparent; }

/* Hero art direction: 16:9 crop on desktop, 4:5 crop on phones. */
.gp-hero__media .gp-img-mobile{ display:none; }
@media (max-width:767px){
  .gp-hero__media .gp-img-desktop{ display:none; }
  .gp-hero__media .gp-img-mobile{ display:block; }
}
.gp-hero__media img{ object-position:center 34%; }

/* Keep the topbar phone number from looking like body copy. */
.gp-topbar a{ font-weight:600; }

/* ============================================================
   16. FINAL POLISH
   ============================================================ */
/* Buttons inherit body line-height (1.7) and end up taller than the
   50px min-height intends. Pin it so every pill is the same height. */
.gp-btn{ line-height:1.2; }

/* On a phone the stacked header was eating ~190px before the hero.
   Tighten the wordmark, nav gaps and CTA so more of the hero is visible. */
@media (max-width:600px){
  .gp-topbar{ font-size:11px; padding:9px 16px; letter-spacing:.06em; }
  .gp-header__bar{ padding:14px var(--gutter) 16px; gap:12px; }
  .gp-wordmark__script{ font-size:34px; }
  .gp-wordmark__sub{ font-size:8.5px; letter-spacing:.28em; }
  .gp-nav{ gap:12px 16px; }
  .gp-nav a{ font-size:10.5px; letter-spacing:.09em; padding:3px 0; }
  .gp-nav a.gp-btn{ padding:12px 22px; min-height:42px; font-size:10.5px; }
  .gp-btns .gp-btn{ width:100%; }
}

/* Google Maps embed on the contact page. */
.gp-map{ border:1px solid var(--c-tint-1); background:var(--c-tint-3); line-height:0; }
.gp-map iframe{ display:block; width:100%; height:440px; border:0; }
@media (max-width:767px){ .gp-map iframe{ height:320px; } }

/* ══════════════════════════════════════════════════════════════════
   17. QA PASS — responsive fixes + type calibrated against the
   reference site (medifreda.com), measured at 768px and 1440px.

   Reference measurements:
     H1      Playfair 58.5px / 700 / line-height 1.0 / centred
     Subhead Playfair 23px  / 600 / line-height 2.2  / centred / mauve
     H3      Playfair 25px  / 500 / line-height 1.0
     Body    Montserrat 15px / 400 / line-height 1.6
     Buttons #6b616e, white, radius 100px, padding 8px 20px, 15px,
             uppercase, NO letter-spacing

   The single biggest visual gap was weight: every heading here was 400
   against their 500–700, which is why this site read thin next to theirs.
   ══════════════════════════════════════════════════════════════════ */

/* ---- 17.1 The box-sizing bug --------------------------------------
   .gp-btn had width:100% at ≤600px with 34px of horizontal padding and
   no border-box, so buttons rendered 405px wide inside a 375px viewport
   and were clipped at both edges by overflow-x:hidden. Global reset. */
*, *::before, *::after{ box-sizing:border-box; }

/* ---- 17.2 Heading weight and scale -------------------------------- */
:root{
  --t-h1:58px; --t-h2:38px; --t-h3:25px; --t-body:15px;
  --lh-head:1.05;
}
h1,.gp-display{ font-weight:700; letter-spacing:-.015em; }
h2{ font-weight:600; letter-spacing:-.01em; }
h3{ font-weight:500; letter-spacing:0; }
.gp-lead{ font-family:var(--f-display); font-weight:600; font-size:22px; line-height:1.9; color:var(--c-mid); }
.gp-hero__lead{ font-family:var(--f-ui); font-weight:400; font-size:17px; line-height:1.65; }
.gp-band__head h2{ margin-bottom:0; }
.gp-card__body h3, .gp-tile h3{ font-weight:500; line-height:1.25; }
.gp-form-intro{ font-weight:600; }

@media (max-width:1024px){
  :root{ --t-h1:46px; --t-h2:32px; --t-h3:23px; }
  .gp-lead{ font-size:20px; line-height:1.8; }
}
@media (max-width:767px){
  :root{ --t-h1:34px; --t-h2:26px; --t-h3:21px; --t-body:16px; }
  .gp-lead{ font-size:18px; line-height:1.7; }
  .gp-hero__lead{ font-size:16px; }
}

/* ---- 17.3 Buttons: match the reference proportions ---------------- */
.gp-btn{
  padding:13px 26px;
  min-height:46px;
  font-size:14px;
  font-weight:600;
  letter-spacing:.06em;
  line-height:1.2;
}
.gp-nav a.gp-btn{ padding:12px 24px; font-size:13px; min-height:44px; }
@media (max-width:767px){
  .gp-btn{ font-size:13px; padding:14px 24px; min-height:48px; }
}

/* ---- 17.4 Tap targets ---------------------------------------------
   Nav links were 25–32px and card links 24px. WCAG 2.5.8 wants 24px
   minimum; 44px is the practical target for a thumb. */
.gp-nav a{ min-height:44px; display:inline-flex; align-items:center; }
.gp-card__link{
  min-height:44px; display:inline-flex; align-items:center;
  border-bottom:0; position:relative;
}
.gp-card__link::after{
  content:""; position:absolute; left:0; right:0; bottom:11px;
  border-bottom:1px solid var(--c-accent);
}
.gp-card__link:hover::after{ border-color:var(--c-ink); }
.gp-faq summary{ min-height:48px; display:flex; align-items:center; }

/* ---- 17.5 Minimum legible sizes ------------------------------------
   The wordmark sub-line fell to 8.5px on a phone. Nothing below 11px. */
.gp-wordmark__sub{ font-size:11px; letter-spacing:.3em; }
@media (max-width:600px){ .gp-wordmark__sub{ font-size:10px; letter-spacing:.24em; } }
.gp-eyebrow{ font-size:12px; }
.gp-topbar{ font-size:12px; }

/* ---- 17.6 Header: horizontal to 1024, hamburger below --------------
   The stacked header was costing 185px at 768 and 194px at 375, against
   the reference site's 120px with a single toggle. */
.gp-header__bar{
  display:flex; align-items:center; justify-content:space-between;
  gap:24px; padding:18px var(--gutter); flex-wrap:nowrap;
}
.gp-burger{ display:none; }
.gp-nav__tel{ display:none; }

@media (max-width:1200px){ .gp-nav{ gap:22px; } .gp-nav a{ font-size:11.5px; letter-spacing:.1em; } }

@media (max-width:1024px){
  .gp-header{ position:sticky; top:0; }
  /* Section 10 sets flex-direction:column below 900px — that rule is
     what stacked the wordmark above the toggle. Force the row back. */
  .gp-header__bar{
    flex-direction:row; align-items:center; justify-content:space-between;
    padding:14px var(--gutter); gap:16px;
  }
  .gp-wordmark{ text-align:left; }
  .gp-wordmark__script{ font-size:36px; }

  .gp-burger{
    display:inline-flex; align-items:center; justify-content:center;
    width:48px; height:48px; padding:0; margin-right:-8px;
    background:none; border:0; cursor:pointer; color:var(--c-ink);
  }
  .gp-burger__box{ position:relative; display:block; width:24px; height:16px; }
  .gp-burger__line, .gp-burger__box::before, .gp-burger__box::after{
    content:""; position:absolute; left:0; width:24px; height:2px;
    background:currentColor; transition:transform .22s ease, opacity .16s ease;
  }
  .gp-burger__box::before{ top:0; }
  .gp-burger__line{ top:7px; }
  .gp-burger__box::after{ bottom:0; }
  .is-open .gp-burger__box::before{ top:7px; transform:rotate(45deg); }
  .is-open .gp-burger__line{ opacity:0; }
  .is-open .gp-burger__box::after{ bottom:7px; transform:rotate(-45deg); }

  /* The panel */
  .gp-nav{
    position:fixed; top:0; right:0; bottom:0; z-index:60;
    width:min(340px,86vw);
    flex-direction:column; align-items:stretch; justify-content:flex-start;
    gap:0; padding:88px 26px 32px;
    background:var(--c-white);
    border-left:1px solid var(--c-tint-1);
    box-shadow:-24px 0 60px -30px rgba(51,41,40,.45);
    transform:translateX(100%);
    transition:transform .26s cubic-bezier(.4,0,.2,1);
    overflow-y:auto;
  }
  .is-open .gp-nav{ transform:translateX(0); }
  .gp-nav a{
    font-size:13px; letter-spacing:.14em; min-height:54px;
    border-bottom:1px solid var(--c-tint-1); padding:4px 0;
  }
  .gp-nav a:hover{ color:var(--c-mid); border-color:var(--c-accent); }
  .gp-nav a.gp-btn{
    margin-top:26px; border-bottom:0; justify-content:center;
    font-size:13px; min-height:50px;
  }
  .gp-nav__tel{
    display:inline-flex; margin-top:18px; border-bottom:0;
    font-family:var(--f-display); font-size:20px; font-weight:600;
    letter-spacing:0; text-transform:none; color:var(--c-mid);
  }
  .gp-navscrim{
    position:fixed; inset:0; z-index:55;
    background:rgba(37,29,32,.42);
    backdrop-filter:blur(2px);
  }
  .gp-navscrim[hidden]{ display:none; }
  html.gp-noscroll, html.gp-noscroll body{ overflow:hidden; }
}

@media (max-width:600px){
  .gp-header__bar{ padding:12px var(--gutter); }
  .gp-wordmark__script{ font-size:32px; }
  .gp-topbar{ font-size:11px; padding:9px 16px; }
}

/* ---- 17.7 Hero proportions per breakpoint --------------------------
   760px of hero inside a 1024px-tall tablet left nothing else visible. */
.gp-hero{ min-height:min(78vh,700px); }
.gp-hero--short{ min-height:min(52vh,420px); }
@media (max-width:1024px){
  .gp-hero{ min-height:min(62vh,540px); }
  .gp-hero--short{ min-height:min(42vh,340px); }
}
@media (max-width:767px){
  .gp-hero{ min-height:min(66vh,520px); padding-bottom:44px; }
  .gp-hero--short{ min-height:min(46vh,330px); padding-bottom:34px; }
}

/* ---- 17.8 Grid density ---------------------------------------------
   Three treatment cards still read well at 1024; two looked sparse. */
@media (min-width:901px) and (max-width:1024px){
  .gp-cards{ grid-template-columns:repeat(3,1fr); gap:22px; }
  .gp-cards--2{ grid-template-columns:repeat(2,1fr); }
  .gp-cards--4{ grid-template-columns:repeat(4,1fr); }
  .gp-ba{ grid-template-columns:repeat(4,1fr); gap:18px; }
  .gp-card__body{ padding:22px 20px 24px; }
}
@media (max-width:900px) and (min-width:641px){
  .gp-cards, .gp-cards--4{ grid-template-columns:repeat(2,1fr); }
  .gp-ba{ grid-template-columns:repeat(2,1fr); }
}

/* ---- 17.9 Band rhythm ---------------------------------------------- */
@media (max-width:1024px){ :root{ --space-band:68px; } }
@media (max-width:767px){ :root{ --space-band:52px; } }

/* ---- 17.10 Long-word and table safety ------------------------------ */
h1,h2,h3,p,li,.gp-pricing__name{ overflow-wrap:break-word; }
.gp-pricing li{ flex-wrap:wrap; }

/* ---- 17.11 Menu stacking context ----------------------------------
   .gp-header is positioned with z-index:20, which creates a stacking
   context — so .gp-nav's z-index:60 only competed *inside* the header,
   and the scrim (a sibling at 55) painted over the open panel. The
   links were visually greyed AND untappable: elementFromPoint inside
   the panel returned .gp-navscrim, so a tap closed the menu instead of
   navigating. Lift the whole header above the scrim while it is open. */
.gp-header.is-open{ z-index:60; }
.gp-navscrim{ z-index:55; }

/* ---- 17.12 Grid columns must be allowed to shrink -----------------
   At 320px .gp-split--narrow-media measured 280px wide but its single
   column computed to 330.78px, pushing the booking copy 31px past the
   right edge. Cause: `1fr` is `minmax(auto, 1fr)`, and the auto minimum
   is the item's min-content width — here the CF7 <select>, whose longest
   option ("Microneedling with PRP + Brightening Serum") set the floor.
   minmax(0,1fr) lets the track shrink; min-width:0 does the same for
   the flex/grid children that inherit an auto minimum. */
.gp-split, .gp-split--narrow-media, .gp-servicetop,
.gp-cards, .gp-ba, .gp-form-grid, .gp-band__inner{ min-width:0; }
.gp-split > *, .gp-servicetop > *, .gp-cards > *,
.gp-ba > *, .gp-form-grid > *, .gp-card, .gp-tile{ min-width:0; }

@media (max-width:960px){ .gp-servicetop{ grid-template-columns:minmax(0,1fr); } }
@media (max-width:900px){ .gp-split, .gp-split--narrow-media{ grid-template-columns:minmax(0,1fr); } }
@media (max-width:640px){ .gp-cards, .gp-cards--2, .gp-cards--4{ grid-template-columns:minmax(0,1fr); } }
@media (max-width:520px){ .gp-ba{ grid-template-columns:minmax(0,1fr); } }
@media (max-width:767px){ .gp-form-grid{ grid-template-columns:minmax(0,1fr); } }

/* A <select> reports its widest option as min-content. Cap it. */
.gp-booking select, .gp-booking input, .gp-booking textarea{ max-width:100%; min-width:0; }
.gp-booking .wpcf7-form-control-wrap{ min-width:0; }

/* ---- 17.13 Panel-only phone number --------------------------------
   `.gp-nav a` is (0,1,1) and beat `.gp-nav__tel` (0,1,0), so the phone
   link intended only for the slide-in panel was also rendering in the
   desktop nav — duplicating the number already in the top bar. */
.gp-nav a.gp-nav__tel{ display:none; }
@media (max-width:1024px){
  .gp-nav a.gp-nav__tel{ display:inline-flex; }
}

/* ---- 17.14 Honeypot field must stay hidden -------------------------
   The spam honeypot renders a decoy <input type="text"> with a random
   name. `.gp-booking :is(input[type=text],…)` is more specific than the
   plugin's own hiding rule, so it was painting a stray 30×50 empty box
   inside the booking form.

   Hidden off-screen rather than with display:none on purpose: a number
   of bots skip display:none inputs, which defeats the trap. Kept out of
   the tab order and out of the accessibility tree too. */
.gp-hp,
.cf7apps-honeypot-wrap,
.wpcf7-form-control-wrap[class*="honeypot"]{
  position:absolute !important;
  left:-9999px !important;
  top:auto !important;
  width:1px !important;
  height:1px !important;
  padding:0 !important;
  margin:0 !important;
  overflow:hidden !important;
  opacity:0 !important;
  pointer-events:none !important;
}
.gp-hp input,
.cf7apps-honeypot-wrap input{
  width:1px !important;
  height:1px !important;
  min-height:0 !important;
  padding:0 !important;
  border:0 !important;
  opacity:0 !important;
}

/* ---- 17.15 Footer link tap targets --------------------------------
   Footer list links were 18px tall — fine with a mouse, not with a
   thumb. Padding rather than min-height so the columns stay compact
   on desktop where it does not matter. */
@media (max-width:900px){
  .gp-footer li{ margin:0; }
  .gp-footer li a{ display:inline-flex; align-items:center; min-height:40px; }
  .gp-footer p a{ display:inline-block; padding:4px 0; }
  .gp-footer{ padding-top:56px; }
  .gp-footer__cols{ gap:30px 28px; }
}
/* Nothing on the page should sit below 11px. */
@media (max-width:600px){ .gp-wordmark__sub{ font-size:11px; letter-spacing:.2em; } }

/* ══════════════════════════════════════════════════════════════════
   18. HERO MEDIA — landscape stills on desktop, vertical video on mobile

   One rule, two devices, and no compromise in either direction.

   Every clip the client shot is vertical phone video. Cropping it to
   16:9 for a desktop hero threw away two thirds of the frame and cut
   heads off; letterboxing it left black bars. So desktop gets a
   landscape photograph instead — and gets it *only*: the <video>
   element carries its URL in data-src rather than src, so a desktop
   browser issues no request for the file at all.

   Mobile gets the vertical clip, and the band itself becomes vertical
   there, so object-fit:cover has nothing to crop away.
   ══════════════════════════════════════════════════════════════════ */

/* ── desktop: the landscape still ─────────────────────────────────── */
.gp-media__img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  object-position:50% 32%;
}
.gp-media__vid{ display:none; }
.gp-hero__media, .gp-photoband__media{ background:var(--c-ink); overflow:hidden; }

/* Copy sits over the left third, so the scrim is heaviest there and
   clears off to the right to let the photograph read. A flat wash over
   the whole frame is what made the old hero look like a brown smear. */
.gp-hero--video::after,
.gp-hero--media::after{
  background:linear-gradient(94deg,
    rgba(37,29,32,.90) 0%,
    rgba(37,29,32,.80) 26%,
    rgba(37,29,32,.52) 50%,
    rgba(37,29,32,.20) 76%,
    rgba(37,29,32,.04) 100%);
}

/* Between 768 and 1024 the hero copy no longer sits in a left column —
   it stacks across the full width at the bottom. A left-to-right scrim
   there just puts 80% ink over the middle of the photograph and the
   whole band goes muddy, which is what happened to the tablet view.
   Same amount of contrast, applied from the floor up instead. */
@media (min-width:768px) and (max-width:1024px){
  .gp-hero--video::after,
  .gp-hero--media::after{
    background:linear-gradient(to top,
      rgba(37,29,32,.86) 0%,
      rgba(37,29,32,.60) 38%,
      rgba(37,29,32,.24) 70%,
      rgba(37,29,32,.08) 100%);
  }
}

/* A centred band wants an even scrim, not a directional one. */
.gp-photoband .gp-media__img{ object-position:50% 40%; }
.gp-photoband::after{ background:rgba(37,29,32,.52); }

/* ── mobile: the vertical clip, effectively uncropped ─────────────── */
@media (max-width:767px){

  /* 9:14 is within a few percent of the source 9:16, so cover trims
     only a sliver top and bottom — and it leaves the next section
     peeking above the fold instead of eating the whole screen.

     Scoped with :has() so that ONLY a band actually carrying a clip
     goes vertical. A band holding a landscape photograph stays a band;
     turning those vertical too was stretching a 2.2:1 crop into a
     portrait box. */

  /* Service-page heroes are a product photograph with one word set
     across it. At this width the word lands on the product lettering,
     so lift the subject out of the bottom third and deepen the floor. */
  .gp-hero--short{ min-height:min(52vh,380px); }
  .gp-hero--short .gp-hero__media img{ object-position:50% 16%; }
  .gp-hero--short::after{
    background:linear-gradient(to top,
      rgba(37,29,32,.88) 0%,
      rgba(37,29,32,.68) 34%,
      rgba(37,29,32,.32) 66%,
      rgba(37,29,32,.14) 100%);
  }

  .gp-media__img{ display:none; }
  .gp-media__vid{
    display:block;
    position:absolute; inset:0;
    width:100%; height:100%;
    object-fit:cover;
    object-position:50% 46%;
  }

  /* The poster is the clip's own first frame, so there is no flash
     between paint and playback and no still image is needed behind. */

  /* Was .86 at the bottom stop, which washed the photograph out
     completely. Dark enough under the headline, clear everywhere else. */
  .gp-hero--video::after,
  .gp-hero--media::after,
  .gp-photoband::after{
    background:linear-gradient(to top,
      rgba(37,29,32,.76) 0%,
      rgba(37,29,32,.54) 26%,
      rgba(37,29,32,.18) 58%,
      rgba(37,29,32,.06) 82%,
      rgba(37,29,32,.24) 100%);
  }

  /* Two full-width stacked pills were the loudest thing on the phone
     hero. But forcing both onto one row with flex:1 1 0 made them
     narrower than their own text — "Request an Appointment" rendered
     as "EQUEST AN APPOINTMENT", clipped inside a nowrap button, on the
     primary call to action. So: auto width, and let them wrap. They sit
     on one row when they fit and two neat left-aligned rows when they
     do not, and the label is never cut. */
  .gp-hero .gp-btns{ gap:10px; margin-top:20px; flex-wrap:wrap; }
  .gp-hero .gp-btns .gp-btn{
    width:auto; flex:0 0 auto; min-width:0;
    padding:13px 20px; font-size:12px; min-height:46px;
    letter-spacing:.05em;
  }
  .gp-hero__lead{ font-size:15px; line-height:1.58; }
}

/* ── legacy class names, still referenced by a few pages ──────────── */
.gp-hero__still{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:50% 34%;
}
.gp-hero__video{ display:none; }

/* ══════════════════════════════════════════════════════════════════
   19. RESPONSIVE COPY

   Some sentences that read well on a 1400px hero are four lines on a
   phone sitting on top of a video. Rather than shrink the type until
   it fits, the markup carries both lengths and swaps them.
   ══════════════════════════════════════════════════════════════════ */
.gp-sm-only{ display:none; }
@media (max-width:767px){
  .gp-sm-hide{ display:none; }
  .gp-sm-only{ display:inline; }
  .gp-topbar{ white-space:nowrap; }
}

/* ══════════════════════════════════════════════════════════════════
   20. SERVICE PAGE: THE FORM STAYS AT THE TOP

   The brief was a booking form at the top of every service page. On a
   wide screen it sits in the right column beside the first block of
   copy. When those columns stack, source order puts the copy first and
   the form ends up roughly 1,700px down — four screens past the fold
   on a phone, which is not "at the top" in any useful sense.
   ══════════════════════════════════════════════════════════════════ */
@media (max-width:960px){
  .gp-servicetop{ gap:26px; }
  .gp-servicetop > *:last-child{ order:-1; }
}

/* ══════════════════════════════════════════════════════════════════
   21. TOUCH TARGETS AND FORM TYPE  (mobile QC)

   Measured at 375px: the topbar phone link was 95x14, the footer
   contact links 32px tall, and the "Anything we should know?" form
   label was 11px. A phone number is the primary action on a med spa
   site viewed on a phone — 14px of tappable height is not enough.
   ══════════════════════════════════════════════════════════════════ */
@media (max-width:767px){

  /* Let the link fill the bar rather than padding the bar and the link
     separately — same 46px target, 10px less chrome above the fold. */
  .gp-topbar{ padding-block:0; }
  .gp-topbar a{ display:inline-block; padding:15px 6px; font-size:12px; }

  /* Footer contact lines were 32px; a phone number and an email are the
     two things people actually reach for down there. */
  .gp-footer__cols a{ display:inline-block; padding-block:7px; }

  /* And the inline phone number in the Contact/Visit split (19px). */
  .gp-split__body p a[href^="tel:"],
  .gp-split__body p a[href^="mailto:"]{ display:inline-block; padding-block:8px; }


  /* Anything still under the floor gets nudged to it. */
  .gp-wordmark__sub{ font-size:11px; }   /* intentional: tracked small caps */
}

/* The footer's address / phone / email sit inside a <p> and an existing
   `.gp-footer p a` rule with 4px padding was outranking the block rule
   above, leaving them at 32px. Matched at the same depth so it wins.
   Extended to 1024px because a tablet is a touch device too — the
   topbar phone link was still 15px tall there. */
@media (max-width:1024px){
  .gp-footer__cols p a{ display:inline-block; padding-block:9px; }
  .gp-topbar a{ display:inline-block; padding:14px 6px; }
  .gp-topbar{ padding-block:0; }
  .gp-split__body p a[href^="tel:"],
  .gp-split__body p a[href^="mailto:"]{ display:inline-block; padding-block:8px; }
}

/* A form label has no business being 11px at any width — it was inside
   a max-width:767 block, so tablets kept the tiny version. */
.gp-booking label,
.wpcf7 label{ font-size:12.5px; }

/* ══════════════════════════════════════════════════════════════════
   22. REFERENCE ALIGNMENT

   Measured off medifreda.com at 430px, which is what the brief has
   pointed at from the beginning:

     hero media   430x419  (1.03:1) — a BLOCK, with no text on it
     H1           Playfair  35/700  lh42  centre  #332928
     H2           Playfair  25/700         centre #6b616e  (or white
                                            on a solid mauve band)
     H3           Playfair  20/500         centre
     body         Montserrat 16/400 lh26   centre #332928
     button       #6b616e, radius 100, Montserrat 13/500 uppercase
     text over a photograph: NEVER, anywhere on the page

   What I had built instead: a full-bleed photo with an 80% ink
   gradient over it, left-aligned white type, a tracked small-caps
   label above every heading, 01/02/03 numbered tiles and a hairline
   rule under each title. Every one of those is a house style of
   generated pages, and together they are why it read as one. None of
   them appear on the reference.
   ══════════════════════════════════════════════════════════════════ */

/* ── 22.1  the eyebrow ─────────────────────────────────────────────
   Tracked uppercase Montserrat over every single heading is the
   loudest tell of the lot. Theirs is a short pink serif line in
   sentence case — "Welcome To". Same element, different voice. */
.gp-eyebrow{
  font-family:var(--f-display);
  font-size:17px;
  font-weight:600;
  font-style:italic;
  letter-spacing:0;
  text-transform:none;
  text-align:center;
  color:var(--c-accent);
  margin:0 0 12px;
}
.gp-eyebrow::first-letter{ text-transform:uppercase; }

/* ── 22.2  no numbered tiles ─────────────────────────────────────── */
.gp-tile__num{ display:none; }

/* ── 22.3  centred, like the reference ──────────────────────────── */
.gp-band__inner,
.gp-hero__copy,
.gp-photoband__inner,
.gp-split__body,
.gp-tile,
.gp-card__body{ text-align:center; }

.gp-band :is(h1,h2,h3,h4,p),
.gp-hero :is(h1,h2,h3,p),
.gp-photoband :is(h2,h3,p),
.gp-tile :is(h3,p),
.gp-split__body :is(h2,h3,p){ text-align:center; }

.gp-rule{ margin-inline:auto; }
.gp-btns{ justify-content:center; }
.gp-lead, .gp-hero__lead{ margin-inline:auto; }

/* The booking form is the one place centred labels would be wrong. */
.gp-booking,
.gp-booking :is(h2,h3,p,label,span,div){ text-align:left; }
.gp-booking .gp-btns,
.gp-booking .wpcf7-submit{ text-align:center; }

/* ── 22.4  the type scale ───────────────────────────────────────── */
:root{ --t-h1:58px; --t-h2:38px; --t-h3:25px; }
h1,.gp-display{ font-weight:700; letter-spacing:-.01em; }
h2{ font-weight:700; }
h3{ font-weight:500; }

/* Their subhead is a serif H2 in mauve, not a sans lead paragraph. */
.gp-lead,
.gp-hero__lead{
  font-family:var(--f-display);
  font-weight:600;
  font-style:normal;
  color:var(--c-mid);
  line-height:1.5;
}
.gp-band p:not(.gp-eyebrow):not(.gp-lead),
.gp-tile p,
.gp-split__body p{
  font-family:var(--f-ui);
  font-weight:400;
  font-size:16px;
  line-height:1.63;
  color:var(--c-ink);
}

@media (max-width:767px){
  :root{ --t-h1:35px; --t-h2:25px; --t-h3:20px; }
  h1{ line-height:1.2; }
  .gp-lead, .gp-hero__lead{ font-size:20px; line-height:1.5; }
  .gp-eyebrow{ font-size:16px; }
}
@media (min-width:768px) and (max-width:1024px){
  :root{ --t-h1:44px; --t-h2:30px; --t-h3:22px; }
  .gp-lead, .gp-hero__lead{ font-size:22px; }
}
@media (min-width:1025px){
  .gp-lead, .gp-hero__lead{ font-size:23px; line-height:1.55; }
}

/* ── 22.5  the hero, rebuilt ─────────────────────────────────────────
   Media block on top at its own aspect ratio, copy underneath on
   white, centred. No absolute positioning, no gradient, no white type
   fighting a photograph for contrast. This is also why it felt broken
   on a 6.7" phone: the old hero was a 669px-tall dark panel with the
   headline jammed against the bottom edge. */
.gp-hero,
.gp-hero--short,
.gp-hero--video,
.gp-hero--media{
  display:block;
  min-height:0;
  aspect-ratio:auto;
  max-height:none;
  padding:0;
  background:var(--c-white);
  overflow:visible;
}
.gp-hero::after,
.gp-hero--video::after,
.gp-hero--media::after,
.gp-hero--short::after{ content:none; display:none; background:none; }

.gp-hero__media{
  position:relative;
  inset:auto;
  z-index:0;
  width:100%;
  aspect-ratio:2.4/1;
  max-height:600px;
  overflow:hidden;
  background:var(--c-tint-2);
}
.gp-hero__media img,
.gp-hero__media video,
.gp-media__img,
.gp-media__vid{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
}
.gp-hero__media .gp-media__img{ object-position:50% 34%; }

.gp-hero__inner{
  position:static;
  max-width:820px;
  margin-inline:auto;
  padding:56px var(--gutter) 60px;
}
.gp-hero__copy{ max-width:none; text-align:center; }

/* Specificity note, because this bit bit me: the original rule is
   `.gp-hero :is(h1,p,.gp-eyebrow)` and :is() inherits the weight of
   its HEAVIEST argument — the class — so that selector scores (0,2,0)
   and a plain `.gp-hero :is(h1,h2,h3)` at (0,1,1) loses to it. The
   headline stayed white and vanished against the new white hero.
   Naming the copy wrapper as well takes these to (0,2,1)/(0,3,0). */
.gp-hero .gp-hero__copy :is(h1,h2,h3){ color:var(--c-ink); text-shadow:none; }
.gp-hero .gp-hero__copy p:not(.gp-eyebrow):not(.gp-hero__lead){ color:var(--c-ink); }
.gp-hero .gp-hero__copy .gp-eyebrow{ color:var(--c-accent); }
.gp-hero .gp-hero__copy .gp-hero__lead{ color:var(--c-mid); }
.gp-hero .gp-rule{ background:var(--c-accent); margin-inline:auto; }
.gp-hero .gp-btns{ justify-content:center; margin-top:26px; }
.gp-hero .gp-btn--outline-light{
  background:transparent; color:var(--c-mid); border-color:var(--c-mid);
}
.gp-hero .gp-btn--outline-light:hover{ background:var(--c-mid); color:var(--c-white); }

/* The feature bands lower down follow the same rule: photograph, then
   words. Never words on top of a photograph. */
.gp-photoband{
  display:block;
  min-height:0;
  aspect-ratio:auto;
  max-height:none;
  padding:0;
  background:var(--c-tint-3);
  overflow:visible;
}
.gp-photoband::after{ content:none; display:none; background:none; }
.gp-photoband__media{
  position:relative; inset:auto; z-index:0;
  width:100%; aspect-ratio:2.4/1; max-height:600px; overflow:hidden;
}
.gp-photoband__inner{
  max-width:760px; margin-inline:auto;
  padding:52px var(--gutter) 56px;
  position:static;
}
.gp-photoband .gp-photoband__inner :is(h2,h3){ color:var(--c-ink); }
.gp-photoband .gp-photoband__inner p:not(.gp-eyebrow){ color:var(--c-ink); }
.gp-photoband .gp-photoband__inner .gp-eyebrow{ color:var(--c-accent); }
.gp-photoband .gp-btn--light{ background:var(--c-mid); color:var(--c-white); }
.gp-photoband .gp-btn--light:hover{ background:var(--c-ink); }
.gp-photoband .gp-btn--outline-light{ color:var(--c-mid); border-color:var(--c-mid); }

@media (max-width:767px){
  /* Their hero block is 1.03:1. The brief also asked for the vertical
     clip on phones, so 4:5 keeps it portrait while staying near their
     proportion — and it is 537px on a 6.7" screen instead of 669. */
  .gp-hero__media{ aspect-ratio:4/5; max-height:none; }
  .gp-photoband__media{ aspect-ratio:1/1; max-height:none; }
  .gp-hero__inner{ padding:40px var(--gutter) 44px; }
  .gp-photoband__inner{ padding:36px var(--gutter) 40px; }
  .gp-hero .gp-btns{ flex-wrap:wrap; justify-content:center; }

  /* Their mobile header is the wordmark and a hamburger on white —
     no bar above it. */
  .gp-topbar{ display:none; }
}

/* ── 22.6  one solid mauve anchor band ───────────────────────────────
   The reference breaks the page with a full section of #6b616e
   carrying white type. That single move is doing a lot of the work
   that made theirs read as designed rather than assembled. */
.gp-band--deep{ background:var(--c-mid); }
.gp-band--deep :is(h1,h2,h3,h4){ color:var(--c-white); }
.gp-band--deep p:not(.gp-eyebrow){ color:rgba(255,255,255,.90); }
.gp-band--deep .gp-eyebrow{ color:var(--c-tint-1); }
.gp-band--deep .gp-rule{ background:rgba(255,255,255,.5); }
.gp-band--deep .gp-tile{ background:transparent; border-color:rgba(255,255,255,.22); }
.gp-band--deep .gp-btn--primary{ background:var(--c-white); color:var(--c-ink); }
.gp-band--deep .gp-btn--primary:hover{ background:var(--c-tint-1); }
.gp-band--deep .gp-btn--ghost{ color:var(--c-white); border-color:rgba(255,255,255,.7); }
.gp-band--deep .gp-btn--ghost:hover{ background:var(--c-white); color:var(--c-ink); }

/* ══════════════════════════════════════════════════════════════════
   23. CONTRAST REPAIR AFTER THE MAUVE BAND

   Turning .gp-band--deep into a solid #6b616e section put a pricing
   list that had been designed for a blush background onto mauve. The
   treatment names came out at 1.9:1 and the grey sub-lines were set in
   #6b616e itself — the exact background colour, so they rendered
   invisible. Everything inside that band now inverts properly.
   ══════════════════════════════════════════════════════════════════ */
.gp-band--deep :is(li,span,dt,dd,strong,em,td,th){ color:var(--c-white); }
.gp-band--deep .gp-pricing__name > span,
.gp-band--deep .gp-pricing__meta,
.gp-band--deep .gp-pricing__note,
.gp-band--deep small{ color:rgba(255,255,255,.74); }
.gp-band--deep .gp-pricing__price{ color:var(--c-white); }
.gp-band--deep :is(.gp-pricing li,.gp-card,.gp-tile,hr){ border-color:rgba(255,255,255,.22); }
.gp-band--deep a:not(.gp-btn){ color:var(--c-white); text-decoration-color:rgba(255,255,255,.5); }

/* The eyebrow at full accent pink sits at 1.94:1 on white — under the
   floor even for large text. A half-step deeper keeps it unmistakably
   the same pink and clears 3:1. */
.gp-eyebrow{ color:#c96f88; }
.gp-hero .gp-hero__copy .gp-eyebrow,
.gp-photoband .gp-photoband__inner .gp-eyebrow{ color:#c96f88; }
.gp-band--deep .gp-eyebrow{ color:var(--c-tint-1); }

/* One more specificity round, and worth writing down: the body rule in
   22.4 is `.gp-band p:not(.gp-eyebrow):not(.gp-lead)`, and because
   :not() contributes the weight of its argument, that selector scores
   (0,3,1) — heavier than the (0,2,0) inversion in 22.6. So the course
   pricing detail lines stayed ink-dark on the mauve band at 2.4:1.
   Naming the inner wrapper takes the override to (0,4,1). */
.gp-band--deep .gp-band__inner :is(h1,h2,h3,h4){ color:var(--c-white); }
.gp-band--deep .gp-band__inner p:not(.gp-eyebrow):not(.gp-lead),
.gp-band--deep .gp-band__inner .gp-tile p,
.gp-band--deep .gp-band__inner :is(li,span,dt,dd,td){ color:rgba(255,255,255,.90); }
.gp-band--deep .gp-band__inner .gp-lead{ color:rgba(255,255,255,.95); }
.gp-band--deep .gp-band__inner .gp-eyebrow{ color:var(--c-tint-1); }

/* ══════════════════════════════════════════════════════════════════
   24. SERVICE CARDS

   Two fixes. The tile is 4:3 at every breakpoint (measured 373x280 at
   430px, 371x278 at 1366) and was being fed 16:9 files, so cover threw
   away a quarter of the width — on mobile AND desktop. Dedicated 4:3
   crops now come in through the filter.

   And the call to action was a 12px underlined "Details" in mauve.
   The reference uses a filled pill: #6b616e, radius 100, Montserrat
   13/500 uppercase. Price above, button below, both centred.
   ══════════════════════════════════════════════════════════════════ */
.gp-card__media,
.gp-cards img{ aspect-ratio:4/3; }

.gp-card__foot{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:16px;
  text-align:center;
}
.gp-price{ text-align:center; }

.gp-card__link{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  background:var(--c-mid);
  color:var(--c-white);
  border:1px solid transparent;
  border-radius:var(--radius-pill);
  padding:12px 26px;
  min-height:44px;
  font-family:var(--f-ui);
  font-size:13px;
  font-weight:500;
  line-height:1.2;
  letter-spacing:.04em;
  text-transform:uppercase;
  text-decoration:none;
  white-space:nowrap;
  transition:background .18s ease, color .18s ease;
}
.gp-card__link:hover,
.gp-card__link:focus-visible{ background:var(--c-ink); color:var(--c-white); }

/* On the mauve band the filled mauve pill would disappear. */
.gp-band--deep .gp-band__inner .gp-card__link{
  background:var(--c-white); color:var(--c-ink);
}
.gp-band--deep .gp-band__inner .gp-card__link:hover{ background:var(--c-tint-1); }

/* ══════════════════════════════════════════════════════════════════
   25. GOOGLE REVIEWS

   Real reviews, transcribed from the Google Business Profile with the
   reviewer's own name and the service they had. The aggregate (5.0 from
   29) is shown once at the top because that figure is stated on the
   profile and is verifiable. Individual reviews carry NO star row:
   Google's panel exposes only the aggregate rating, not a per-review
   score, so printing five stars on each card would be asserting
   something I could not actually confirm.
   ══════════════════════════════════════════════════════════════════ */
.gp-rating{
  display:flex; flex-direction:column; align-items:center; gap:7px;
  margin:0 0 18px;
}
.gp-rating__stars{
  color:var(--c-accent);
  font-size:23px;
  letter-spacing:.16em;
  line-height:1;
}
.gp-rating__num{
  font-family:var(--f-ui); font-size:13px; font-weight:500;
  letter-spacing:.04em; color:var(--c-mid);
}

.gp-reviews{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:22px;
  margin-top:46px;
  align-items:stretch;
}
@media (max-width:1024px){ .gp-reviews{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px; } }
@media (max-width:700px){  .gp-reviews{ grid-template-columns:minmax(0,1fr); margin-top:34px; } }

.gp-review{
  margin:0;
  display:flex; flex-direction:column; gap:18px;
  background:var(--c-white);
  border:1px solid var(--c-tint-1);
  border-radius:4px;
  padding:32px 26px 26px;
  text-align:center;
  position:relative;
}
.gp-review::before{
  content:"\201C";
  position:absolute; top:4px; left:0; right:0;
  font-family:var(--f-display);
  font-size:52px; line-height:1;
  color:var(--c-tint-1);
  pointer-events:none;
}
.gp-review__text{
  font-family:var(--f-display);
  font-size:16.5px; font-weight:400; line-height:1.74;
  color:var(--c-ink);
  margin:0;
  position:relative;
}
.gp-review__by{ margin-top:auto; padding-top:6px; }
.gp-review__name{
  display:block;
  font-family:var(--f-display); font-weight:700; font-size:16px;
  color:var(--c-ink);
}
.gp-review__meta{
  display:block; margin-top:5px;
  font-family:var(--f-ui); font-size:12.5px; font-weight:400;
  letter-spacing:.02em;
  color:var(--c-mid);
}
@media (max-width:700px){
  .gp-review{ padding:28px 22px 24px; }
  .gp-review__text{ font-size:16px; line-height:1.7; }
}

/* Accent pink stars on the blush band measured 1.74:1 — washed out.
   The same deeper rose used for the eyebrows reads as rose-gold here
   and stays inside the palette. The row is aria-hidden and the figure
   beside it carries the meaning, so this is legibility, not access. */
.gp-rating__stars{ color:#c96f88; }

/* ══════════════════════════════════════════════════════════════════
   26. TRUST STRIP

   Sits directly above the booking form, which on a treatment page is
   the first thing on the screen on mobile and the right-hand column on
   desktop. Rating and proof at the point of decision, one tap from the
   source.
   ══════════════════════════════════════════════════════════════════ */
.gp-trust{
  display:flex;
  align-items:center;
  gap:10px;
  flex-wrap:wrap;
  margin:0 0 22px;
  padding:12px 16px;
  background:var(--c-tint-3);
  border:1px solid var(--c-tint-1);
  border-radius:var(--radius-pill);
  text-decoration:none;
  transition:background .18s ease, border-color .18s ease;
}
.gp-trust:hover,
.gp-trust:focus-visible{ background:var(--c-tint-2); border-color:var(--c-accent); }

.gp-trust__stars{
  color:#c96f88;
  font-size:15px;
  letter-spacing:.1em;
  line-height:1;
  flex:0 0 auto;
}
.gp-trust__text{
  font-family:var(--f-ui);
  font-size:13px;
  font-weight:400;
  line-height:1.35;
  color:var(--c-ink);
  flex:1 1 auto;
  min-width:0;
}
.gp-trust__text strong{ font-weight:600; }
.gp-trust__cue{
  font-family:var(--f-ui);
  font-size:11.5px;
  font-weight:500;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--c-mid);
  text-decoration:underline;
  text-underline-offset:3px;
  flex:0 0 auto;
  white-space:nowrap;
}
.gp-trust:hover .gp-trust__cue{ color:var(--c-ink); }

/* The booking block is the one left-aligned island on a centred page,
   so the strip follows it rather than the page. */
.gp-booking .gp-trust{ text-align:left; }

@media (max-width:420px){
  .gp-trust{ gap:8px; padding:11px 14px; border-radius:14px; }
  .gp-trust__text{ font-size:12.5px; flex:1 1 100%; order:2; }
  .gp-trust__stars{ order:1; }
  .gp-trust__cue{ order:3; flex:1 1 100%; text-align:left; }
}

/* ══════════════════════════════════════════════════════════════════
   27. FAQ, TREATMENT AREAS, PRE/AFTERCARE, STICKY CALL BAR
   ══════════════════════════════════════════════════════════════════ */

/* ── FAQ ─────────────────────────────────────────────────────────────
   The <details>/<summary> accordion already existed and is already
   styled in section 12 — I had written a second set of rules against
   `.gp-faq__item`, a class this markup does not use, so they matched
   nothing. Only the genuinely missing pieces are kept here: the list
   needs a measure and left alignment, because section 22 centres every
   paragraph in a band and centred multi-line prose reads badly. */
.gp-faq{ max-width:760px; margin-inline:auto; text-align:left; }
.gp-faq summary{ text-align:left; }
.gp-faq summary:hover{ color:var(--c-mid); }
.gp-faq__a p{
  font-family:var(--f-ui);
  font-size:15.5px; line-height:1.7;
  color:var(--c-ink);
  text-align:left;
  margin:0 0 12px;
}
.gp-faq__a p:last-child{ margin-bottom:0; }

/* ── treatment areas ───────────────────────────────────────────────── */
.gp-areas{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));
  gap:2px;
  margin-top:34px;
  background:var(--c-tint-1);
  border:1px solid var(--c-tint-1);
}
.gp-area{
  background:var(--c-white);
  padding:24px 22px;
  text-align:left;
}
.gp-area h3{
  font-family:var(--f-display);
  font-size:19px; font-weight:600; margin:0 0 8px;
  color:var(--c-ink); text-align:left;
}
.gp-area p{
  font-family:var(--f-ui); font-size:14.5px; line-height:1.65;
  color:var(--c-ink); margin:0; text-align:left;
}
.gp-area__price{
  display:block; margin-top:12px;
  font-family:var(--f-ui); font-size:12px; font-weight:600;
  letter-spacing:.06em; text-transform:uppercase;
  color:var(--c-mid);
}

/* ── before / after care ───────────────────────────────────────────── */
.gp-care{
  display:grid;
  /* auto-fit was computing a third, empty track for two children —
     harmless to read but it eats one gap and shifts the pair off
     centre. Two columns is what this always is, so say so. */
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:24px;
  margin-top:34px;
  text-align:left;
}
@media (max-width:820px){
  .gp-care{ grid-template-columns:minmax(0,1fr); }
}
.gp-care__col{
  background:var(--c-white);
  border:1px solid var(--c-tint-1);
  border-radius:4px;
  padding:26px 24px;
}
.gp-care__col h3{
  font-family:var(--f-display); font-size:20px; font-weight:600;
  margin:0 0 14px; color:var(--c-ink); text-align:left;
}
.gp-care__col ul{ margin:0; padding-left:20px; }
.gp-care__col li{
  font-family:var(--f-ui); font-size:15px; line-height:1.62;
  color:var(--c-ink); margin-bottom:10px; text-align:left;
}
.gp-care__col li:last-child{ margin-bottom:0; }
.gp-care__note{
  margin-top:18px; text-align:center;
  font-family:var(--f-ui); font-size:13.5px; color:var(--c-mid);
}

/* ── sticky call / book bar (phones only) ──────────────────────────── */
.gp-callbar{ display:none; }
@media (max-width:767px){
  .gp-callbar{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:8px;
    position:fixed;
    left:0; right:0; bottom:0;
    z-index:70;
    padding:9px 12px calc(9px + env(safe-area-inset-bottom));
    background:rgba(255,255,255,.96);
    backdrop-filter:saturate(180%) blur(10px);
    border-top:1px solid var(--c-tint-1);
  }
  .gp-callbar__btn{
    display:flex; align-items:center; justify-content:center; gap:7px;
    min-height:48px;
    border-radius:var(--radius-pill);
    font-family:var(--f-ui); font-size:13px; font-weight:500;
    letter-spacing:.05em; text-transform:uppercase;
    text-decoration:none;
  }
  .gp-callbar__btn--call{
    background:transparent; color:var(--c-mid);
    border:1px solid var(--c-mid);
  }
  .gp-callbar__btn--book{ background:var(--c-mid); color:var(--c-white); }
  .gp-callbar__btn--book:active,
  .gp-callbar__btn--call:active{ transform:translateY(1px); }

  /* Clear the footer so the bar never sits on top of the last link. */
  body{ padding-bottom:74px; }
  /* The slide-in menu and its scrim must cover the bar, not sit under it. */
  .gp-header.is-open{ z-index:80; }
  .gp-navscrim{ z-index:75; }
}

/* ====================================================================
   28. ODD-CARD GRIDS + PER-BREAKPOINT HERO ART
   ==================================================================== */

/* The treatment grid runs three across from 901px, two below that. Adding a
   seventh treatment leaves one card alone on the last row, hard against the
   left edge, which reads as a mistake rather than a layout. Centre it.

   The guard is the column count: in a three-column grid a lone last card is
   :nth-child(3n+1); in a two-column grid it is :nth-child(odd). Neither
   fires on a full last row, so the rules are inert on the six-card grids. */
@media (min-width:901px){
  .gp-cards:not(.gp-cards--2):not(.gp-cards--4) > :last-child:nth-child(3n+1){ grid-column:2; }
}
@media (min-width:641px) and (max-width:900px){
  .gp-cards:not(.gp-cards--4) > :last-child:nth-child(odd){
    grid-column:1 / -1; width:calc(50% - 15px); margin-inline:auto;
  }
}
@media (min-width:641px){
  .gp-cards--2 > :last-child:nth-child(odd){
    grid-column:1 / -1; width:calc(50% - 15px); margin-inline:auto;
  }
}

/* Service heroes are 2.4:1 on desktop and 4:5 on phones. One crop cannot
   serve both: cover would show only the middle third of a wide frame inside
   a portrait box. Pages that care wrap the hero art in <picture> and hand
   the phone its own portrait file, so exactly one of the two is ever
   fetched. <picture> is display:contents so the <img> inside it still
   positions against .gp-hero__media rather than against the wrapper. */
.gp-hero__media picture,
.gp-photoband__media picture{ display:contents; }

/* ====================================================================
   29. SECTION SEAMS
   ==================================================================== */

/* Every band on this site is full bleed and is meant to butt straight up
   against the next one. They were not: a 19.2px white stripe sat in every
   single join, header to hero, band to band, band to footer.

   It was not our spacing. WordPress applies its default block gap to the
   children of any flow layout:

       :root :where(.is-layout-flow) > * { margin-block-start: 1.2rem }

   and .entry-content is a flow layout, so each wp:html section inherited a
   top margin — as did <main> and the footer template part, from the same
   rule scoped to .wp-site-blocks. Between two differently tinted bands the
   stripe read as a divider and went unnoticed; between two pink ones it
   read as a crack.

   Zeroed at both levels rather than by setting spacing.blockGap to 0 in
   theme.json, because that value also spaces normal blocks and the editor
   canvas — this only touches the full-bleed bands, which never wanted a
   gap in the first place.

   Specificity: Core's rule is (0,1,0). `body .wp-site-blocks > *` is
   (0,1,1) and `.entry-content > :is(…)` is (0,2,0), so both win outright
   rather than relying on stylesheet order. */
body .wp-site-blocks > *{
  margin-block-start:0;
  margin-block-end:0;
}
.entry-content > :is(.gp-hero, .gp-band, .gp-photoband, .gp-cta, .gp-strip){
  margin-block-start:0;
  margin-block-end:0;
}

/* ====================================================================
   30. SPLIT MEDIA AT ITS OWN ASPECT RATIO
   ==================================================================== */

/* .gp-split__media--tall forces every photograph into a 4:5 box and covers,
   which is right when the art was cut for that box and wrong when it was
   not — a near-square frame lost 44% of itself there. This variant drops
   the fixed ratio and the 100% height so the image simply renders at its
   own proportions, whole. .gp-split already centres its columns, so a
   shorter image sits centred against the copy rather than hanging at
   the top, and the accent square still anchors to the image's real
   bottom-right corner because the wrapper now shrinks to fit it. */
.gp-split .gp-split__media--natural img{
  aspect-ratio:auto;
  height:auto;
  object-fit:contain;
}

/* ====================================================================
   31. TREATMENTS DROPDOWN
   ==================================================================== */

/* Two different disclosures from one piece of markup: a hover/focus panel
   on desktop, an inline accordion inside the slide-in drawer on phones.

   "Treatments" stays a real link to the services page in both — the caret
   beside it is a separate <button>, which is the pattern that works for
   keyboard and screen-reader users. A parent that is *only* a toggle
   strands anyone who wants the index page; a parent that is *only* a link
   strands anyone who cannot hover. */

/* The caret's accessible name is an aria-label on the button rather than
   a visually-hidden <span>. The span version worked for screen readers but
   its absolutely-positioned text pushed the drawer's scrollable width out
   to 403px against a 322px panel, so the menu scrolled sideways. */

.gp-nav__group{ position:relative; }
.gp-nav__row{ display:flex; align-items:center; }
.gp-subnav a{ text-decoration:none; }

/* The caret. Drawn in CSS so the header still costs zero extra requests. */
.gp-nav__toggle{
  display:inline-flex; align-items:center; justify-content:center;
  background:none; border:0; padding:0; cursor:pointer; color:inherit;
}
.gp-nav__chev{
  display:block; width:7px; height:7px;
  border-right:1.6px solid currentColor; border-bottom:1.6px solid currentColor;
  transform:rotate(45deg) translateY(-1px);
  transition:transform .2s ease;
}

/* ---- 31.1 Desktop: a panel on hover or keyboard focus -------------- */
@media (min-width:1025px){
  .gp-nav__group{ display:flex; align-items:center; }

  /* No JS on this breakpoint — :hover and :focus-within do the work. The
     button is removed outright rather than merely made unclickable:
     pointer-events:none still leaves it in the tab order, so keyboard
     users landed on a control that did nothing. The caret becomes a
     pseudo-element on the link, which cannot be focused at all. */
  .gp-nav__toggle{ display:none; }

  .gp-nav__top::after{
    content:""; display:inline-block; width:6px; height:6px;
    margin:-3px 0 0 8px;
    border-right:1.6px solid currentColor; border-bottom:1.6px solid currentColor;
    transform:rotate(45deg);
    transition:transform .2s ease;
  }
  .gp-nav__group:hover .gp-nav__top::after,
  .gp-nav__group:focus-within .gp-nav__top::after{
    transform:rotate(225deg) translate(-2px,-2px);
  }

  .gp-subnav{
    position:absolute; top:100%; left:50%; margin:10px 0 0 -130px;
    width:260px; padding:10px 0;
    display:flex; flex-direction:column;
    background:var(--c-white);
    border:1px solid var(--c-tint-1);
    box-shadow:0 26px 50px -28px rgba(51,41,40,.45);
    opacity:0; visibility:hidden; pointer-events:none;
    transition:opacity .18s ease, visibility .18s ease;
    z-index:30;
  }
  /* The 10px of breathing room above the panel is dead ground the mouse
     has to cross, and crossing it would drop :hover and snap the panel
     shut. This invisible strip spans that gap and belongs to the panel,
     so the group stays hovered the whole way down. It cannot open the
     panel by accident: while closed the panel is pointer-events:none. */
  .gp-subnav::before{
    content:""; position:absolute; left:0; right:0; top:-10px; height:10px;
  }
  .gp-nav__group:hover .gp-subnav,
  .gp-nav__group:focus-within .gp-subnav{
    opacity:1; visibility:visible; pointer-events:auto;
  }
  .gp-nav__group:hover .gp-nav__chev,
  .gp-nav__group:focus-within .gp-nav__chev{
    transform:rotate(225deg) translateY(-1px);
  }

  .gp-subnav a{
    display:flex; align-items:center; min-height:40px;
    padding:6px 20px; border:0;
    font-family:var(--f-ui); font-size:12px; font-weight:500;
    letter-spacing:.06em; text-transform:none; line-height:1.35;
    color:var(--c-ink); white-space:normal; text-align:left;
  }
  .gp-subnav a:hover{ background:var(--c-tint-3); color:var(--c-mid); border:0; }
  .gp-subnav a.gp-subnav__all{
    margin-top:6px; padding-top:12px;
    border-top:1px solid var(--c-tint-1);
    font-style:italic; color:var(--c-mid);
  }
}

/* ---- 31.2 Phones and tablets: accordion inside the drawer ---------- */
@media (max-width:1024px){
  /* The drawer is a column, but .gp-nav still carries flex-wrap:wrap from
     the desktop row it used to be. A wrapping COLUMN flex container that
     runs out of height starts a second column beside the first — so once
     these eight links made the list taller than the panel, Contact, Book
     Now and the phone number jumped into a column 81px off the right edge
     and the whole menu scrolled sideways. The panel scrolls vertically
     (overflow-y:auto), which is what it should do instead. */
  .gp-nav{ flex-wrap:nowrap; }

  .gp-nav__group{ display:block; border-bottom:1px solid var(--c-tint-1); }
  .gp-nav__top::after{ content:none; }   /* the real button shows here instead */
  .gp-nav__row{ justify-content:space-between; gap:8px; }

  /* The row owns the divider now, so the link must not draw its own. */
  .gp-nav .gp-nav__row .gp-nav__top{ flex:1 1 auto; border-bottom:0; }

  /* 48px square: the caret is its own tap target, separate from the link,
     so opening the list and going to the index page cannot be confused. */
  .gp-nav__toggle{
    flex:0 0 auto; width:48px; height:48px; margin-right:-12px;
    color:var(--c-mid);
  }
  .gp-nav__chev{ width:9px; height:9px; border-width:2px; }
  .gp-nav__group.is-sub-open .gp-nav__chev{ transform:rotate(225deg) translateY(-1px); }

  .gp-subnav{ display:none; padding:2px 0 12px; }
  .gp-nav__group.is-sub-open .gp-subnav{ display:flex; flex-direction:column; }

  /* display:flex, not the inline-flex these links inherit from .gp-nav a.
     Inline-flex shrink-wraps, so "Hair Restoration with PRP" laid out at
     its full intrinsic width and pushed the drawer's scrollable width to
     403px against a 322px panel — the menu scrolled sideways. Block-level
     flex fills the panel, so white-space:normal can actually wrap. */
  .gp-nav .gp-subnav a{
    display:flex;
    min-height:46px; padding:4px 0 4px 16px;
    border-bottom:0; border-left:1px solid var(--c-tint-1);
    font-size:11.5px; letter-spacing:.1em; text-transform:none;
    color:var(--c-mid); white-space:normal;
  }
  .gp-nav .gp-subnav a:hover{ color:var(--c-ink); }
  .gp-nav .gp-subnav .gp-subnav__all{ font-style:italic; }
}

/* ══════════════════════════════════════════════════════════════════
   32 · PHONE: STOP CROPPING THE MEDIA SLOTS

   Measured every hero and photoband at 375px. The slots are 4:5 and
   1:1 there, but almost none of the art is portrait, so `cover` was
   throwing away most of each frame:

     hero  4:5   svc-fillers / svc-relaxers / svc-prp / svc-iv  55%
                 hero-about                                     55%
                 svc-room                                       44%
                 svc-brand                                      40%
                 band-lips (the offers hero)                     65%
     band  1:1   band-room                                      58%
                 band-lips                                      56%
                 hero-services                                  55%
                 storefront.mp4                                 44%

   The 44% on the storefront clip was the worst of it in practice: it
   cut Phoebe off at the shins and took the top of the doorway with it.

   Five pages already ship a real 4:5 portrait cut behind a
   (max-width:767px) <source> — contact, reviews, results, services
   and Russian Lips. Those are the only slots that were ever correct,
   and this section leaves them exactly as they are: their art is
   already 4:5, so its own ratio and the slot's are the same number.
   ══════════════════════════════════════════════════════════════════ */
@media (max-width:767px){

  /* a) A section that actually plays a clip gets the clip's shape.
        Both clips are 576x1024, so 9:16 shows them whole. Only the
        band changes — the hero's 4:5 window keeps Phoebe, the tray,
        the chair and the neon sign, and loses ceiling and floor,
        which is a crop worth having for something above the fold. */
  .gp-hero--video .gp-photoband__media{ aspect-ratio:9/16; }

  /* b) Everywhere else the art is a landscape still. Rather than crop
        it to a portrait window, let it set the height of its own
        block: nothing is cut at any source ratio, and the wide 2.4:1
        cuts come out unchanged because 2.4:1 is what they already are.
        Scoped off .gp-hero--video so the clips above keep their slot. */
  .gp-hero:not(.gp-hero--video) .gp-hero__media,
  .gp-photoband:not(.gp-hero--video) .gp-photoband__media{
    aspect-ratio:auto;
    max-height:none;
  }
  .gp-hero:not(.gp-hero--video) .gp-hero__media img,
  .gp-photoband:not(.gp-hero--video) .gp-photoband__media img{
    position:relative;
    inset:auto;
    width:100%;
    height:auto;
    object-fit:contain;
    object-position:50% 50%;
  }
}

/* ══════════════════════════════════════════════════════════════════
   33 · DESKTOP: AIM THE TWO CROPS THAT MISSED THEIR SUBJECT

   The hero band is 2.4:1 and most of the photography is 16:9, so
   roughly a quarter of each frame is trimmed top and bottom. On six
   of the eight that is a normal editorial crop — the VERSA+ pack, the
   PRP arm, the About treatment shot and the bands all sit inside the
   window. Two did not, and both were aimed by the shared
   `center 34%` default rather than at their own subject:

     svc-relaxers  the Daxxify vial is taller than the window, and at
                   34% the window sat on the cap, cutting the brand
                   name off the label completely. 85% keeps the cap
                   and brings DAXXIFY back into frame.

     svc-brand     at 34% the window held blank wall and a sliver of
                   one gold letter — 44% of the frame was below it,
                   including the whole neon sign. 70% lands on the
                   shelf, the orchid, the full "Botox & Filler" neon
                   and the gold script.

   Below 768px both images are shown whole (section 32), so this only
   needs to apply where the 2.4:1 window exists.
   ══════════════════════════════════════════════════════════════════ */
@media (min-width:768px){
  .gp-hero__media img[src$="svc-relaxers.jpg"]{ object-position:50% 85%; }
  .gp-hero__media img[src$="svc-brand.jpg"]{    object-position:50% 70%; }
}

/* ══════════════════════════════════════════════════════════════════
   34 · DON'T LET THE HEIGHT CAP RE-CROP A BAND THAT ALREADY FITS

   .gp-photoband__media is aspect-ratio 2.4/1, which is exactly the
   shape the band art is cut to, so on paper nothing is trimmed. But
   it also carried max-height:520px, and past roughly 1250px of
   viewport the cap wins: at 1440 the slot wants 594px, gets 520, and
   the box becomes 2.74:1. A 2.4:1 file then loses 12% top and bottom
   and a 2.2:1 one loses 19% — cropping that reappears on wide
   monitors only, which is why the band measured clean at 1024.

   Raised to 600px to match .gp-hero__media, so the band is exact out
   to about 1440. Past that the cap bites again; the fix there is art
   wider than 2.4:1, not a taller band.
   ══════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════
   35 · A 2:3 PHOTOGRAPH IN THE SPLIT KEEPS ITS OWN SHAPE

   The IV photograph is 1060x1484 — portrait. Nothing landscape can
   hold it: the 4:3 card keeps 54% of the height and the 2.4:1 hero
   band keeps 30%, so the only honest desktop home for the full frame
   is a portrait slot. The split on the IV page is one, but its img
   carries aspect-ratio:4/5 (0.80 against the photo's 0.71), which
   would still shave 11% off. Let this one size itself instead.

   Keyed off the filename rather than a page class so the rule dies
   with the file if the art is ever swapped again.
   ══════════════════════════════════════════════════════════════════ */
.gp-split__media img[src$="split-iv.jpg"],
.gp-split__media--tall img[src$="split-iv.jpg"]{
  aspect-ratio:auto;
  height:auto;
  object-fit:contain;
}

/* ══════════════════════════════════════════════════════════════════
   36 · THE HERO CLIP GETS ITS OWN SHAPE ON PHONES TOO

   Section 32 did this for the band. The hero kept 4:5 because the
   room clip only lost ceiling and floor there — a crop worth having
   above the fold.

   The new clip is not that: it is a 9:16 reel with the gold wordmark
   along the top and three lip close-ups along the bottom, so a 4:5
   window clips the top of "Glow" AND cuts through all three circles —
   the two things the clip exists to show. Measured on six frames
   across its six seconds.

   So the hero media goes 9:16 wherever the section actually plays a
   clip. Cost: the media block is 667px instead of 469px on a 375px
   screen, which pushes the headline below the fold on a shorter
   phone. That is the trade for showing the reel whole, which is what
   was asked for.
   ══════════════════════════════════════════════════════════════════ */
@media (max-width:767px){
  /* 464/730, not 9/16: the clip is cropped to its useful band — 13px
     above the wordmark, 10px below the lip circles — so the slot
     matches the file and cover has nothing left to remove. 590px on a
     375px screen instead of 667, which buys back 77px of fold. */
  .gp-hero--video .gp-hero__media{ aspect-ratio:464/730; max-height:none; }
}

/* ══════════════════════════════════════════════════════════════════
   37 · REELS ON THE RESULTS PAGE

   Vertical clips as gallery content rather than as a backdrop, so
   they have to override the .gp-media__vid rules that pin a hero clip
   absolutely inside its slot and hide it above 767px.

   Two across from 641px up, one below. Each media box is 9:16 and the
   clip is cover — reel-lips-dose is 468x832 (0.5577 against 0.5625),
   which loses half a percent off the sides, and reel-lips-visit is
   exactly 9:16. Capped at 340px each so a pair does not turn into two
   600px-wide phone screens on a desktop monitor.
   ══════════════════════════════════════════════════════════════════ */
.gp-reels{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:28px;
  max-width:728px;
  margin:44px auto 0;
}
@media (max-width:640px){
  .gp-reels{ grid-template-columns:minmax(0,1fr); gap:32px; max-width:340px; }
}
.gp-reels__intro{ margin:0; }

.gp-reel{ margin:0; }
.gp-reel__media{
  position:relative;
  width:100%;
  aspect-ratio:9/16;
  overflow:hidden;
  background:var(--c-tint-2);
  box-shadow:var(--shadow-card);
}
.gp-reel .gp-reel__vid{
  display:block;
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
}
/* With prefers-reduced-motion the loader adds controls, and a control
   bar on an absolutely-positioned element sits under the crop. Let the
   clip lay itself out instead. */
.gp-reel .gp-reel__vid[controls]{
  position:relative; inset:auto;
  height:auto; object-fit:contain; background:#000;
}
.gp-reel__media:has(.gp-reel__vid[controls]){ aspect-ratio:auto; }

.gp-reel__cap{
  margin:14px 0 0;
  font-family:var(--f-ui);
  font-size:12.5px;
  line-height:1.5;
  letter-spacing:.02em;
  color:var(--c-mid);
  text-align:center;
}

/* ══════════════════════════════════════════════════════════════════
   38 · ONE PORTRAIT BOX FOR EVERY CARD TILE

   The card photographs come in two cuts: portrait pairs and faces at
   1286x1600, and a handful of 4:3 room and product shots. Letting each
   file keep its own ratio left short tiles sitting beside tall ones in
   the same row, with a band of white above the price.

   So the box is fixed and the photograph fits it, rather than the other
   way round. Every tile in a card grid takes the 1286x1600 portrait box
   and fills its own column. The portrait files land in it untouched; the
   4:3 ones are cropped left and right by cover, which on a room or a
   product shot costs nothing that matters. Cropping the other way, to
   4:3, would take 40% off the top and bottom of the before/after pairs,
   which on a face means foreheads and chins.

   No width cap here. An earlier pass capped the portrait tiles at the
   3-up column width so they matched across the services page's 3-up and
   2-up grids. With every tile on one ratio each grid is already
   internally consistent, and the cap only left the 2-up tiles floating
   in white gutters.
   ══════════════════════════════════════════════════════════════════ */
.gp-cards .gp-card__media{
  aspect-ratio:1286/1600;
}
.gp-cards .gp-card__media img{
  aspect-ratio:1286/1600;
  object-fit:cover;
  object-position:50% 50%;
}
