/* ============================================================
   BOWERS HOME SERVICES — Water and Pipe Safety Inspection funnel.

   ⛔ THE PALETTE IS NOT A DESIGN CHOICE. Chris ruled 21 Sep 2026:
   "Do not upgrade the palette. Match it exactly... He put a lot of
   work into that brand. His colors are pink and black with a little
   bit of white."

   Every token below was READ off bowersplumbingllc.com on 21 Sep 2026,
   not invented:
     primary / accent  #ED1872   (the magenta in his logo and CTAs)
     background        #FFFFFF
     text              #000000
     link              #CC1818
     heading font      Khand
     body font         Roboto
     border radius     2px
     button primary    square corners (0px), no shadow
     button secondary  black, 30px pill, no shadow

   The one deviation, and why: his site sets primary button TEXT to
   #333333 on #ED1872, which is 2.1:1 and unreadable. White on the same
   magenta is 4.1:1 and passes AA at the large bold size buttons use
   here. The colour he owns is unchanged; only the label is legible.

   LIGHT IS THE DEFAULT, because his brand is light. Dark is the
   override, expressed as [data-theme="dark"]. That is the reverse of
   the JC Plumbing build, where dark was the brand. Both ship a toggle
   (Chris's standing default), and both ship a print stylesheet.

   ⚠ THE LOGO IS WHITE-FILLED WITH A BLACK KEYLINE. It survives on
   white because of the keyline, and it sings on dark. Do not add a
   white plate behind it on dark.
   ============================================================ */

/* ============================================================
   1. TOKENS
   ============================================================ */
:root{
  /* ---- his brand, exactly ---- */
  --pink:        #ED1872;
  --pink-ink:    #FFFFFF;      /* label on pink — see header note */
  --pink-deep:   #C21460;      /* hover; a darkened --pink */

  /* ⛔ --pink-text IS NOT A SECOND BRAND COLOUR. It is --pink-deep reused
     for one job: SMALL pink TEXT on a light surface.

     Measured: #ED1872 on #FFFFFF is 4.22:1 and on #F6F6F7 is 3.91:1. The
     4.22 figure is often waved through as passing, but only "large text"
     may use the 3:1 threshold, and large text means 18.66px bold or 24px
     regular. The eyebrow is 16.3px at weight 600 and the card tag is
     14.4px, so both owe the full 4.5:1 and both were failing.

     #C21460 measures 5.89 on white and 5.46 on the alt ground. It is a
     darkened version of HIS pink, not a different hue, and it is used
     ONLY where pink type is small and the ground is light.

     ⛔ EVERY LARGE PINK SHAPE STAYS #ED1872 EXACTLY: buttons, the form
     card header, the closing slab, rules, the skewed eyebrow plate, and
     the pink word in the hero headline. Chris ruled the palette is
     matched, not improved. This token changes no shape, only small type. */
  --pink-text:   #C21460;
  --pink-wash:   #FDEAF2;      /* 6% pink on white, for tint plates */
  --black:       #000000;
  --white:       #FFFFFF;
  --link:        #CC1818;

  /* ---- surfaces ---- */
  --bg:          #FFFFFF;
  --bg-alt:      #F6F6F7;
  --bg-deep:     #111113;
  --card:        #FFFFFF;
  --line:        #E3E3E6;
  --line-strong: #000000;

  /* ---- ink ---- */
  --ink:         #000000;
  --ink-soft:    #4A4A4F;
  --ink-mute:    #6A6A71;    /* was #75757C: 4.23 on --bg-alt, under 4.5 */
  --ink-on-deep: #FFFFFF;

  /* ---- type ---- */
  --font-head: 'Khand', 'Oswald', sans-serif;
  --font-body: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* ---- geometry (his: 2px radius, 4px base unit) ---- */
  --r:      2px;
  --r-btn:  0px;
  --r-pill: 30px;
  --u:      4px;

  --shadow:    0 1px 2px rgba(0,0,0,.07), 0 8px 28px rgba(0,0,0,.07);
  --shadow-lg: 0 2px 6px rgba(0,0,0,.10), 0 24px 60px rgba(0,0,0,.14);

  --ease: cubic-bezier(.22,.61,.36,1);
  --container: 1180px;
}

[data-theme="dark"]{
  --bg:          #0E0E10;
  --bg-alt:      #17171A;
  --bg-deep:     #000000;
  --card:        #17171A;
  --line:        #2C2C31;
  --line-strong: #3A3A41;

  --ink:         #FFFFFF;
  --ink-soft:    #C4C4CB;
  --ink-mute:    #8E8E97;

  --pink-wash:   #2A0A18;
  --link:        #FF6B6B;
  --shadow:      0 1px 2px rgba(0,0,0,.5), 0 8px 28px rgba(0,0,0,.45);
  --shadow-lg:   0 2px 6px rgba(0,0,0,.55), 0 24px 60px rgba(0,0,0,.6);
}

