/*
 * IXL Home Inspections -- design system.
 *
 * Tokens are lifted verbatim from the Webflow build's :root block so the rebuilt site
 * is the same brand, not a reinterpretation. Everything below that is hand-written:
 * the Webflow stylesheet was 95KB of generated utility classes for two sites, and this
 * replaces it at roughly a twentieth the size with no JS dependency.
 */

:root {
  --brand: #053f5c;
  --brand-deep: #04324a;
  --brand-tint: #f0f4f8;
  --accent: #f47f00;
  --accent-light: #ffb701;
  --accent-dark: #f56419;
  --ink: #151c34;
  --slate: #7e828f;
  --light-grey: #e5e5e5;
  --gainsboro: #d2dbdd;
  --white: #fff;

  /* Reading measure. Set in rem, not ch: ch resolves against each element's own
     font-size, so paragraphs and figures using the same token were coming out 554px and
     729px -- mismatched right-hand edges down every prose page. 34.5rem is the width the
     body copy already had. */
  --measure: 34.5rem;
  --shell: 1160px;
  --radius: 6px;
  --shadow: 0 2px 4px #053f5c1a, 0 12px 32px #053f5c14;

  --font-display: Montserrat, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-body: Inter, "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* Body copy on the Webflow build was a soft blue-grey rather than the near-black used
     for headings. It is what keeps the long checklist columns from reading as a wall of
     text, so it comes across with the rest of the type. */
  --prose: #546285;

  /* The two easings every Webflow interaction on the old site used. Named here because
     the reveals, the hover states and the parallax all have to agree -- mixing eases is
     what makes ported motion feel subtly wrong even when the durations match.
     outQuart drives entrances; outExpo drives the arrow-circle hover. */
  --ease-out-quart: cubic-bezier(.165, .84, .44, 1);
  --ease-out-expo: cubic-bezier(.19, 1, .22, 1);

  --nav-height: 108px;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  /* -.03em and line-height 1 on the display sizes are lifted from the Webflow build.
     The tighter tracking is most of why the old headlines read as one solid mass of
     type rather than as separate words. */
  line-height: 1.05;
  letter-spacing: -0.03em;
  color: var(--brand);
  margin: 0 0 .5em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.5rem, 1.5rem + 3.8vw, 3.75rem); }
h2 { font-size: clamp(2rem, 1.35rem + 2.6vw, 3rem); }
h3 { font-size: clamp(1.375rem, 1.15rem + .95vw, 1.75rem); }
h4 { font-size: 1.0625rem; letter-spacing: -0.015em; }

p { margin: 0 0 1.15em; max-width: var(--measure); text-wrap: pretty; color: var(--prose); font-size: 1.125rem; line-height: 1.5; letter-spacing: -.02em; }
p:last-child { margin-bottom: 0; }

a { color: var(--brand); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-dark); }

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

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

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--brand); color: var(--white); padding: .75rem 1.25rem;
}
.skip-link:focus { left: 0; }

/* ---------- layout ---------- */

.shell { width: min(100% - 2.5rem, var(--shell)); margin-inline: auto; }
.section { padding-block: clamp(3rem, 1.6rem + 5.5vw, 5.5rem); }
/* Several pages use <section class="shell"> for their prose flow -- the width constraint
   without .section's padding, so the content butted straight against the hero above and
   the band below with no rhythm at all. Give it the same vertical measure. */
section.shell { padding-block: clamp(3rem, 1.6rem + 5.5vw, 5.5rem); }
/* An image in a prose flow aligns to the text measure. Left full-width it ran 1160px
   against a 68ch paragraph column, and the mismatched left/right edges are most of why
   those pages read as off. */
section.shell > .media, .prose-block > .media { max-width: var(--measure); }
.section--tint { background: var(--brand-tint); }
.section--brand { background: var(--brand); color: var(--white); }
.section--brand h2, .section--brand h3 { color: var(--white); }

.eyebrow {
  font-family: var(--font-display);
  font-size: .75rem; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--accent-dark);
  margin: 0 0 .75rem;
}
.section--brand .eyebrow { color: var(--accent-light); }

