/* Bright Solutions of Ohio. Palette sampled from their own live site:
   green #8DC63F against near-black, which is their existing wordmark.
   Structure inherited from the Affordable Air build so the whole system,
   templates, nav, schema, lazy loading and audit, carries across unchanged. */

/* NAMES ARE INHERITED, VALUES ARE BRIGHT SOLUTIONS. The variable names came from
   the Affordable Air build and were kept so the shared templates, nav, schema and
   audit carry across untouched. That is why --red holds a green and --navy holds
   a charcoal. Read the value, not the name.

   De-navied Aug 17, 2026. Every dark surface on this site (top strip, hero panel,
   service areas band, lead band, footer, mobile call bar) was still rendering in
   Affordable Air's navy #0E2E47, and every muted grey carried a blue cast. Their
   own wordmark is green on near-black, so navy was never their colour. */
:root {
  --red: #8DC63F;
  --red-deep: #75A831;
  --blue: #1B1B1B;
  --blue-deep: #000000;
  --navy: #1B1B1B;
  --navy-2: #2E2E2E;
  --ink: #1B1B1B;
  --body: #4A4A4A;
  --muted: #737373;
  --line: #E2E2E2;
  --wash: #F6F6F5;
  --paper: #FFFFFF;
  --radius: 12px;
  --shadow: 0 10px 30px rgba(27, 27, 27, 0.10);
  --shadow-lg: 0 20px 50px rgba(27, 27, 27, 0.18);
  --wrap: 1180px;

  /* Hero scrim. Charcoal, matching --blue #1B1B1B, NOT the Affordable Air navy
     this build inherited. --scrim is the strength dial and is overridden per
     hero, because the six finished heroes are not equally bright: measured over
     the headline zone their brightest cells run from 101 to 182. One flat value
     cannot serve both ends. It either leaves the bright hero unreadable or turns
     the dark ones into a black bar with a photo faintly behind it.
     Default is the floor: just enough separation for white text on a dusk hero. */
  --scrim-rgb: 27, 27, 27;
  --scrim: .20;
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  color: var(--body);
  background: var(--paper);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  padding-bottom: 60px; /* clears the fixed mobile call bar */
}
@media (min-width: 861px) { body { padding-bottom: 0; } }

h1, h2, h3, h4 { color: var(--ink); line-height: 1.2; margin: 0 0 12px; font-weight: 800; letter-spacing: -0.01em; }
h1 { font-size: clamp(2rem, 4.4vw, 3.05rem); }
h2 { font-size: clamp(1.55rem, 3vw, 2.2rem); }
h3 { font-size: 1.2rem; }
p { margin: 0 0 16px; }
a { color: var(--blue-deep); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }
.wrap { width: min(100% - 40px, var(--wrap)); margin-inline: auto; }
.eyebrow { color: var(--red); font-weight: 800; font-size: 0.78rem; letter-spacing: 0.16em; text-transform: uppercase; margin-bottom: 10px; }
.lede { font-size: 1.1rem; color: var(--body); }
section { padding: 64px 0; }
.section-head { max-width: 780px; margin-bottom: 32px; }
.section-head.center { margin-inline: auto; text-align: center; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 28px; border-radius: 999px; font-weight: 800; font-size: 1rem;
  background: var(--red); color: #fff; border: 2px solid var(--red);
  cursor: pointer; transition: transform .12s ease, background .12s ease;
  text-align: center;
}
.btn:hover { background: var(--red-deep); border-color: var(--red-deep); color: #fff; text-decoration: none; transform: translateY(-1px); }
.btn.blue { background: var(--blue); border-color: var(--blue); }
.btn.blue:hover { background: var(--blue-deep); border-color: var(--blue-deep); }
.btn.ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,.75); }
.btn.ghost:hover { background: rgba(255,255,255,.14); }
/* Header pairing: call stays the red primary because a ringing phone is the
   money, and Schedule Service sits beside it as the outlined secondary. */