/* ============================================================
   2. RESET + BASE
   ============================================================ */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:1.0625rem;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  transition:background .25s var(--ease), color .25s var(--ease);
}

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

h1,h2,h3,h4{
  font-family:var(--font-head);
  font-weight:700;
  line-height:1.04;
  letter-spacing:.005em;
  margin:0;
  text-wrap:balance;
}
h1{ font-size:clamp(2.6rem, 6.2vw, 4.3rem); text-transform:uppercase; }
h2{ font-size:clamp(2rem, 4.2vw, 3rem); text-transform:uppercase; }
h3{ font-size:clamp(1.4rem, 2.2vw, 1.75rem); }
p{ margin:0 0 1rem; }
strong{ font-weight:700; }

a{ color:var(--link); text-decoration-thickness:1px; text-underline-offset:2px; }
a:hover{ color:var(--pink); }

em{ font-style:normal; color:var(--pink); }

:focus-visible{ outline:3px solid var(--pink); outline-offset:3px; }

.container{
  width:100%;
  max-width:var(--container);
  margin-inline:auto;
  padding-inline:clamp(1.15rem, 4vw, 2.5rem);
}

/* Skip link — keyboard users land on the form, not the header. */
.skip{
  position:absolute; left:-9999px; top:0; z-index:200;
  background:var(--black); color:#fff; padding:.75rem 1.1rem;
  font-weight:700; text-decoration:none;
}
.skip:focus{ left:.5rem; top:.5rem; }

/* ============================================================
   3. BUTTONS — his geometry, not ours.
   Primary is SQUARE (0px) because his is. Secondary is a 30px pill
   because his is. Do not "harmonise" them; the mismatch is his brand.
   ============================================================ */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.6rem;
  font-family:var(--font-head);
  font-size:1.2rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase;
  padding:.95rem 1.9rem;
  border:2px solid transparent;
  border-radius:var(--r-btn);
  text-decoration:none; cursor:pointer;
  transition:background .18s var(--ease), color .18s var(--ease), transform .18s var(--ease);
}
.btn svg{ width:1.1em; height:1.1em; flex:none; }
.btn:active{ transform:translateY(1px); }