.lede { font-size: 1.1875rem; color: #3a4358; }
.section--brand .lede { color: #dbe6ee; }

.grid { display: grid; gap: 1.75rem; }
@media (min-width: 720px) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 980px) { .grid--4 { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 720px) and (max-width: 979px) { .grid--4 { grid-template-columns: repeat(2, 1fr); } }

.split { display: grid; gap: 2.5rem; align-items: start; }
/* Whichever column is shorter, center it against the taller one: the leftover space
   becomes a margin above and below rather than a hole under the short column. Which side
   is shorter varies by section, so this cannot be pinned to :first-child. */
@media (min-width: 900px) { .split { align-items: center; } }
@media (min-width: 900px) { .split { grid-template-columns: 1.1fr .9fr; gap: 4rem; } }

/* ---------- buttons ---------- */

/* Sizing is the Webflow build's: 18px type, 60px minimum height, 20px/35px padding and a
   3px radius -- a noticeably larger, squarer button than the compact rounded one this
   rebuild had. It is one of the strongest signals of the old design. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font-family: var(--font-display); font-weight: 700; font-size: 1.125rem;
  letter-spacing: 0; text-decoration: none; text-align: center;
  min-height: 60px; padding: 1.15rem 2.2rem; border-radius: 3px;
  border: 2px solid transparent;
  transition: background-color .25s ease, color .25s ease, border-color .25s ease;
  cursor: pointer;
}
/* On the old site the DEFAULT button was brand teal and turned orange on hover; orange
   was the exception, used for the CTA sitting on a photographic band. Both sites follow
   that. The header call button is the one deliberate exception -- see .site-header__call,
   which uses .btn--accent so it does not vanish against a teal hero. */
.btn--primary { background: var(--brand); color: var(--white); }
.btn--primary:hover { background: var(--accent); color: var(--white); }
.btn--accent { background: var(--accent); color: var(--white); }
.btn--accent:hover { background: var(--light-grey); color: var(--accent-dark); }
.btn--ghost { border-color: currentColor; color: var(--brand); background: transparent; }
.btn--ghost:hover { background: var(--brand); color: var(--white); border-color: var(--brand); }
.section--brand .btn--ghost, .site-hero .btn--ghost { color: var(--white); }
.section--brand .btn--ghost:hover, .site-hero .btn--ghost:hover { background: var(--white); color: var(--brand); border-color: var(--white); }
.btn-row { display: flex; flex-wrap: wrap; gap: .875rem; margin-top: 1.75rem; }

/* ---------- header ---------- */

/* Transparent bar floating over the hero photograph, exactly as the Webflow build had it.
   The old site also changed the bar's background and height on scroll (a PAGE_SCROLL
   interaction firing over the first ~18% of the page); that is reproduced here by a
   data-scrolled attribute set from shared/motion.js, so the links stay legible once the
   photo has scrolled away underneath them. */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 99;
  background: transparent;
  transition: background-color .3s ease, box-shadow .3s ease;
}
.site-header[data-scrolled="true"] {
  background: var(--brand);
  box-shadow: 0 2px 18px #04324a40;
}
.site-header__inner {
  display: flex; align-items: center; gap: 1.75rem;
  min-height: var(--nav-height);
  transition: min-height .3s ease;
}
.site-header[data-scrolled="true"] .site-header__inner { min-height: 84px; }
/* The padding is what guarantees clearance: the bar's height is set by whichever child is
   tallest, so without it the lockup can sit flush against the top and bottom edges. */
.site-header__logo { display: flex; align-items: center; padding-block: .625rem; }
/* Sized by width, not height: the file is a horizontal lockup whose lower third is the
   pale "HOME INSPECTIONS" wordmark. Constraining the height cropped that wordmark against
   the header edge. 168px is close to the width the old nav gave it.

   It scales down in step with the bar when the page scrolls, on the same duration and
   easing, so the two read as one movement rather than the bar closing in on a logo that
   stayed put. */
.site-header__logo img {
  width: 168px; height: auto;
  transition: width .3s ease;
}
.site-header[data-scrolled="true"] .site-header__logo img { width: 124px; }
@media (prefers-reduced-motion: reduce) {
  .site-header__logo img, .site-header__inner, .site-header { transition: none; }
}

.site-nav ul { display: flex; gap: .5rem; list-style: none; margin: 0; padding: 0; }
.site-nav a {
  font-family: var(--font-display); font-weight: 600; font-size: 1rem;
  color: var(--white); opacity: .8; text-decoration: none;
  padding: .5rem 1.2rem;
  border-bottom: 2px solid transparent;
  /* The slow border and quick opacity are the old site's own transition pair. */
  transition: border-color 1s ease, opacity .2s ease, color .2s ease;
}
.site-nav a:hover, .site-nav a[aria-current="page"] {
  opacity: 1; border-bottom-color: var(--accent); color: var(--white);
}

.site-nav { margin-left: auto; }

/* The header row is tight between the mobile breakpoint (899px) and a comfortable
   desktop: a logo, five or six nav items and a CTA. Below about 1150px the CTA used to
   wrap its own label onto a second line, which pushed the header to 100px tall -- it did
   this on BOTH sites at ~950px long before the commercial nav grew a Service Area entry.
   Tighten the link padding through that band instead, and never let the CTA break. */
.site-header__call { white-space: nowrap; }
@media (min-width: 900px) and (max-width: 1199px) {
  .site-header__inner { gap: 1rem; }
  .site-nav a { padding-inline: .6rem; font-size: .9375rem; }
}
.nav-toggle { display: none; background: none; border: 0; padding: .5rem; color: var(--brand); }

@media (max-width: 899px) {
  /* One row: logo left, then the phone button and the menu toggle. The nav wraps onto
     a second row only when it is open. */
  .site-header__inner { flex-wrap: wrap; gap: .625rem; min-height: 76px; }
  .site-header[data-scrolled="true"] .site-header__inner { min-height: 76px; }
  .site-header__logo { margin-right: auto; }
  .site-header__logo { padding-block: .5rem; }
  .site-header__logo img, .site-header[data-scrolled="true"] .site-header__logo img { width: 118px; }
  .site-header__call { order: 2; min-height: 0; padding: .6rem .85rem; font-size: .8125rem; }
  .site-header__call-word { display: none; }
  .nav-toggle { display: block; order: 3; color: var(--white); }
  .site-nav { order: 4; flex-basis: 100%; margin-left: 0; display: none; }
  /* Once open, the panel needs its own ground: the links sit over whatever photograph
     happens to be behind the transparent bar, and white-on-sky is unreadable. */
  .site-nav[data-open="true"] { display: block; background: var(--brand); margin: 0 -1.25rem; padding: 0 1.25rem; }
  .site-nav ul { flex-direction: column; gap: 0; padding-bottom: 1rem; }
  .site-nav a { display: block; padding: .75rem 0; border-bottom: 1px solid #ffffff2e; }
}

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

.site-hero {
  background: linear-gradient(160deg, var(--brand) 0%, var(--brand-deep) 62%, #02222f 100%);
  color: var(--white);
  /* The header floats over the hero, so the hero owns the space the header sits in. */
  padding-block: calc(var(--nav-height) + 2rem) clamp(3.5rem, 2rem + 6vw, 6.5rem);
}
.site-hero h1 { color: var(--white); max-width: 16ch; }
/* The Webflow headline broke onto a second line and turned that line orange. The color
   carries the emphasis, so the markup is <em> -- the meaning survives with styles off. */
.site-hero h1 em { color: var(--accent); font-style: normal; display: block; }
.site-hero p { color: #e8eef2; font-size: 1.125rem; max-width: 46ch; }
.site-hero .eyebrow { color: var(--accent-light); }
.site-hero--compact { padding-block: calc(var(--nav-height) + 1rem) clamp(2.75rem, 2rem + 3vw, 4rem); }
.site-hero--compact h1 { max-width: 22ch; }

/* The full-height photographic hero from the old homepage. Capped rather than a bare
   100vh: on a short laptop window 100vh is fine, but on a tall portrait monitor it
   leaves the headline stranded in the middle of an enormous photograph. */
.site-hero--tall {
  min-height: min(100vh, 860px);
  display: flex; align-items: center;
}
.site-hero--tall .shell { width: min(100% - 2.5rem, var(--shell)); }

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

.card {
  --card-pad: 1.75rem;
  background: var(--white); border: 1px solid var(--light-grey);
  border-radius: var(--radius); padding: var(--card-pad); box-shadow: var(--shadow);
}
.card h3 { margin-bottom: .5rem; }
/* Cards in a grid stretch to the tallest, so a card with shorter copy used to leave its
   "read more" link floating mid-height while its neighbour's sat at the bottom. Making the
   card a flex column and pushing its last child down aligns the links along one line.
   Scoped with :has() to cards that actually END in a link -- several cards elsewhere close
   on a paragraph, and those must keep sitting directly under the copy. Browsers without
   :has() simply render what they did before, so this degrades to the old behavior. */
.card:has(.card__link) { display: flex; flex-direction: column; }
.card:has(.card__link) > :last-child { margin-top: auto; padding-top: .35rem; }

.card p { font-size: 1rem; color: #3a4358; }
.card__link { font-family: var(--font-display); font-weight: 700; font-size: .9375rem; color: var(--accent-dark); text-decoration: none; }
.card__link:hover { text-decoration: underline; }

.checklist { list-style: none; margin: 0; padding: 0; }
.checklist li { position: relative; padding-left: 1.75rem; margin-bottom: .6rem; }
.checklist li::before {
  content: ""; position: absolute; left: 0; top: .58em;
  width: .5rem; height: .5rem; border-radius: 50%; background: var(--accent);
}
.section--brand .checklist li::before { background: var(--accent-light); }

/* ---------- prose blocks on interior pages ---------- */

.prose-block { padding-block: clamp(2.5rem, 1.6rem + 3vw, 4rem); border-bottom: 1px solid var(--light-grey); }
.prose-block:last-of-type { border-bottom: 0; }

/* ---------- form ---------- */

.form-grid { display: grid; gap: 1.1rem; }
@media (min-width: 640px) { .form-grid--2 { grid-template-columns: 1fr 1fr; } }
.field label {
  display: block; font-family: var(--font-display); font-weight: 600;
  font-size: .8125rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--brand); margin-bottom: .35rem;
}
.field input, .field select, .field textarea {
  width: 100%; font: inherit; font-size: 1rem; color: var(--ink);
  padding: .75rem .9rem; border: 1px solid var(--gainsboro);
  border-radius: var(--radius); background: var(--white);
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--brand); }
.field textarea { min-height: 8rem; resize: vertical; }
.field-note { font-size: .875rem; color: var(--slate); margin-top: .35rem; }

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

.site-footer { background: var(--brand-deep); color: #c3d4de; padding-block: 3.5rem 2rem; }
.site-footer h4 {
  color: var(--white); font-size: .8125rem; letter-spacing: .14em;
  text-transform: uppercase; margin-bottom: 1rem;
}
.site-footer a { color: #c3d4de; text-decoration: none; }
.site-footer a:hover { color: var(--accent-light); text-decoration: underline; }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-bottom: .55rem; }
.phone-lg {
  font-family: var(--font-display); font-size: 1.375rem; font-weight: 700;
  text-decoration: none;
}
.site-footer .phone-lg { color: var(--white); }
.site-footer__bar {
  margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid #ffffff26;
  display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
  font-size: .875rem;
}

/* ---------- breadcrumbs ---------- */

.breadcrumbs { background: var(--brand-tint); border-bottom: 1px solid var(--light-grey); }
.breadcrumbs ul {
  display: flex; flex-wrap: wrap; gap: .5rem; list-style: none;
  margin: 0; padding: .75rem 0; font-size: .875rem; color: var(--slate);
}
.breadcrumbs a { color: var(--brand); text-decoration: none; }
.breadcrumbs a:hover { text-decoration: underline; }
.breadcrumbs [aria-hidden="true"] { color: var(--gainsboro); }

/* ---------- stat / coverage strip ---------- */

.strip { display: grid; gap: 1.5rem; padding-block: 2rem; }
@media (min-width: 720px) { .strip { grid-template-columns: repeat(3, 1fr); } }
.strip__item strong {
  display: block; font-family: var(--font-display); font-size: 1.5rem;
  color: var(--brand); line-height: 1.2;
}
.strip__item span { font-size: .9375rem; color: var(--slate); }

/* ---------- county list ---------- */

.county-grid { display: grid; gap: 1.25rem; }
@media (min-width: 640px) { .county-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .county-grid { grid-template-columns: repeat(3, 1fr); } }
.county-card { border: 1px solid var(--light-grey); border-radius: var(--radius); padding: 1.25rem 1.4rem; }
.county-card h3 { font-size: 1.125rem; margin-bottom: .35rem; }
.county-card p { font-size: .9375rem; color: var(--slate); margin: 0; }

.site-footer__wordmark {
  font-family: var(--font-display); font-weight: 700; color: var(--white);
  font-size: 1.5rem; letter-spacing: .04em; margin: 0 0 1.25rem;
}
.site-footer__wordmark span {
  display: block; font-size: .8125rem; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--accent-light);
}

/* ---------- footer socials ---------- */

.site-footer__social { display: flex; gap: .75rem; margin-top: 1.25rem; }
.site-footer__social li { margin: 0; }
.site-footer__social a {
  display: grid; place-items: center; width: 40px; height: 40px;
  border: 1px solid #ffffff33; border-radius: var(--radius); color: #c3d4de;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}
.site-footer__social a:hover { background: var(--accent); border-color: var(--accent); color: var(--white); }

/* Honeypot: off-screen rather than display:none, which some bots skip over. */
.hp { position: absolute; left: -5000px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- photography ----------
   Slots are declared in the pages and filled from src/assets/images/. Every <img>
   carries width and height, and every frame sets an aspect-ratio, so the box is the
   same size before and after the file arrives -- swapping a placeholder for a real
   photo must never move the copy underneath it. */

.media { margin: 0 0 1.5rem; }
.media > img {
  width: 100%; border-radius: var(--radius);
  object-fit: cover; background: var(--brand-tint);
}
.media figcaption {
  font-size: .9375rem; color: var(--slate); margin-top: .6rem;
  max-width: 56ch; line-height: 1.5;
}
.media--wide > img { aspect-ratio: 16 / 9; }
.media--square > img { aspect-ratio: 1 / 1; }
/* A portrait at full column width would stand ~1.25x as tall as it is wide -- on a
   1160px shell that is a wall of photograph. Cap it at a human size. */
.media--portrait { max-width: 420px; }

/* Keeps the uploaded file's own aspect ratio instead of imposing one -- for slots where
   the incoming photo could be portrait or landscape and cropping it blind would be worse
   than letting the frame follow the picture. */
.media--natural > img { height: auto; aspect-ratio: auto; max-width: 620px; }
.media--portrait > img { aspect-ratio: 4 / 5; }
.media--band > img { aspect-ratio: 21 / 9; }
.media--shadow > img { box-shadow: var(--shadow); }

/* The split layout puts copy beside a photo; the image is sticky-free and simply
   sits at the top of its column so short copy does not stretch it. */
.split .media { margin-bottom: 0; }

/* Card photography: full-bleed to the card edge, so the padding that holds the copy
   does not also inset the image. .card sets its own padding, hence the negative pull. */
.card__media {
  display: block; border-radius: var(--radius) var(--radius) 0 0; overflow: hidden;
  /* Cancel the card's own padding exactly -- both read the same custom property, so the
     image stays flush to the border if that padding is ever changed. */
  margin: calc(var(--card-pad) * -1) calc(var(--card-pad) * -1) 1.25rem;
}
.card__media img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; background: var(--brand-tint); }

/* ---------- hero with a photograph behind it ----------
   The gradient is kept and composited over the image rather than replaced: it is what
   guarantees the headline stays legible whatever photo ends up back there. */

/* The photograph and its scrim are background LAYERS set inline by heroBackdrop() in
   shared/media.js -- gradients over photo, one element, no stacking to get wrong. All
   this rule has to do is stop .site-hero's own gradient from overriding the inline one
   and give the type a ground if the photo never loads. */
.site-hero--photo {
  position: relative;
  background-color: var(--brand-deep);
  background-image: none;   /* the inline style supplies the real stack */
}

/* A full-width photographic band between sections. */
.photo-band { position: relative; overflow: hidden; }
.photo-band img { width: 100%; aspect-ratio: 21 / 9; object-fit: cover; }
@media (max-width: 720px) {
  .photo-band img { aspect-ratio: 16 / 10; }
  .media--band > img { aspect-ratio: 16 / 10; }
}

/* ============================================================================
   Webflow design port
   ----------------------------------------------------------------------------
   Sections and motion carried over from the published Webflow build, rebuilt as
   plain CSS. Values (sizes, offsets, shadows, easings, durations) were read off
   the export's stylesheet and its IX2 interaction data rather than eyeballed --
   see archive/<site>/*.webflow/. No webflow.js: the 300KB runtime existed to do
   what transitions and one IntersectionObserver do below.
   ========================================================================== */

/* ---------- scroll reveals ----------
   The old site revealed most sections on scroll: opacity 0 -> 1 over 1s on outQuart,
   optionally sliding 100px up or in from the left.

   The hidden state is gated behind [data-motion="on"], which shared/motion.js sets on
   <html> before first paint. Without JS -- or with it broken -- the attribute is never
   set, no element is ever hidden, and the page reads normally. Hiding content by
   default and relying on script to reveal it is how ported animation loses people. */
[data-motion="on"] [data-reveal] { opacity: 0; will-change: opacity, transform; }
[data-motion="on"] [data-reveal="up"] { transform: translateY(100px); }
[data-motion="on"] [data-reveal="left"] { transform: translateX(-100px); }
[data-motion="on"] [data-reveal].is-revealed {
  opacity: 1; transform: none;
  transition: opacity 1s var(--ease-out-quart), transform 1s var(--ease-out-quart);
}
/* Staggered children, as the old page-load interaction did with its 300/600ms delays. */
[data-motion="on"] [data-reveal-delay="1"].is-revealed { transition-delay: .15s; }
[data-motion="on"] [data-reveal-delay="2"].is-revealed { transition-delay: .3s; }

@media (prefers-reduced-motion: reduce) {
  [data-motion="on"] [data-reveal] { opacity: 1; transform: none; }
  [data-parallax] { transform: none !important; }
}

/* ---------- overlapping image collage ----------
   Three photographs stacked out of alignment. The geometry is measured off the old
   build's rendered layout rather than re-invented -- inside a 660x620 block it placed a
   358x400 square at the top left, a 332x400 square at 50%/35%, and a 320px circle at
   6.5%/63% straddling the bottom of the first. Expressed here as percentages of the
   container so the group scales as one composition.

   Absolute positioning rather than the original's flex-and-negative-margins: the two
   squares have to overlap by a fixed FRACTION at every width, and margins that overlap
   at 1440px pull apart at 900px. */
.collage {
  position: relative;
  width: 100%; max-width: 660px;
  aspect-ratio: 660 / 620;
  margin-inline: auto;
}
.collage__tile, .collage__circle { position: absolute; overflow: hidden; }
.collage__tile img, .collage__circle img { width: 100%; height: 100%; object-fit: cover; display: block; }
.collage__tile { border-radius: 6px; }
.collage__back {
  left: 0; top: 0; width: 54.2%; aspect-ratio: 358 / 400;
  box-shadow: 0 2px 5px 1px #0003;
}
.collage__front {
  left: 49.7%; top: 35.5%; width: 50.3%; aspect-ratio: 332 / 400;
  box-shadow: 0 2px 5px 3px #0003;
}
.collage__circle {
  left: 6.5%; top: 63.4%; width: 48.5%; aspect-ratio: 1;
  border-radius: 50%; z-index: 1;
  box-shadow: 0 2px 5px 5px #0003;
}
/* Under ~700px the three-up stack collides with itself; the circle is the one that can
   go without breaking the composition. */
@media (max-width: 700px) {
  .collage { aspect-ratio: 660 / 520; }
  .collage__circle { display: none; }
  .collage__front { top: 26%; }
}

/* The collage is the wider element in its row but the text beside it carries a long
   heading, so this pairing gives the copy the larger share. */
@media (min-width: 900px) {
  .split--collage { grid-template-columns: .92fr 1.08fr; }
}

/* ---------- photographic band with an icon list ----------
   A full-bleed photo under a flat brand wash (#053f5c99 on the homepage), an orange
   heading, and a column of orange discs with uppercase labels beside it. */
.feature-band {
  background-color: var(--brand-deep);
  background-size: cover; background-position: 50%;
  padding-block: clamp(3.5rem, 2rem + 6vw, 6.25rem);
  color: var(--white);
}
.feature-band h2 { color: var(--accent); }
.feature-band p { color: #eef3f6; }
.feature-band .split { align-items: center; }

.icon-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.5rem; }
.icon-list li { display: flex; align-items: center; gap: 1.25rem; }
.icon-list .icon-list__disc {
  flex: none; display: grid; place-items: center;
  width: 58px; height: 58px; border-radius: 50%;
  background: var(--accent); color: var(--white);
}
.icon-list .icon-list__disc svg { width: 26px; height: 26px; }
.icon-list span {
  font-family: var(--font-display); font-weight: 600; font-size: 1.0625rem;
  letter-spacing: .04em; text-transform: uppercase; color: var(--white);
  line-height: 1.25;
}

/* ---------- residential service rows ("service-sections") ----------
   The home-inspections side of the old build. Same full-bleed two-column idea as the
   commercial `servicesgrid` below, but a deliberately warmer, less corporate voice, and
   the two are NOT interchangeable -- do not merge them:

     commercial  gold letter-spaced eyebrow, small light heading, body at line-height 2.2
     residential no eyebrow, a large 40px orange heading at weight 200, ordinary body

   Archive values: rows are `min-height: 60vh`, panel `padding: 40px 80px` and vertically
   centered; heading `--accent` 40px/200; body `--brand` weight 300, or `--light-grey` on
   the navy row. Benefit rows are 60px tall, ruled in `--accent-dark`, and carry the
   `.arrow-circle` chevron control that was ported with the design but never used until
   now. Hover lifts the rule and the text to `--accent-light`, as the original did.

   Panel markup always comes before the photo so a one-column phone reads heading first;
   the alternation is a desktop-only column swap. Same rule as .split-row -- see there. */
/* Page intro above a run of .service-rows. Takes the rows' orange light heading so the
   two read as one page, and caps its own measure and centers it -- the global `p` rule
   otherwise leaves a ~550px column stranded against the left of a 1160px shell. */
.service-intro { text-align: center; }
.service-intro .shell { max-width: 52rem; }
.service-intro h2 {
  color: var(--accent);
  font-size: clamp(1.85rem, 1.1rem + 2.4vw, 2.5rem);
  font-weight: 200; line-height: 1.15; letter-spacing: -.01em;
}
.service-intro p { color: var(--brand); font-weight: 300; margin-inline: auto; }

.service-rows { display: grid; }
.service-row { display: grid; }
@media (min-width: 900px) {
  .service-row { grid-template-columns: 1fr 1fr; min-height: 60vh; }
  .service-row--reverse .service-row__panel { grid-column: 2; grid-row: 1; }
  .service-row--reverse .service-row__media { grid-column: 1; grid-row: 1; }
}
.service-row--brand { background: var(--brand); }

.service-row__panel {
  margin-block: auto;
  padding: clamp(2.5rem, 1rem + 4vw, 2.5rem) clamp(1.5rem, -1rem + 6vw, 5rem);
}
.service-row__media {
  background-color: var(--brand-deep);
  background-size: cover; background-position: 50%;
  min-height: 52vw;
}
@media (min-width: 900px) { .service-row__media { min-height: 0; } }

.service-row__panel h2 {
  color: var(--accent);
  font-size: clamp(1.85rem, 1.1rem + 2.4vw, 2.5rem);
  font-weight: 200; line-height: 1.1; letter-spacing: -.01em;
  margin: 0 0 1.25rem;
}
/* The ampersand sat smaller than the words either side of it in the original lockup. */
.service-row__panel h2 .amp { font-size: .75em; font-weight: 300; }
.service-row__panel p { color: var(--brand); font-weight: 300; max-width: 46ch; }
.service-row--brand .service-row__panel p { color: var(--light-grey); }
.service-row__lead-in { margin-bottom: .5rem; }

.benefit-list { list-style: none; margin: 1.25rem 0 0; padding: 0; }
.benefit-list li { border-bottom: 1px solid var(--accent-dark); }
.benefit-list a {
  display: flex; align-items: center; justify-content: space-between; gap: 1.25rem;
  min-height: 60px; padding: .5rem 0;
  color: var(--brand); font-weight: 300; line-height: 1.45; text-decoration: none;
  transition: color .3s ease;
}
.service-row--brand .benefit-list a { color: var(--light-grey); }
.benefit-list a:hover,
.service-row--brand .benefit-list a:hover { color: var(--accent-light); }
.benefit-list li:hover { border-bottom-color: var(--accent-light); }
/* The ring is the same control as .arrow-link's, so it inherits that hover transition. */
.benefit-list a:hover .arrow-circle { transform: scale(1.25); }
.benefit-list a:hover .chev-out { transform: translateX(100%); opacity: 0; }
.benefit-list a:hover .chev-in { transform: translateX(0); opacity: 1; }

/* ---------- service-detail split rows ("servicesgrid") ----------
   The alternating full-bleed rows from the Webflow service-detail pages. A two-column
   grid with the gutters zeroed, items flowing in document order, so odd rows read
   panel|photo and even rows read photo|panel without any explicit placement.

   Values are the archive's own: panels are `padding: 40px 120px` with `min-height`
   60vh on the brand panels and 50vh on the white ones; photos carry a flat wash over
   them (#053f5c4d, and #00000080 on the rain shot, which is much brighter than the
   rest). The one non-obvious rule is the 80% height on right-hand photos: it is what
   produces the stagger, letting the page ground show above and below the picture while
   the panel opposite runs edge to edge. Left-hand photos fill their cell instead --
   they already sit between two brand panels, so they read as inset without the gap.

   Photos are background-images rather than <img> for the same reason the heroes are:
   the wash has to composite over the picture, and a background layer stack is the only
   arrangement that does that reliably. See heroBackdrop() in shared/media.js. */
.split-rows { display: grid; }
.split-row { display: grid; }
@media (min-width: 900px) {
  .split-row { grid-template-columns: 1fr 1fr; }
  /* Every row is panel-then-photo in the markup, so a one-column phone always reads
     heading before picture. The alternation is a desktop-only column swap: without it,
     collapsing the grid butts two unrelated photographs against each other. */
  .split-row--reverse .split-row__panel { grid-column: 2; grid-row: 1; }
  .split-row--reverse .split-row__media { grid-column: 1; grid-row: 1; }
}

.split-row__panel {
  display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
  padding: clamp(2.5rem, 1rem + 5vw, 2.5rem) clamp(1.5rem, -2rem + 9vw, 7.5rem);
  min-height: 50vh;
}
.split-row__panel--brand { background: var(--brand); min-height: 60vh; }

.split-row__media {
  background-color: var(--brand-deep);
  background-size: cover; background-position: 50%;
  min-height: 45vw;
}
@media (min-width: 900px) {
  .split-row__media { min-height: 0; }
  /* The stagger: right-hand photos inset to 80% and centered in their row. */
  .split-row:not(.split-row--reverse) .split-row__media { height: 80%; margin-block: auto; }
}

/* Archive typography for these rows: lighter and much airier than the site's default
   prose. font-weight 200/300 is why Inter is requested at those weights in layout.js. */
.split-row__panel .eyebrow {
  font-family: var(--font-body);
  font-size: 1.125rem; font-weight: 200; letter-spacing: .4em;
  color: var(--accent-light); margin-bottom: .625rem;
}
.split-row__panel h2 {
  font-family: var(--font-body);
  font-size: 1.75rem; font-weight: 300; line-height: 1.5;
  margin: 0 0 .9rem; color: var(--brand);
}
.split-row__panel p {
  font-size: 1.125rem; font-weight: 200; line-height: 2.2; margin: 0;
  color: var(--brand);
}
.split-row__panel p + p { margin-top: 1.4rem; }
.split-row__panel--brand h2, .split-row__panel--brand p { color: var(--light-grey); }

/* The centered intro and outro that bracketed the grid (.overview-section). */
.detail-overview { text-align: center; padding-block: clamp(3rem, 1rem + 7vw, 9.375rem); }
.detail-overview .shell { max-width: 46rem; }
.detail-overview .eyebrow {
  font-family: var(--font-body);
  font-size: 1.125rem; font-weight: 200; letter-spacing: .4em; color: var(--accent-light);
}
.detail-overview h2 { font-family: var(--font-body); font-weight: 300; line-height: 1.5; }
/* The global `p` rule caps the measure at --measure and leaves the box left-anchored, which
   in a centered block parks the text ~180px left of center. Re-center it, and take the
   archive's brand navy: at weight 200 the default slate prose color reads washed out. */
.detail-overview p { font-weight: 200; line-height: 2.2; font-size: 1.125rem; color: var(--brand); margin-inline: auto; }

/* ---------- centered picture cards ("Above and Beyond") ---------- */
.tool-cards { display: grid; gap: 1rem; }
@media (min-width: 820px) { .tool-cards { grid-template-columns: repeat(3, 1fr); } }
.tool-card { text-align: center; display: flex; flex-direction: column; align-items: center; }
.tool-card__media {
  width: 100%; max-width: 250px; border-radius: 6px; overflow: hidden;
  box-shadow: 0 2px 5px 2px #0003; margin-bottom: 1.75rem;
}
.tool-card__media img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; }
.tool-card h3 { color: var(--accent); font-size: 1.375rem; margin-bottom: .6rem; }
.tool-card p { max-width: 34ch; margin-inline: auto; }

/* The old build's flat grey band, used behind the About block. */
.section--grey { background: var(--light-grey); }
.section--grey .card { border-color: #d5d5d5; }

/* ---------- arrow-circle link ----------
   The card link from the old site: a thin orange ring that scales to 1.4 while one
   chevron slides out to the right and a second slides in behind it. Both chevrons live
   in the ring; overflow hides them at the edges. 800ms on outExpo, as the original. */
.arrow-link {
  display: inline-flex; align-items: center; gap: .7rem;
  font-family: var(--font-display); font-weight: 700; font-size: .9375rem;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent-dark); text-decoration: none;
}
.arrow-circle {
  position: relative; overflow: hidden; flex: none;
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border: 1.5px solid var(--accent); border-radius: 50%;
  transition: transform .8s var(--ease-out-expo), background-color .5s ease;
}
.arrow-circle svg { position: absolute; width: 14px; height: 14px; transition: transform .8s var(--ease-out-expo), opacity .5s var(--ease-out-expo); }
.arrow-circle .chev-out { transform: translateX(0); opacity: 1; }
.arrow-circle .chev-in { transform: translateX(-100%); opacity: 0; }
.arrow-link:hover .arrow-circle { transform: scale(1.4); }
.arrow-link:hover .chev-out { transform: translateX(100%); opacity: 0; }
.arrow-link:hover .chev-in { transform: translateX(0); opacity: 1; }

/* ---------- image hover ----------
   Frame grows to 1.05 while the picture inside grows to 1.1, so the photo pushes
   against its own edges rather than the whole card drifting. */
.zoom-frame { overflow: hidden; transition: transform 1s cubic-bezier(.25,.46,.45,.94); }
.zoom-frame img { transition: transform 1s cubic-bezier(.55,.085,.68,.53); }
a:hover .zoom-frame, .zoom-frame:hover { transform: scale(1.05); }
a:hover .zoom-frame img, .zoom-frame:hover img { transform: scale(1.1); }
@media (prefers-reduced-motion: reduce) {
  .zoom-frame, .zoom-frame img, .arrow-circle, .arrow-circle svg { transition: none; }
}

/* ---------- grouped checklist ----------
   The old "In-Depth Inspections" column: a slate subhead per system, each followed by
   orange ticks. Distinct from .checklist's orange dots, which the interior pages use. */
.check-group + .check-group { margin-top: 1.5rem; }
.check-group h3 {
  color: var(--slate); font-size: 1.375rem; letter-spacing: -.03em;
  margin-bottom: .4rem;
}
.checklist--check li { padding-left: 1.6rem; margin-bottom: .3rem; color: var(--prose); }
.checklist--check li::before {
  content: ""; position: absolute; left: .15rem; top: .3em;
  width: .42rem; height: .72rem; border-radius: 0; background: none;
  /* A tick is two borders on a TALL box rotated 45deg. On a square box the same rule
     draws a wide chevron, which is what this looked like at first. */
  border-right: 2.5px solid var(--accent);
  border-bottom: 2.5px solid var(--accent);
  transform: rotate(45deg);
}
/* The bold line that closed the old column, above its button. */
.check-tagline {
  font-family: var(--font-display); font-weight: 700; font-size: 1.25rem;
  color: var(--slate); letter-spacing: -.03em; line-height: 1.2;
  margin: 1.75rem 0 0; max-width: 26ch;
}

/* On a narrow viewport the hero copy runs the full width of the screen, but the scrim is
   a left-to-right gradient sized for a text column that only occupies the left third of a
   desktop hero. The right-hand end of every line ends up over open photograph. Below the
   breakpoint, lay a flat wash over the whole frame as well. */
@media (max-width: 720px) {
  .site-hero--photo::before {
    content: ""; position: absolute; inset: 0;
    background: #0000009e; pointer-events: none;
  }
  .site-hero--photo > * { position: relative; z-index: 1; }
}

/* Stock-photo license credits. Deliberately quiet -- small, low contrast, last thing on
   the page -- but genuinely rendered: the licences that require them require them to be
   visible, so this must never become display:none or an off-screen class. */
.site-footer__credits {
  margin: .9rem 0 0;
  font-size: .75rem;
  line-height: 1.5;
  color: #7e97a6;
  max-width: none;
}
.site-footer__credits a { color: #7e97a6; text-decoration: underline; }
.site-footer__credits a:hover { color: var(--accent-light); }

/* ============================================================================
   Home maintenance guide
   ----------------------------------------------------------------------------
   One page, two outputs: the web version and the printable PDF that
   `npm run guide:pdf` renders from this same markup. The @media print block at
   the bottom of this file is the PDF's stylesheet -- there is no second doc.
   ========================================================================== */

/* Tick boxes rather than bullets: people print this and work down it with a pen. */
.tick-list { list-style: none; margin: 0; padding: 0; }
.tick-list li {
  position: relative; padding-left: 2.1rem; margin-bottom: .7rem;
  color: var(--prose); line-height: 1.45;
}
.tick-list li::before {
  content: ""; position: absolute; left: 0; top: .18em;
  width: 1.15rem; height: 1.15rem;
  border: 2px solid var(--gainsboro); border-radius: 3px;
  background: var(--white);
}

.season-grid { display: grid; gap: 1.5rem; margin-top: 2.5rem; }
@media (min-width: 900px) { .season-grid { grid-template-columns: repeat(2, 1fr); } }
.season {
  background: var(--white); border: 1px solid var(--light-grey);
  border-radius: var(--radius); padding: 1.9rem; box-shadow: var(--shadow);
  /* Equal-height cards whose tick lists start at the same line. */
  display: flex; flex-direction: column;
}
.season__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  border-bottom: 2px solid var(--accent); padding-bottom: .6rem; margin-bottom: 1rem;
}
.season__head h3 { margin: 0; color: var(--brand); }
.season__when {
  margin: 0; font-family: var(--font-display); font-weight: 600;
  font-size: .8125rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--slate);
}
.season__note { font-size: 1rem; margin-bottom: 1.2rem; }

.guide-download {
  background: var(--brand-tint); border: 1px solid var(--gainsboro);
  border-radius: var(--radius); padding: 2rem;
}
.guide-download h3 { margin-bottom: .6rem; }
.guide-download p { font-size: 1rem; }

/* Wide table on a narrow screen scrolls inside its own box rather than pushing the
   whole page sideways. */
.table-wrap { overflow-x: auto; margin-top: 2rem; }
table.lifespan { border-collapse: collapse; width: 100%; min-width: 34rem; font-size: 1rem; }
table.lifespan th, table.lifespan td {
  text-align: left; padding: .8rem 1rem; border-bottom: 1px solid var(--light-grey);
  vertical-align: top;
}
table.lifespan thead th {
  font-family: var(--font-display); font-size: .8125rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--white); background: var(--brand);
  border-bottom: 0;
}
table.lifespan tbody tr:nth-child(odd) { background: #fafbfc; }
table.lifespan td:nth-child(2) { white-space: nowrap; font-weight: 600; color: var(--brand); }
table.lifespan td:nth-child(3) { color: var(--slate); }

/* Masthead carried by the maintenance guide for its printed form only. Declared here,
   ahead of the print block, so @media print can turn it on -- a base rule placed after
   that block would win on source order and keep it hidden on paper. */
.print-masthead { display: none; }

/* ---------- print / PDF ----------
   What `npm run guide:pdf` actually renders. The chrome comes off, the palette goes
   ink-friendly, and the page breaks are pinned so a season's checklist is never split
   across two sheets. */
@media print {
  @page { size: letter; margin: 14mm 14mm 16mm; }

  .site-header, .site-footer, .breadcrumbs, .skip-link,
  .btn-row, .guide-download, .section--brand { display: none !important; }

  /* Reveal animations must not leave the printed page blank. */
  [data-reveal] { opacity: 1 !important; transform: none !important; }

  body { background: #fff; color: #1b2330; font-size: 10.5pt; line-height: 1.45; }
  p { color: #333; font-size: 10.5pt; max-width: none; }
  .shell { width: 100%; max-width: none; }
  .section, section.shell { padding-block: 0 !important; }
  .section--grey, .section--tint { background: none !important; }

  h1 { font-size: 24pt; color: #053f5c; }
  h2 { font-size: 15pt; color: #053f5c; margin-top: 1.4em; }
  h3 { font-size: 11.5pt; }
  .eyebrow { color: #f47f00; font-size: 7.5pt; }
  .lede { font-size: 11pt; }

  /* The hero is a background image, which print drops by default; render it as a plain
     titled block instead of a grey void. */
  .site-hero--photo { background: none !important; min-height: 0 !important; padding-block: 0 !important; }
  .site-hero h1, .site-hero p { color: #1b2330 !important; }
  .site-hero h1 em { color: #f47f00 !important; }
  /* On screen the hero copy is held to a short measure against a photograph; on paper
     that leaves a narrow ragged column with the next heading crowding under it. */
  .site-hero p { max-width: none; }
  .site-hero { margin-bottom: 18pt; }

  .print-masthead {
    display: flex; align-items: center; justify-content: space-between; gap: 12pt;
    border-bottom: 1.5pt solid #053f5c; padding-bottom: 7pt; margin-bottom: 16pt;
  }
  .print-masthead img { width: 122px; height: auto; }
  .print-masthead p {
    margin: 0; font-family: Montserrat, Helvetica, Arial, sans-serif; font-weight: 600;
    font-size: 8pt; letter-spacing: .09em; text-transform: uppercase; color: #7e828f;
  }

  .season-grid { display: block; }
  .season {
    box-shadow: none; border: 1px solid #ccc; padding: 12pt;
    margin-bottom: 12pt;
    /* Keep a season's list whole on one sheet. */
    break-inside: avoid; page-break-inside: avoid;
  }
  .tick-list li { margin-bottom: .42rem; break-inside: avoid; }
  .tick-list li::before { border-color: #666; }

  .card { box-shadow: none; border: 1px solid #ccc; break-inside: avoid; }
  .grid--3, .split { display: block; }
  .grid--3 > * , .split > * { margin-bottom: 10pt; }
  .table-wrap { overflow: visible; }
  table.lifespan { min-width: 0; font-size: 9.5pt; break-inside: auto; }
  table.lifespan thead { display: table-header-group; }
  table.lifespan tr { break-inside: avoid; }
  table.lifespan thead th { background: #053f5c !important; color: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }

  a { color: inherit; text-decoration: none; }
}