.btn.ghost-blue { background: transparent; color: var(--blue-deep); border-color: var(--blue); }
.btn.ghost-blue:hover { background: var(--blue); color: #fff; border-color: var(--blue); }
.btn.wide { width: 100%; }

/* ---------- Top strip + header ---------- */
.topstrip { background: var(--navy); color: #D8D8D8; font-size: 0.86rem; }
.topstrip .wrap { display: flex; gap: 18px; justify-content: space-between; align-items: center; padding: 9px 0; flex-wrap: wrap; }
.topstrip a { color: #fff; font-weight: 700; }
.topstrip .badges { display: flex; gap: 18px; flex-wrap: wrap; }
@media (max-width: 700px) { .topstrip .badges { display: none; } }

/* White header with the full-colour mark, which is how Affordable Air actually
   present themselves on their own site and signage. The white-only SVG is kept
   for the dark footer. Logo art was trimmed of 503px of dead margin top and
   bottom before use, so the height below is real logo rather than empty space. */
header.site { background: #fff; position: sticky; top: 0; z-index: 50; box-shadow: 0 2px 14px rgba(27,27,27,.12); border-bottom: 1px solid var(--line); }
/* The header gets a wider track than the content. Seven nav groups plus two
   buttons plus the logo measures 1227px; the 1180px content wrap could never
   hold it at any viewport size, which is what was squashing the logo. Content
   stays at 1180 for readable line lengths. */
header.site .wrap { width: min(100% - 40px, 1240px); display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 12px 0; }
/* flex: none is load bearing. Without it the logo is a shrinkable flex item, and
   once the nav grew past the available width it squashed horizontally while the
   fixed height held, distorting the mark to a 0.84 ratio against its natural
   1.67. Measured, not eyeballed. */
header.site .logo { flex: none; display: block; }
header.site .logo img { height: 56px; width: auto; max-width: none; }
/* ---------- Dropdown navigation ----------
   :hover for mice, :focus-within so it also opens on keyboard tab. No JS.
   The padding-bottom on the trigger bridges the gap to the panel, otherwise the
   menu closes as the pointer crosses the space between them. */
.has-menu { position: relative; }
.has-menu > a { display: inline-flex; align-items: center; gap: 6px; padding: 22px 0; }
.has-menu > a::after { content: ""; width: 7px; height: 7px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translateY(-2px); opacity: .55; }
.menu {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%) translateY(6px);
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); padding: 10px; min-width: 250px;
  opacity: 0; visibility: hidden; transition: opacity .14s ease, transform .14s ease; z-index: 60;
}
.has-menu:hover > .menu, .has-menu:focus-within > .menu { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
.menu a { display: block; padding: 9px 14px; border-radius: 8px; font-size: 0.93rem; font-weight: 600; color: var(--ink); white-space: nowrap; }
.menu a:hover { background: var(--wash); color: var(--blue-deep); text-decoration: none; }
.menu a.head { font-weight: 800; color: var(--blue-deep); border-bottom: 1px solid var(--line); border-radius: 8px 8px 0 0; margin-bottom: 4px; }
/* The service-area list is 13 long, so it runs in columns instead of a scroll. */
.menu.cols { display: grid; grid-template-columns: repeat(2, minmax(180px, 1fr)); gap: 0 6px; min-width: 400px; }
.menu.cols a.head { grid-column: 1 / -1; }

/* Six nav items plus two buttons is a lot of horizontal budget. nowrap stops
   "Water Heaters" and "Service Areas" folding onto two lines, which is what
   they did the moment the dropdowns added their carets. */
nav.main { display: flex; align-items: center; gap: 15px; }
nav.main > a, nav.main .has-menu > a { white-space: nowrap; }
nav.main a { color: var(--ink); font-weight: 700; font-size: 0.92rem; }
nav.main a:hover { color: var(--blue-deep); }
nav.main a.btn { color: #fff; }
nav.main a.btn.ghost-blue { color: var(--blue-deep); }
nav.main a.btn.ghost-blue:hover { color: #fff; }
@media (max-width: 1120px) { nav.main > a:not(.btn), nav.main .has-menu { display: none; } }

/* ---------- Mobile navigation ----------
   Desktop keeps the CSS dropdowns. Below 1180px those are hidden entirely and
   this panel takes over, because hover does not exist on a phone and the site
   has 31 nav destinations. Groups are native <details>, so expanding them needs
   no JavaScript and stays accessible. */
.navtoggle {
  display: none; width: 46px; height: 42px; border: 1px solid var(--line);
  background: #fff; border-radius: 10px; cursor: pointer; padding: 0;
  flex-direction: column; align-items: center; justify-content: center; gap: 5px;
}
.navtoggle span { display: block; width: 22px; height: 2px; background: var(--ink); border-radius: 2px; transition: transform .2s ease, opacity .2s ease; }
body.nav-open .navtoggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
body.nav-open .navtoggle span:nth-child(2) { opacity: 0; }
body.nav-open .navtoggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (max-width: 1120px) { .navtoggle { display: flex; } }

.mobilenav {
  position: fixed; inset: 0; z-index: 90; background: rgba(27,27,27,.55);
  opacity: 0; transition: opacity .2s ease;
}
body.nav-open .mobilenav { opacity: 1; }
.mn-inner {
  position: absolute; top: 0; right: 0; bottom: 0; width: min(88vw, 400px);
  background: #fff; overflow-y: auto; padding: 18px 18px 40px;
  transform: translateX(100%); transition: transform .22s ease;
  box-shadow: -10px 0 40px rgba(27,27,27,.28);
}
body.nav-open .mn-inner { transform: translateX(0); }
.mn-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.mn-head img { height: 44px; }
.mn-close { border: 0; background: none; font-size: 1.9rem; line-height: 1; color: var(--muted); cursor: pointer; padding: 4px 8px; }
.mobilenav a, .mobilenav summary {
  display: block; padding: 13px 12px; border-radius: 9px; font-weight: 700;
  color: var(--ink); font-size: 1rem; border-bottom: 1px solid var(--line);
}
.mobilenav a:hover, .mobilenav summary:hover { background: var(--wash); text-decoration: none; }
.mobilenav summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; align-items: center; }
.mobilenav summary::-webkit-details-marker { display: none; }
.mobilenav summary::after { content: "+"; font-size: 1.3rem; color: var(--blue); font-weight: 400; }
.mobilenav details[open] > summary::after { content: "\2212"; }
.mobilenav details[open] > summary { color: var(--blue-deep); }
.mobilenav details a { padding-left: 26px; font-weight: 600; font-size: 0.95rem; color: var(--body); border-bottom: 0; }
.mn-cta { display: grid; gap: 10px; margin-top: 20px; }
.mn-cta .btn { width: 100%; }
body.nav-open { overflow: hidden; }
/* Two buttons plus a logo will not fit a phone. The mobile call bar is already
   pinned to the bottom of every page, so the header keeps Schedule Service and
   drops the duplicate call button rather than squeezing both. */
/* Raised 620 -> 780 on Aug 17, 2026. The logo plus TWO pill buttons plus the
   toggle measures about 700px before the wrap padding, so between 620 and 780
   the phone button was pushed off the right edge. Dropping it is safe: the
   fixed call bar at the bottom of every page carries the number on mobile. */
@media (max-width: 780px) {
  header.site .logo img { height: 42px; }
  nav.main a.btn { padding: 11px 15px; font-size: 0.88rem; }
  nav.main a.btn:not(.ghost-blue) { display: none; }
}

/* ---------- Manufacturer / accreditation badge row ---------- */
.badgerow { background: #fff; border-bottom: 1px solid var(--line); }
.badgerow .wrap { display: flex; align-items: center; justify-content: center; gap: 20px 46px; flex-wrap: wrap; padding: 26px 0; }
.badgerow img { height: 54px; width: auto; opacity: .92; }
.badgerow img.tall { height: 72px; }
@media (max-width: 560px) { .badgerow img { height: 40px; } .badgerow img.tall { height: 54px; } }

/* Wide photo band. A cropping band for photography, and a "show it whole" mode
   for supplied marketing banners, which have their own composition and get
   beheaded by object-fit: cover. */
.photoband img { width: 100%; height: clamp(190px, 26vw, 330px); object-fit: cover; border-radius: var(--radius); }
.photoband.whole img { height: auto; object-fit: contain; }
.club-card img.shield { width: 190px; margin: 0 auto 6px; }

/* Icons in the trust bar under the hero */
.trustbar .ti { width: 30px; height: 30px; margin: 0 auto 7px; display: block; }
.trustbar .ti path, .trustbar .ti circle, .trustbar .ti rect { fill: var(--blue); }
.trustbar .ti.red path { fill: var(--red); }

/* ---------- Hero ----------
   Default hero has real bottom padding. The homepage overrides it to 0 because
   its trust bar is pulled up over the seam; every other page has nothing there,
   so without this the CTA buttons sit flush against the next section. */
.hero { background: linear-gradient(180deg, var(--navy-2) 0%, var(--navy) 100%); color: #fff; padding: 56px 0 62px; }
.hero.has-trustbar { padding-bottom: 0; }

/* ---------- Full-bleed hero ----------
   A wide photo shrunk into a side box has no presence, so the homepage runs the
   image edge to edge with the copy over it. Every hero in this set was generated
   with its subject deliberately in the RIGHT THIRD and its left half calm, so the
   gradient is weighted left: the headline gets its contrast without ever covering
   the electrician, the truck or the equipment, which are the point of the photo.
   It reaches full transparency by the right edge rather than stopping short, so
   the subject is seen at full strength instead of through a permanent veil. */
.hero.bleed { position: relative; padding: 0; overflow: hidden; min-height: 560px; display: flex; align-items: center; }
.hero.bleed > .bg { position: absolute; inset: 0; z-index: 0; }
.hero.bleed > .bg img { width: 100%; height: 100%; object-fit: cover; object-position: 72% 50%; }
.hero.bleed > .bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg,
    rgba(var(--scrim-rgb), calc(var(--scrim) * 1))    0%,
    rgba(var(--scrim-rgb), calc(var(--scrim) * .92)) 30%,
    rgba(var(--scrim-rgb), calc(var(--scrim) * .58)) 55%,
    rgba(var(--scrim-rgb), calc(var(--scrim) * .22)) 78%,
    rgba(var(--scrim-rgb), 0)                       100%);
}
/* Per-hero strength. Set on the .hero.bleed element, one class, nothing else
   changes. Measured brightest cell in each headline zone is in the comment.
   Anything not listed rides the --scrim default, which is heroes 3, 4 and 5:
   service entrance (101), parking lot (122) and landscape (124) are already
   dark enough for white text and want almost nothing laid over them. */
.hero.bleed.scrim-mid    { --scrim: .34; } /* hero 1, signs / bucket truck: 141 */
.hero.bleed.scrim-strong { --scrim: .50; } /* hero 2, residential fixture: 182, the only genuinely bright one */
.hero.bleed > .wrap { position: relative; z-index: 1; padding: 72px 0 118px; }
.hero.bleed .hero-copy { max-width: 620px; }
.hero.bleed h1 { text-shadow: 0 2px 18px rgba(0,0,0,.35); }
/* Per-template focal points. Each photo puts its subject somewhere different, so
   the crop is set per template rather than left to object-fit's centre guess.
   Only the homepage carries a trust bar, so only it needs the deep bottom
   padding that the bar sits over. */
.hero.bleed.bleed-service > .bg img { object-position: 68% 50%; }
.hero.bleed.bleed-area > .bg img { object-position: 62% 44%; }
.hero.bleed.bleed-service > .wrap,
.hero.bleed.bleed-area > .wrap { padding-bottom: 76px; }
.hero.bleed.bleed-service, .hero.bleed.bleed-area { min-height: 470px; }

@media (max-width: 900px) {
  .hero.bleed { min-height: 0; }
  .hero.bleed > .wrap { padding: 54px 0 104px; }
  .hero.bleed.bleed-service > .wrap,
  .hero.bleed.bleed-area > .wrap { padding-bottom: 60px; }
  .hero.bleed.bleed-service, .hero.bleed.bleed-area { min-height: 0; }
  .hero.bleed > .bg img { object-position: 62% 45%; }
  /* Mobile turns the gradient vertical, because the copy sits over the whole
     frame rather than beside the subject, so there is no calm left half to hide
     in. It runs harder than desktop for that reason: the multipliers push past
     1x the dial deliberately, and the top stop is clamped so the strong hero
     cannot exceed a full-opacity panel. */
  .hero.bleed > .bg::after {
    background: linear-gradient(180deg,
      rgba(var(--scrim-rgb), min(1, calc(var(--scrim) * 1.9)))  0%,
      rgba(var(--scrim-rgb), calc(var(--scrim) * 1.75))        55%,
      rgba(var(--scrim-rgb), calc(var(--scrim) * 1.55))       100%);
  }
}
.hero h1 { color: #fff; }
.hero .accent { color: var(--red); }
.hero p { color: #D8D8D8; }
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 44px; align-items: center; }
@media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; gap: 28px; } }
.hero-ctas { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 22px; }
.hero-points { list-style: none; padding: 0; margin: 20px 0 0; display: flex; gap: 10px 22px; flex-wrap: wrap; color: #D8D8D8; font-weight: 600; }
.hero-points li::before { content: "✔"; color: #6FD08C; font-weight: 800; margin-right: 8px; }
.hero-art img { border-radius: var(--radius); box-shadow: var(--shadow-lg); }

/* Trust bar is its own element now, pulled up over the bottom of the bleed hero
   rather than living inside it. Negative margin instead of transform, so it
   actually occupies layout space and nothing underneath slides beneath it. */
.trustwrap { position: relative; z-index: 2; margin-top: -74px; }
.trustbar { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-lg); }
.trustbar-inner { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; padding: 18px 10px; text-align: center; }
@media (max-width: 800px) { .trustbar-inner { grid-template-columns: repeat(2, 1fr); gap: 16px 6px; } }
.trustbar .t { font-weight: 800; color: var(--ink); font-size: 0.98rem; }
.trustbar .s { font-size: 0.82rem; color: var(--muted); }
.after-hero { padding-top: 54px; }

/* ---------- Service cards ---------- */
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
/* Three columns is right for 3 and 6 cards. With 4 it leaves a single orphan on
   a second row, and with 2 it leaves a hole. Count-specific modifiers rather
   than letting the default strand a card. */
.cards.two, .cards.four { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 900px) { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .cards, .cards.two, .cards.four { grid-template-columns: 1fr; } }
.card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 26px 24px; transition: transform .15s ease, box-shadow .15s ease;
  display: flex; flex-direction: column;
}
.card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.card img.icon { width: 62px; height: 62px; object-fit: contain; margin-bottom: 14px; }
.card h3 { margin-bottom: 8px; }
.card p { font-size: 0.96rem; flex: 1; }
.card .more { font-weight: 800; color: var(--red); font-size: 0.92rem; }

/* ---------- Comfort Club ---------- */
.club { background: var(--wash); }
.club-grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: 40px; align-items: center; }
@media (max-width: 860px) { .club-grid { grid-template-columns: 1fr; } }
.club-list { list-style: none; padding: 0; margin: 0 0 20px; display: grid; grid-template-columns: 1fr 1fr; gap: 8px 20px; }
@media (max-width: 520px) { .club-list { grid-template-columns: 1fr; } }
.club-list li { position: relative; padding-left: 26px; font-weight: 600; color: var(--ink); }
.club-list li::before { content: "✔"; position: absolute; left: 0; color: var(--blue); font-weight: 800; }
.price { font-size: 2.6rem; font-weight: 800; color: var(--red); line-height: 1; }
.price small { display: block; font-size: 0.9rem; color: var(--muted); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; margin-top: 6px; }
/* Affordable Air used a 3px DASHED border here and it made sense there: the
   card held a price, --blue was a real blue, and dashed read as a tear-out
   coupon. Both halves of that broke on this build. --blue is now near-black,
   so it rendered as a heavy dashed box that reads as a placeholder, and the
   card here holds the bucket truck, which is a credibility claim rather than
   an offer. Solid, with a green top rule to mark it as the highlighted one.
   Inherited styling can survive a repalette and still lose its meaning. */
.club-card { background: #fff; border: 1px solid var(--line); border-top: 4px solid var(--red); border-radius: var(--radius); padding: 30px; text-align: center; box-shadow: var(--shadow); }

/* ---------- Areas ---------- */
.areas { background: var(--navy); color: #fff; }
.areas h2 { color: #fff; }
.areas p { color: #D2D2D2; }
.chips { display: flex; flex-wrap: wrap; gap: 10px; margin: 22px 0 6px; }
.chips a { background: rgba(255,255,255,.09); border: 1px solid rgba(255,255,255,.22); color: #fff; padding: 9px 16px; border-radius: 999px; font-weight: 700; font-size: 0.92rem; }
.chips a:hover { background: var(--red); border-color: var(--red); text-decoration: none; }

/* ---------- Problems list ---------- */
.problems { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
@media (max-width: 800px) { .problems { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .problems { grid-template-columns: 1fr; } }
.problem { background: #fff; border: 1px solid var(--line); border-left: 4px solid var(--red); border-radius: 8px; padding: 14px 18px; font-weight: 700; color: var(--ink); display: flex; align-items: center; gap: 13px; }
.problem img { width: 40px; height: 40px; object-fit: contain; flex: none; }

/* ---------- Lead form ---------- */
.leadband { background: linear-gradient(135deg, var(--blue-deep) 0%, var(--navy) 100%); color: #fff; }
.leadband h2 { color: #fff; }
.leadband p { color: #D8D8D8; }
/* The form card is a WHITE panel inside the dark lead band, so it must win
   the colour cascade back. `.leadband p` is class+element and out-specifies
   `.form-legal`, which rendered the privacy line in near-white ON white and
   made it effectively invisible. Found on the first real render, Aug 17. */
.leadband .form-card p, .leadband .form-card .note, .leadband .form-card .form-legal { color: var(--muted); }
.leadband .form-card label { color: var(--ink); }
.lead-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; }
@media (max-width: 860px) { .lead-grid { grid-template-columns: 1fr; gap: 26px; } }
.form-card { background: #fff; border-radius: var(--radius); padding: 28px; box-shadow: var(--shadow-lg); }
.form-card h3 { margin-bottom: 4px; }
.form-card .note { font-size: 0.88rem; color: var(--muted); margin-bottom: 18px; }
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 0.84rem; font-weight: 700; color: var(--ink); margin-bottom: 5px; }
.field input, .field select, .field textarea {
  width: 100%; padding: 13px 14px; border: 1px solid var(--line); border-radius: 9px;
  font: inherit; font-size: 1rem; color: var(--ink); background: #fff;
}
.field input:focus, .field select:focus, .field textarea:focus { outline: 3px solid rgba(28,119,189,.28); border-color: var(--blue); }
.field textarea { min-height: 96px; resize: vertical; }
/* Honeypot: off-screen rather than display:none, because some bots skip hidden
   fields but will happily fill anything present in the DOM. */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-msg { margin-top: 12px; font-weight: 700; font-size: 0.95rem; }
.form-msg.err { color: var(--red-deep); }
.form-msg.ok { color: #1B7F4B; }
.form-legal { font-size: 0.8rem; color: var(--muted); margin: 12px 0 0; }

/* ---------- Footer ---------- */
footer.site { background: var(--navy); color: #C6C6C6; padding: 54px 0 22px; font-size: 0.95rem; }
footer.site h4 { color: #fff; font-size: 1rem; margin-bottom: 12px; }
footer.site a { color: #C6C6C6; display: block; margin-bottom: 7px; }
footer.site a:hover { color: #fff; }
.foot-grid { display: grid; grid-template-columns: 1.3fr 1fr 1fr 1.1fr; gap: 34px; }
@media (max-width: 900px) { .foot-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .foot-grid { grid-template-columns: 1fr; } }
.foot-logo img { height: 62px; margin-bottom: 14px; }
.licences { border-top: 1px solid rgba(255,255,255,.14); margin-top: 30px; padding-top: 18px; display: flex; gap: 10px 26px; flex-wrap: wrap; font-size: 0.82rem; color: #9C9C9C; }
.foot-bottom { border-top: 1px solid rgba(255,255,255,.14); margin-top: 16px; padding-top: 16px; font-size: 0.82rem; color: #9C9C9C; display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap; }

/* ---------- Fixed mobile call bar ----------
   HVAC money is the phone call, so on a phone the call and quote actions never
   leave the screen. Two cells only, so the labels cannot clip the way Carl's
   four-cell bar did at 390px. */
.callbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 60; display: grid; grid-template-columns: 1fr 1fr; background: var(--navy); border-top: 3px solid var(--red); }
.callbar a { color: #fff; font-weight: 800; text-align: center; padding: 16px 8px; font-size: 0.98rem; }
.callbar a:hover { text-decoration: none; }
.callbar a:first-child { background: var(--red); }
@media (min-width: 861px) { .callbar { display: none; } }

.skip { position: absolute; left: -9999px; }
.skip:focus { left: 12px; top: 12px; background: #fff; padding: 10px 16px; z-index: 99; border-radius: 8px; }

/* ---- Added Aug 16, 2026, against Mike's pre-launch audit ---- */

/* Trust block moved above the fold. His note: BBB and licences were buried
   in the footer, where they do nothing for a first-time visitor deciding
   whether to call a stranger about their broken furnace. */
.credbar {
  list-style: none; margin: 12px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 22px;
}
.credbar li {
  font-size: 0.9rem; font-weight: 700; color: var(--blue-deep);
  display: flex; align-items: center; gap: 7px;
}
.credbar li::before {
  content: ""; flex: 0 0 16px; height: 16px; border-radius: 50%;
  background: var(--blue);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z'/></svg>") center/13px no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z'/></svg>") center/13px no-repeat;
}

/* Manufacturer authority. The logos were already there but naked; the point
   is the messaging, because a homeowner does not know that Comfort Specialist
   outranks Authorized Dealer unless somebody tells them. */
.authority { padding-top: 8px; }
/* The shared rule is `.badgerow .wrap`, which lays out an inner wrap. In the
   authority section the badgerow sits INSIDE the wrap instead, so it has no
   inner .wrap and that rule never matched: the logos fell back to inline flow
   and bunched together in the middle. Scoped only to .authority, so the plain
   badgerow strip used on the other 68 pages is untouched.

   Laid out on the SAME 4-column grid as .authority-grid below it, so each
   badge sits directly above the paragraph that explains it. Sized by width
   rather than height because their aspect ratios run from 3.16:1 (Mitsubishi)
   to 1.50:1 (BBB), and one shared height shrinks BBB to a stamp. */
.authority .badgerow {
  margin: 0 0 22px;
  background: transparent;
  border-bottom: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px;
  align-items: center;
  justify-items: center;
  padding: 4px 0 0;
}
.authority .badgerow img { height: auto; max-width: 100%; }
/* The four HVAC-specific badge widths that sat here, Trane, Mitsubishi, Day &
   Night and BBB, were Affordable Air's and are gone, along with a stray closing
   brace they were carrying. Bright Solutions has no manufacturer badges; their
   credentials are licence 48857 and 4.8 stars over 37 reviews. Anything added
   here later needs its own explicit width, not an inherited HVAC one. */
@media (max-width: 900px) {
  .authority .badgerow { grid-template-columns: repeat(2, 1fr); gap: 22px; }
}
@media (max-width: 700px) {
  .authority .badgerow { justify-content: center; gap: 18px 30px; }
}
.authority-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px;
}
.authority-grid h3 { font-size: 1.02rem; margin-bottom: 6px; color: var(--blue-deep); }
.authority-grid p { font-size: 0.94rem; color: #4A4A4A; }
@media (max-width: 900px) { .authority-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .authority-grid { grid-template-columns: 1fr; } }

/* Financing promoted from a single trust tile to a real section. */
.financing { background: var(--blue-deep); color: #fff; }
.financing h2 { color: #fff; }
.fin-grid { max-width: 780px; }
.fin-list { list-style: none; padding: 0; margin: 20px 0 24px; display: grid; gap: 10px; }
.fin-list li { position: relative; padding-left: 30px; color: #EDEDED; font-weight: 600; }
.fin-list li::before {
  content: ""; position: absolute; left: 0; top: 4px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--red);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z'/></svg>") center/14px no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z'/></svg>") center/14px no-repeat;
}
.fin-legal { margin-top: 16px; font-size: 0.84rem; color: #B4B4B4; max-width: 62ch; }

/* FAQ. Native <details> on purpose: it is accessible, keyboard operable and
   works with JavaScript switched off, and Google reads the answer text in the
   DOM whether or not it is expanded. */
.faq { background: #F5F7F9; }
.faq-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 26px; }
.faq details {
  background: #fff; border: 1px solid #E2E6EA; border-radius: 10px;
  padding: 0 18px; transition: border-color .15s;
}
.faq details[open] { border-color: var(--blue); }
.faq summary {
  cursor: pointer; list-style: none; padding: 15px 0;
  font-weight: 700; color: var(--blue-deep); font-size: 1rem;
  display: flex; justify-content: space-between; align-items: center; gap: 14px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+"; flex: 0 0 auto; font-size: 1.5rem; font-weight: 400;
  color: var(--red); line-height: 1;
}
.faq details[open] summary::after { content: "\2013"; }
.faq details p { padding: 0 0 16px; color: #4A4A4A; font-size: 0.96rem; }
@media (max-width: 820px) { .faq-grid { grid-template-columns: 1fr; } }


/* ---------- Real job photos ----------
   The recovered gallery photos top out at 720px on the long edge because Wix
   downscaled them on upload, so they are shown at card size and never as a
   banner. A fixed crop height keeps a 376 square and a 720x960 portrait sitting
   in one tidy row instead of stair-stepping. */
.proof { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 310px)); gap: 24px; justify-content: center; }
.proof-item { margin: 0; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); }
.proof-item img { width: 100%; height: 230px; object-fit: cover; display: block; }
.proof-item figcaption { padding: 14px 16px; font-size: 0.9rem; color: var(--body); line-height: 1.45; }
@media (max-width: 560px) { .proof { grid-template-columns: 1fr; } }

/* ---------- Phone heroes: STACK, do not overlay ----------
   Cody looked at this on a real phone (Aug 17, 2026) and reported the pictures
   cut off and the text shifted around. Both come from one cause.

   The heroes are 3:1 banners. Overlaid, the image is `object-fit: cover` inside
   a box whose height is set by the COPY, which on a phone is tall and narrow.
   So a 1800x600 photo gets cropped to a thin vertical sliver, and then needs a
   near-opaque scrim on top of that sliver before white text will read over it.
   The photograph is destroyed twice and the copy floats over the wreckage.

   Below 700px the hero stacks instead: the whole photograph at its real 3:1
   aspect ratio, then the copy on a solid charcoal panel underneath. The picture
   survives intact, the text sits on a predictable background, and the scrim is
   switched off entirely because it has nothing left to do. */
@media (max-width: 700px) {
  .hero.bleed { display: block; min-height: 0; padding: 0; background: var(--navy); }
  .hero.bleed > .bg { position: static; }
  .hero.bleed > .bg img { width: 100%; height: auto; aspect-ratio: 3 / 1; object-fit: cover; }
  .hero.bleed > .bg::after { display: none; }
  .hero.bleed > .wrap,
  .hero.bleed.bleed-service > .wrap,
  .hero.bleed.bleed-area > .wrap { padding: 24px 0 28px; }
  .hero.bleed.bleed-service, .hero.bleed.bleed-area { min-height: 0; }
  .hero.bleed .hero-copy { max-width: none; }
  .hero.bleed h1 { text-shadow: none; }
  /* Ragged wrapped rows were most of the "aligned weird". One per line. */
  .hero-points { flex-direction: column; gap: 9px; }
  .hero-ctas { display: grid; grid-template-columns: 1fr; gap: 10px; }
  .hero-ctas .btn { width: 100%; }
  /* .trustwrap pulls itself up 74px to overlap the hero, which works when the
     hero has 118px of bottom padding under the buttons. Stacked, the hero only
     has 28px, so the pull swallowed the second call to action. No overlap on
     phones: it sits under the hero like a normal block. */
  .trustwrap { margin-top: 18px; }
  .hero.has-trustbar { padding-bottom: 0; }
}