.btn--primary{ background:var(--pink); color:var(--pink-ink); }
.btn--primary:hover{ background:var(--pink-deep); color:#fff; }

.btn--dark{ background:var(--black); color:#fff; border-radius:var(--r-pill); }
.btn--dark:hover{ background:var(--pink); color:#fff; }

.btn--lg{ font-size:1.4rem; padding:1.15rem 2.3rem; }
.btn--block{ width:100%; }

/* ============================================================
   4. FUNNEL CHROME — header and footer.
   No navigation anywhere. The only way off an opt-in page is the form.
   ============================================================ */
.funnel-header{
  background:var(--bg);
  border-bottom:3px solid var(--pink);
  position:relative; z-index:20;
}
.funnel-header__inner{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding-block:.85rem;
}
.funnel-header--center .funnel-header__inner{ justify-content:center; position:relative; }
.funnel-header--center .header-cta{ position:absolute; right:clamp(1.15rem,4vw,2.5rem); }

.brand__logo{ width:clamp(158px, 22vw, 238px); height:auto; }

.header-tel{
  font-family:var(--font-head); font-size:1.28rem; font-weight:700;
  letter-spacing:.03em; color:var(--ink); text-decoration:none; white-space:nowrap;
}
.header-tel:hover{ color:var(--pink); }
.header-tel span{ color:var(--pink-text); }   /* 4.22 -> 5.89 on white */

/* ⛔ At 375px the logo, the phone and the toggle did not fit and the toggle
   was clipped off the right edge. Three things give way, in this order:
   the logo shrinks, the word "Call" goes, the number stays. The number is
   the point of the element; the label is decoration.

   ⛔ AND THE PHONE LINK IS A 44px TAP TARGET, measured, not assumed. It was
   28px tall. Joe will open this in his truck, and the header number is the
   single most likely thing a tradesman taps on a phone. A text link inherits
   the height of its text unless it is told otherwise. */
.header-tel{
  display:inline-flex; align-items:center;
  min-height:44px; padding-inline:.15rem;
}
@media (max-width:620px){
  .funnel-header__inner{ gap:.4rem; }
  .brand__logo{ width:clamp(116px, 33vw, 158px); }
  .header-tel{ font-size:1.05rem; }
  .header-tel .tel-word{ display:none; }
}

.theme-toggle{
  width:44px; height:44px; flex:none;    /* 44px minimum tap target */
  display:grid; place-items:center;
  background:transparent; color:var(--ink);
  border:1px solid var(--line); border-radius:var(--r);
  cursor:pointer; transition:border-color .18s var(--ease), color .18s var(--ease);
}
.theme-toggle:hover{ border-color:var(--pink); color:var(--pink); }
.theme-toggle svg{ width:19px; height:19px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; }
.theme-toggle .icon-moon{ display:none; }
[data-theme="dark"] .theme-toggle .icon-moon{ display:block; }
[data-theme="dark"] .theme-toggle .icon-sun{ display:none; }

.funnel-footer{
  background:var(--bg-deep); color:var(--ink-on-deep);
  padding-block:2.6rem; margin-top:0;
}
.funnel-footer__inner{ text-align:center; }
.funnel-footer .brand__logo{ margin-inline:auto; margin-bottom:1.1rem; }
.funnel-footer p{ margin:.3rem 0; font-size:.92rem; color:rgba(255,255,255,.7); }
.funnel-footer p strong{ color:#fff; }
/* The footer link stands on its own line rather than sitting inside a
   sentence, so the inline-link exemption does not cover it. It gets a real
   44px target like any other standalone control. */
.funnel-footer a{
  color:rgba(255,255,255,.7);
  display:inline-flex; align-items:center; min-height:44px; padding-inline:.4rem;
}
.funnel-footer a:hover{ color:var(--pink); }

/* ============================================================
   5. HERO — the opt-in page only.
   Photo left, form card right, collapsing to form-first on a phone.
   ============================================================ */
.hero{ position:relative; overflow:hidden; background:var(--bg-deep); }
.hero__bg{ position:absolute; inset:0; }
.hero__bg img{ width:100%; height:100%; object-fit:cover; object-position:center 32%; }
/* The scrim is what makes white type legible over a photograph. Both
   layers are needed: the vertical one lifts the top, the horizontal one
   protects the headline column on desktop. */
.hero__scrim{
  position:absolute; inset:0;
  background:
    linear-gradient(180deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.72) 55%, rgba(0,0,0,.86) 100%),
    linear-gradient(90deg, rgba(0,0,0,.72) 0%, rgba(0,0,0,.28) 62%, rgba(0,0,0,.45) 100%);
}
.hero__inner{ position:relative; z-index:2; padding-block:clamp(2.4rem, 6vw, 4.6rem); }

/* Three grid items, not two, so the phone can reorder them.
   Desktop: headline and proof stack in the left column, form on the right.
   Phone:   headline, then THE FORM, then proof. */
.hero__grid{
  display:grid;
  grid-template-columns:1.06fr .94fr;
  grid-template-areas:
    "copy  form"
    "aside form";
  gap:clamp(1.2rem, 2.4vw, 1.9rem) clamp(1.8rem, 4vw, 3.4rem);
  align-content:center;
}
.hero__copy { grid-area:copy; }
.hero__aside{ grid-area:aside; }
.hero__form { grid-area:form; align-self:center; }

@media (max-width:980px){
  .hero__grid{
    grid-template-columns:1fr;
    grid-template-areas:"copy" "form" "aside";
    gap:1.5rem;
  }
  /* ⛔ Measured at 375px: with proof above the form, the first field sat
     about 1,500px down. Trim what stands between the headline and the ask. */
  .hero__sub{ max-width:none; font-size:1.05rem; }
  .hero h1{ margin-bottom:.8rem; }
  /* Stays at large-text size on a phone; shrinking it reintroduced the
     contrast failure it was raised to solve. */
  .hero .eyebrow{ font-size:1.18rem; letter-spacing:.07em; padding:.28rem .62rem; }
}

.hero h1{ color:#fff; margin:.55rem 0 1.1rem; }
.hero h1 em{ color:var(--pink); }
.hero__sub{ color:rgba(255,255,255,.93); font-size:clamp(1.05rem,1.75vw,1.23rem); max-width:36ch; }
.hero__sub strong{ color:#fff; }
.hero__reason{
  color:rgba(255,255,255,.82); font-size:1rem; font-style:italic;
  border-left:3px solid var(--pink); padding-left:.95rem; max-width:40ch; margin-bottom:1.2rem;
}

.eyebrow{
  display:inline-block;
  font-family:var(--font-head); font-size:1.2rem; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; color:var(--pink-text);
}
.hero .eyebrow{ color:#fff; background:var(--pink); padding:.32rem .8rem; letter-spacing:.1em; }

.proofline{ display:flex; flex-wrap:wrap; gap:.5rem; margin-top:1.3rem; }
.chip{
  font-family:var(--font-head); font-size:.95rem; font-weight:600; letter-spacing:.05em;
  text-transform:uppercase;
  border:1px solid rgba(255,255,255,.4); color:#fff;
  padding:.28rem .7rem; border-radius:var(--r);
}

/* ============================================================
   6. THE FORM CARD
   ============================================================ */
.formcard{
  background:var(--card); color:var(--ink);
  border:3px solid var(--black);
  border-radius:var(--r);
  box-shadow:var(--shadow-lg);
  overflow:hidden;
}
.formcard__head{
  background:var(--pink); color:#fff;
  padding:.75rem 1.4rem;
  display:flex; align-items:center; justify-content:space-between; gap:.75rem;
}
.formcard__label{
  font-family:var(--font-head); font-size:1.24rem; font-weight:700;
  letter-spacing:.07em; text-transform:uppercase;
}
/* Keeps the card label on one line at 375px. */
@media (max-width:420px){
  .formcard__label{ font-size:1.18rem; letter-spacing:.035em; }  /* >=18.66px keeps it large text on pink */
  .formcard__head{ padding:.65rem 1.1rem; }
  .formcard form{ padding:1.25rem 1.1rem 1.1rem; }
}
.formcard__icon{ width:26px; height:26px; fill:none; stroke:#fff; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; flex:none; }
.formcard form{ padding:1.5rem 1.4rem 1.3rem; }

.field{ margin-bottom:.9rem; }
.field label{
  display:block; margin-bottom:.3rem;
  font-family:var(--font-head); font-size:1.05rem; font-weight:600;
  letter-spacing:.05em; text-transform:uppercase; color:var(--ink);
}
.field input{
  width:100%; padding:.8rem .9rem;
  font-family:var(--font-body); font-size:1.05rem; color:var(--ink);
  background:var(--bg); border:2px solid var(--line-strong); border-radius:var(--r);
  transition:border-color .16s var(--ease), box-shadow .16s var(--ease);
}
.field input::placeholder{ color:var(--ink-mute); }
/* ⛔ DO NOT PUT `outline:none` BACK HERE.
   It was here, paired with a border colour change and a 3px --pink-wash
   ring. --pink-wash is #FDEAF2, which is all but invisible on white, so a
   keyboard user was left with a border shifting from black to pink and
   nothing else. Removing the focus ring is the one accessibility failure
   rated CRITICAL, and a near-white glow does not replace it.

   A mouse click on an input does not match :focus-visible, so the visible
   ring appears for keyboard and AT users and never interrupts a tap. */
.field input:focus{ border-color:var(--pink); }
.field input:focus-visible{
  border-color:var(--pink);
  outline:3px solid var(--pink);
  outline-offset:2px;
}
.field input[aria-invalid="true"]{ border-color:var(--link); }

/* ⛔ A RED BORDER IS NOT AN ERROR MESSAGE.
   Colour alone carries no meaning for a colour-blind user and none at all
   for a screen reader. Each invalid field gets its own message, sitting
   directly under that input, tied to it with aria-describedby, and
   announced with role="alert". The message is hidden until it has text,
   so the form does not reserve a row of empty red space. */
.field__err{
  display:none;
  margin:.35rem 0 0;
  font-size:.86rem; font-weight:500; line-height:1.35;
  color:var(--link);
}
.field__err:not(:empty){ display:flex; align-items:flex-start; gap:.35rem; }
.field__err::before{ content:"!";
  flex:none; width:1.05em; height:1.05em; margin-top:.1em;
  display:grid; place-items:center;
  background:var(--link); color:#fff; border-radius:50%;
  font-size:.75em; font-weight:700;
}

.microcopy{ margin:.7rem 0 .55rem; font-size:.93rem; color:var(--ink-soft); text-align:center; }
.consent{ margin:0; font-size:.735rem; line-height:1.5; color:var(--ink-mute); }
.consent a{ color:var(--ink-soft); }

.formnote{
  margin:.9rem 0 0; padding:.65rem .8rem;
  font-size:.86rem; line-height:1.45;
  background:var(--pink-wash); border-left:3px solid var(--pink); color:var(--ink-soft);
}

/* ============================================================
   7. SECTIONS
   ============================================================ */
.section{ padding-block:clamp(2.8rem, 6vw, 4.6rem); }
.section--alt{ background:var(--bg-alt); }
.section--deep{ background:var(--bg-deep); color:var(--ink-on-deep); }
/* On a near-black ground #ED1872 measures 4.97:1, so the true brand pink
   is both correct and required here. --pink-text would be needlessly dim.

   ⛔ .hero .eyebrow IS NOT IN THIS LIST, and must never be added to it.
   The hero eyebrow is WHITE type on a pink plate, not pink type on a dark
   ground. It was briefly included here, this rule won on source order over
   the white declaration in section 5, and the label rendered pink on pink:
   invisible. Caught in a screenshot, not by the contrast script, because
   the script cannot see a ::before plate. */
.section--deep .eyebrow, .slab .eyebrow{ color:var(--pink); }
.section--deep .ocard__tag{ color:var(--pink); font-size:1.02rem; }
[data-theme="dark"] .eyebrow, [data-theme="dark"] .ocard__tag,
[data-theme="dark"] .stepbar__label strong{ color:var(--pink); }
.section--deep h2, .section--deep h3{ color:#fff; }
.section--deep p{ color:rgba(255,255,255,.82); }
.section--tight{ padding-block:clamp(2rem, 4vw, 3rem); }

.section-head{ margin-bottom:2rem; }
.section-head--center{ text-align:center; }
.section-head .eyebrow{ margin-bottom:.5rem; }
.section-head p{ color:var(--ink-soft); max-width:62ch; }
.section-head--center p{ margin-inline:auto; }

.rule{ width:64px; height:4px; background:var(--pink); border:0; margin:.85rem 0 0; }
.section-head--center .rule{ margin-inline:auto; }

.cardgrid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(270px,1fr)); gap:1.25rem; }

.ocard{
  background:var(--card);
  border:1px solid var(--line);
  border-top:4px solid var(--pink);
  border-radius:var(--r);
  padding:1.5rem 1.35rem;
}
.ocard__tag{
  display:inline-block; margin-bottom:.5rem;
  font-family:var(--font-head); font-size:.9rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase; color:var(--pink-text);
}
.ocard h3{ margin-bottom:.6rem; }
.ocard p{ color:var(--ink-soft); margin:0; }
.ocard p + p{ margin-top:.7rem; }
.section--deep .ocard{ background:rgba(255,255,255,.05); border-color:rgba(255,255,255,.14); }
.section--deep .ocard p{ color:rgba(255,255,255,.8); }

/* Numbered chapters on the thank-you page. */
.chapter{ display:grid; grid-template-columns:auto 1fr; gap:clamp(1rem,3vw,2.2rem); align-items:start; }
.chapter__num{
  font-family:var(--font-head); font-size:clamp(3.4rem,7vw,5.2rem); font-weight:700; line-height:.85;
  color:transparent; -webkit-text-stroke:2px var(--pink); letter-spacing:-.02em;
}
.chapter h2{ margin-bottom:.75rem; }
.chapter p{ color:var(--ink-soft); max-width:66ch; }
.section--deep .chapter p{ color:rgba(255,255,255,.82); }

.ticklist{ list-style:none; margin:1rem 0 0; padding:0; }
.ticklist li{ position:relative; padding-left:1.9rem; margin-bottom:.6rem; color:var(--ink-soft); }
.ticklist li::before{
  content:""; position:absolute; left:0; top:.52em;
  width:11px; height:11px; background:var(--pink); border-radius:var(--r);
}
.section--deep .ticklist li{ color:rgba(255,255,255,.85); }

/* ============================================================
   8. STEP BAR + BOOKING PAGE
   ============================================================ */
.book-top{ padding-block:clamp(1.8rem,4vw,2.8rem) 0; text-align:center; }
.book-top--tight{ padding-bottom:0; }
.book-top h1{ margin:.7rem 0 .5rem; }
.book-sub{ color:var(--ink-soft); font-size:1.1rem; max-width:52ch; margin-inline:auto; }

.stepbar{ max-width:520px; margin:0 auto 1.4rem; }
.stepbar__label{
  display:flex; justify-content:space-between; align-items:baseline;
  font-family:var(--font-head); font-size:1rem; font-weight:600;
  letter-spacing:.11em; text-transform:uppercase; margin-bottom:.45rem;
}
.stepbar__label span{ color:var(--ink-mute); }
.stepbar__label strong{ color:var(--pink-text); }
.stepbar__track{ height:7px; background:var(--line); border-radius:var(--r); overflow:hidden; }
.stepbar__fill{ height:100%; background:var(--pink); border-radius:var(--r); }

.confirm-icon{
  width:62px; height:62px; margin:0 auto 1rem;
  display:grid; place-items:center;
  background:var(--pink); border-radius:50%;
}
.confirm-icon svg{ width:31px; height:31px; fill:none; stroke:#fff; stroke-width:3; stroke-linecap:round; stroke-linejoin:round; }

.book-cal{ padding-block:1.6rem clamp(2.4rem,5vw,3.4rem); }
/* ⛔ HEIGHT FLOOR — half 1 of the height guard; the JS in the page is
   half 2. Both are required. A booking widget is loaded position:absolute
   by its own script, so this wrapper reports height 0 and the fine print
   lays out over the calendar. Ported from the JC build, where it was
   measured against a real embed. */
.cal-frame{
  min-height:640px; max-width:860px; margin-inline:auto;
  background:var(--bg-alt); border:1px solid var(--line); border-radius:var(--r);
}
.cal-frame iframe{ width:100%; border:none; }
@media (max-width:620px){ .cal-frame{ min-height:760px; } }

/* A placeholder reserves space. It never speaks. */
.ph--silent{ min-height:inherit; display:grid; place-items:center; }
.ph__mark svg{ width:56px; height:56px; fill:none; stroke:var(--line); stroke-width:1.3; stroke-linecap:round; stroke-linejoin:round; }

.book-note{ text-align:center; margin:1.5rem auto 0; max-width:46ch; color:var(--ink-soft); font-size:.98rem; }
.book-note strong{ color:var(--ink); }

/* The phone fallback under the calendar is a real button, not a sentence.
   Someone who cannot find a workable slot is the most likely person on this
   page to leave, and "call us" buried in grey prose does not catch them. */
.book-call{
  display:inline-flex; align-items:center; justify-content:center; gap:.55rem;
  min-height:48px; margin-top:.9rem; padding:.55rem 1.3rem;
  font-family:var(--font-head); font-size:1.2rem; font-weight:700;
  letter-spacing:.03em; text-transform:uppercase; text-decoration:none;
  color:var(--ink); background:transparent;
  border:2px solid var(--line-strong); border-radius:var(--r);
  transition:background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.book-call svg{ width:1.05em; height:1.05em; flex:none; }
.book-call:hover{ background:var(--pink); border-color:var(--pink); color:#fff; }

/* ============================================================
   20. WHAT HAPPENS NEXT — the three beats after a booking.

   This is not filler. Setting expectations between booking and arrival is
   the cheapest no-show reduction there is, and Joe is paying for booked
   jobs, not booked calendar slots. It sits BELOW the calendar so it can
   never push the booker down the page.
   ============================================================ */
.nextsteps{ display:grid; grid-template-columns:repeat(3,1fr); gap:1px; background:var(--line); border:1px solid var(--line); }
.nextstep{ background:var(--card); padding:1.5rem 1.3rem; }
.nextstep__n{
  display:inline-grid; place-items:center;
  width:34px; height:34px; margin-bottom:.8rem;
  background:var(--pink); color:#fff; border-radius:var(--r);
  /* 1.2rem = 19.2px, which clears the 18.66px large-text floor. At 1.15rem
     this numeral was 18.4px and its white-on-pink 4.22:1 owed the full 4.5. */
  font-family:var(--font-head); font-size:1.2rem; font-weight:700; line-height:1;
}
.nextstep h3{ font-size:1.22rem; margin-bottom:.35rem; }
.nextstep p{ margin:0; color:var(--ink-soft); font-size:.96rem; }
@media (max-width:760px){
  .nextsteps{ grid-template-columns:1fr; }
  .nextstep{ padding:1.2rem 1.15rem; display:grid; grid-template-columns:auto 1fr; gap:.2rem .85rem; align-items:center; }
  .nextstep__n{ margin:0; grid-row:1; }
  .nextstep h3{ grid-column:2; margin:0; }
  .nextstep p{ grid-column:1 / -1; margin-top:.5rem; }
}

/* ============================================================
   9. THE VIDEO FRAME — thank-you page
   ============================================================ */
.vsl{ max-width:820px; margin:1.6rem auto 0; }
.vsl__frame{
  position:relative; aspect-ratio:16/9;
  background:var(--bg-deep);
  border:3px solid var(--black); border-radius:var(--r);
  overflow:hidden; display:grid; place-items:center;
}
[data-theme="dark"] .vsl__frame{ border-color:var(--pink); }
.vsl__frame iframe, .vsl__frame video{ position:absolute; inset:0; width:100%; height:100%; border:none; }
.vsl__frame .ph__mark svg{ stroke:rgba(255,255,255,.28); width:66px; height:66px; }
.undervideo{ text-align:center; margin:1rem 0 0; color:var(--ink-soft); }

/* ============================================================
   10. REVEAL — content is VISIBLE by default.
   html.js-anim is added by js/aw.js only inside the animated branch,
   immediately before the observer that un-hides. If the script never
   loads, or anything above it throws, the page still reads.
   ============================================================ */
.js-anim .reveal{ opacity:0; transform:translateY(14px); }
.js-anim .reveal.is-in{
  opacity:1; transform:none;
  transition:opacity .6s var(--ease), transform .6s var(--ease);
  transition-delay:calc(var(--d,0) * 90ms);
}
@media (prefers-reduced-motion: reduce){
  .js-anim .reveal{ opacity:1 !important; transform:none !important; }
}

/* ============================================================
   11. PRINT — Chris's standing default: every build ships one.
   Ink-friendly: photo scrims, the form, the calendar and the video
   frame are all meaningless on paper.
   ============================================================ */
@media print{
  :root{ --bg:#fff; --ink:#000; --ink-soft:#222; }
  body{ background:#fff; color:#000; font-size:11pt; }
  .hero__bg, .hero__scrim, .theme-toggle, .btn, .formcard,
  .cal-frame, .vsl, .second-cta, .stepbar{ display:none !important; }
  .hero{ background:#fff; }
  .hero h1, .hero__sub, .hero__reason, .chip{ color:#000 !important; }
  .chip{ border-color:#000; }
  .section--deep, .funnel-footer{ background:#fff !important; color:#000 !important; }
  .section--deep h2, .section--deep h3, .funnel-footer p strong{ color:#000 !important; }
  .section--deep p, .funnel-footer p, .funnel-footer a{ color:#222 !important; }
  .chapter__num{ -webkit-text-stroke:1px #000; }
  a[href^="http"]::after{ content:" (" attr(href) ")"; font-size:9pt; color:#444; }
  .section{ padding-block:1.2rem; break-inside:avoid; }
}

/* ============================================================
   12. MOBILE CTA — the one extra call to action, phones only.
   ============================================================ */
.second-cta{ display:none; }
@media (max-width:980px){ .second-cta{ display:block; } }

/* ============================================================
   13. THE SLANT — the one brand motif worth borrowing.

   His wordmark is set on an italic slant. Nothing else on his site
   picks that up. Repeating a shallow -8deg skew on the accent shapes
   (eyebrow badge, trust strip dividers, section flags) makes the page
   feel drawn FROM the logo rather than merely placed near it.

   ⛔ Text is never skewed, only the plate behind it. Skewed type at
   small sizes is a legibility problem, and Khand is already condensed.
   ============================================================ */
.slant{ position:relative; display:inline-block; }
.slant > span{ position:relative; z-index:1; }
.slant::before{
  content:""; position:absolute; inset:-.18em -.62em;
  background:var(--pink); transform:skewX(-8deg); z-index:0;
}

/* ============================================================
   14. TRUST STRIP — the proof bar under the hero.
   Four facts, all verifiable. The pattern this page follows
   (Trust and Authority + Conversion) names missing certifications as
   its single worst anti-pattern, so the license number is not
   decoration, it is the point.
   ============================================================ */
.trustbar{ background:var(--black); color:#fff; }
.trustbar__grid{
  display:grid; grid-template-columns:repeat(4, 1fr);
  align-items:center;
}
.trustbar__item{
  display:flex; align-items:center; gap:.7rem;
  padding:1.05rem .4rem;
  border-left:1px solid rgba(255,255,255,.14);
}
.trustbar__item:first-child{ border-left:0; }
.trustbar__item svg{
  width:23px; height:23px; flex:none;
  fill:none; stroke:var(--pink); stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round;
}
.trustbar__item b{
  display:block;
  font-family:var(--font-head); font-size:1.08rem; font-weight:600;
  letter-spacing:.055em; text-transform:uppercase; line-height:1.15;
}
.trustbar__item small{ display:block; font-size:.775rem; color:rgba(255,255,255,.58); letter-spacing:.01em; }
@media (max-width:900px){
  .trustbar__grid{ grid-template-columns:repeat(2, 1fr); }
  .trustbar__item:nth-child(3){ border-left:0; }
  .trustbar__item:nth-child(n+3){ border-top:1px solid rgba(255,255,255,.14); }
}
@media (max-width:460px){
  .trustbar__item{ padding:.85rem .3rem; }
  .trustbar__item b{ font-size:.97rem; }
}

/* ============================================================
   15. CHECK GRID — what we actually look at.
   The education play. This is the section that makes the offer a
   real thing rather than a coupon, so it gets the most air.
   ============================================================ */
.checkgrid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(258px,1fr)); gap:1px; background:var(--line); border:1px solid var(--line); }
.checkitem{ background:var(--card); padding:1.7rem 1.45rem; }
.checkitem__ico{
  width:46px; height:46px; margin-bottom:.95rem;
  display:grid; place-items:center;
  background:var(--pink-wash); border-radius:var(--r);
}
.checkitem__ico svg{ width:24px; height:24px; fill:none; stroke:var(--pink); stroke-width:1.75; stroke-linecap:round; stroke-linejoin:round; }
.checkitem h3{ font-size:1.32rem; margin-bottom:.4rem; }
.checkitem p{ margin:0; color:var(--ink-soft); font-size:.975rem; }

/* ⛔ MEASURED: stacked on a phone these six cards ran 1,741px, the longest
   block on the page by far, and the icon sitting on its own line above each
   heading was buying nothing. Below 620px the icon moves INTO the heading
   row, which returns roughly 60px per card. The icon shrinks with it, since
   at that size it is a marker, not an illustration. */
@media (max-width:620px){
  .checkitem{
    padding:1.25rem 1.15rem;
    display:grid; grid-template-columns:auto 1fr; gap:.2rem .85rem;
    align-items:center;
  }
  .checkitem__ico{ width:38px; height:38px; margin:0; grid-row:1; }
  .checkitem__ico svg{ width:20px; height:20px; }
  .checkitem h3{ grid-column:2; margin:0; font-size:1.22rem; }
  .checkitem p{ grid-column:1 / -1; margin-top:.5rem; }
}

/* ============================================================
   16. SIGNS — the self-diagnosis list.
   Two columns of symptoms on a black ground. A reader who ticks two
   of these has already sold themselves; the list does the work.
   ============================================================ */
.signs{ display:grid; grid-template-columns:repeat(auto-fit, minmax(310px,1fr)); gap:.55rem 2.2rem; margin-top:1.8rem; }
.sign{
  display:flex; align-items:flex-start; gap:.85rem;
  padding:.8rem 0; border-bottom:1px solid rgba(255,255,255,.12);
}
.sign__box{
  width:22px; height:22px; flex:none; margin-top:.15rem;
  border:2px solid var(--pink); border-radius:var(--r);
  display:grid; place-items:center;
}
.sign__box svg{ width:13px; height:13px; fill:none; stroke:var(--pink); stroke-width:3.2; stroke-linecap:round; stroke-linejoin:round; }
.sign p{ margin:0; color:rgba(255,255,255,.88); font-size:1.02rem; }

/* ============================================================
   17. THE REASON — Joe's own voice, set as a pull quote.
   ⛔ The attribution line is a placeholder like everything else.
   Nothing here may be published as Joe's words until he says it.
   ============================================================ */
.reasonblock{
  border-left:5px solid var(--pink);
  padding:.35rem 0 .35rem 1.7rem;
  max-width:60ch;
}
.reasonblock p{ font-size:clamp(1.12rem,2vw,1.35rem); line-height:1.5; color:var(--ink); }
.reasonblock cite{
  display:block; margin-top:.9rem; font-style:normal;
  font-family:var(--font-head); font-size:1.05rem; font-weight:600;
  letter-spacing:.09em; text-transform:uppercase; color:var(--ink-mute);
}

/* ============================================================
   18. CLOSING SLAB — full pink, one instruction.
   ============================================================ */
.slab{ background:var(--pink); color:#fff; text-align:center; padding-block:clamp(3rem,6vw,4.6rem); }
.slab h2{ color:#fff; }
/* ⛔ White on #ED1872 is 4.22:1, which only clears the bar as LARGE text.
   The line is short, so it is set at 18.9px/700 rather than diluting his
   pink or dropping to black text under a white heading. */
.slab p{
  color:#fff; max-width:48ch; margin-inline:auto;
  font-size:1.18rem; font-weight:700;
}
.slab .btn--dark{ background:var(--black); color:#fff; border-radius:var(--r-btn); }
.slab .btn--dark:hover{ background:#fff; color:var(--pink); }

/* ============================================================
   19. STICKY MOBILE BAR — phones only.
   Two thumb-sized targets, both at least 44px tall, sitting above the
   home indicator. It appears only AFTER the hero form has scrolled
   away, so it never competes with the form itself.
   ============================================================ */
.thumbbar{ display:none; }
@media (max-width:980px){
  .thumbbar{
    display:grid; grid-template-columns:1fr 1fr;
    position:fixed; left:0; right:0; bottom:0; z-index:60;
    background:var(--black);
    padding-bottom:env(safe-area-inset-bottom);
    border-top:2px solid var(--pink);
    transform:translateY(105%);
    transition:transform .28s var(--ease);
  }
  .thumbbar.is-up{ transform:none; }
  .thumbbar a{
    min-height:54px;
    display:flex; align-items:center; justify-content:center; gap:.5rem;
    font-family:var(--font-head); font-size:1.2rem; font-weight:700;
    letter-spacing:.05em; text-transform:uppercase; text-decoration:none;
  }
  .thumbbar a svg{ width:1.05em; height:1.05em; }
  .thumbbar__call{ color:#fff; }
  .thumbbar__apply{ background:var(--pink); color:#fff; }
  /* On the booking page there is nothing to "apply" for any more, so the bar
     carries the single fallback action across the full width. */
  .thumbbar--single{ grid-template-columns:1fr; }
  .thumbbar--single .thumbbar__call{ background:var(--pink); }
  /* Clear the bar so the footer's last line is never trapped under it. */
  .funnel-footer{ padding-bottom:calc(2.6rem + 54px + env(safe-area-inset-bottom)); }
}
@media print{ .thumbbar{ display:none !important; } }
