.site-bar {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--paper-raised);
  border-bottom: 1px solid var(--line);
}
.site-bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 20px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: var(--ink);
}
.brand-word {
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 1.3rem;
  color: var(--slate-dark);
  letter-spacing: -0.01em;
}
.brand-word em { font-style: normal; color: var(--rust); }
.site-bar-note {
  font-size: 0.85rem;
  color: var(--ink-faint);
  display: none;
}
@media (min-width: 640px) {
  .site-bar-note { display: block; }
}

.header-geo { display: none; align-items: center; gap: 22px; }
@media (min-width: 640px) { .header-geo { display: flex; } }
.header-geo-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 1.2rem;
  color: var(--ink-soft);
  text-decoration: none;
}
.header-geo-item svg { width: 24px; height: 24px; flex: none; color: var(--rust); }
.header-geo-phone { font-weight: 700; color: var(--slate-dark); }
.header-geo-phone:hover { color: var(--rust-dark); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--rust-dark);
  margin: 0 0 0.9em;
}

.hero {
  padding: 28px 0 52px;
  background: var(--paper);
}

/* Hero mosaic — arrangement borrowed from a reference the user liked
   (headline+CTA tile, two small support tiles, one tall photo tile);
   content and photography are our own. */
.hero-mosaic {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  /* Reference's own gap, measured directly at 1280px between every pair of
     blocks (title→tiles, tile→tile, tiles→photo) — 11px everywhere, not
     20. Was 20 here for a while without ever being checked back against
     the actual number — close enough to not look broken, wrong regardless. */
  .hero-mosaic { grid-template-columns: 1.15fr 0.95fr; gap: 11px; align-items: stretch; }
}

.mosaic-col { display: flex; flex-direction: column; gap: 16px; }
@media (min-width: 900px) {
  .mosaic-col { gap: 11px; }
}

/* Theme tokens the carousel swaps per active photo (assets/js/carousel.js
   sets data-theme on .hero-mosaic) — tiles read the photo's own mood back,
   the three of them tied together instead of each sitting on its own
   unrelated background. Defaults below are theme 1 (hero-1, blue sky). */
/* Renumbered after hero-1-house, hero-2-roof, and hero-3-downspout were
   dropped from the carousel — theme N now matches whichever slide is
   actually in position N, not the original file numbering. */
.hero-mosaic {
  --tile-light: #fefffe;
  --tile-dark: #191d22;
  --tile-dark-rgb: 25, 29, 34;
  --tile-dark-sub: #c7ccd1;
  --mosaic-photo-url: url('../img/hero/hero-4.webp');
}
.hero-mosaic[data-theme="2"] { --tile-light: #f9f7f4; --tile-dark: #151517; --tile-dark-rgb: 21, 21, 23; --tile-dark-sub: #c7ccd1; }
.hero-mosaic[data-theme="3"] { --tile-light: #ffffff; --tile-dark: #272d3b; --tile-dark-rgb: 39, 45, 59; --tile-dark-sub: #c7ccd1; }
.hero-mosaic[data-theme="4"] { --tile-light: #ffffff; --tile-dark: #232427; --tile-dark-rgb: 35, 36, 39; --tile-dark-sub: #c7ccd1; }
.hero-mosaic[data-theme="5"] { --tile-light: #e8e8e8; --tile-dark: #060709; --tile-dark-rgb: 6, 7, 9; --tile-dark-sub: #c7ccd1; }
.hero-mosaic[data-theme="6"] { --tile-light: #edeae9; --tile-dark: #0b0909; --tile-dark-rgb: 11, 9, 9; --tile-dark-sub: #c7ccd1; }
.hero-mosaic[data-theme="7"] { --tile-light: #ffffff; --tile-dark: #202430; --tile-dark-rgb: 32, 36, 48; --tile-dark-sub: #c7ccd1; }

.mosaic-main {
  flex: 1 1 auto;
  /* Fixed, not tied to --tile-light/data-theme — this is the reading
     surface for the heading and CTA, not a photo accent tile. Shifting
     color here on every slide change was more distraction than payoff;
     the two small tiles still carry the per-photo tint. */
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 44px 46px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
@media (min-width: 900px) {
  /* Reference's headline tile measures 682×426 at a 1280px viewport —
     clearly wider than tall (ratio 1.6), not the near-square box content
     was pushing ours into. Locking the ratio to the tile's own width (not
     its content) is what makes the photo column come out the right shape
     too, since it stretches to match this tile + the pair beneath it.
     flex-grow has to go — it was resizing the tile to fill the column
     and winning over aspect-ratio every time.
     Content is tight in here for now on purpose — copy gets a real pass
     next, this step is the shape. */
  /* Padding measured directly off the reference too (91px 49px) — was
     40px 44px, never actually checked against the real number. */
  .mosaic-main { flex: 0 0 auto; aspect-ratio: 682 / 426; padding: 91px 49px; min-height: 0; }
  /* Reference DOM, measured directly (getComputedStyle, not eyeballed):
     .hero-info__title is 56px/600/56px line-height, .hero-info__dsc is
     28px/400/28px, the button's own text is 21px — but that measurement
     was taken at a single 1280px viewport, and got applied here as a flat
     value across the WHOLE 900px+ range. .mosaic-main's box is width-driven
     (aspect-ratio: 682/426, right above), so it's genuinely shorter at the
     narrow end of that range — a flat 56px h1 doesn't fit there and pushes
     the box open, overlapping the tile above it. clamp() ties the size to
     viewport width so it only reaches the full reference value once the
     box itself is actually big enough to hold it; verified by checking the
     rendered h1's own box stays inside .mosaic-main's at both 900px and a
     1280px-plus width, not just eyeballed at one size. */
  .mosaic-main h1 { font-size: clamp(1.2rem, -2.1rem + 5.6vw, 2.8rem); line-height: 1.1; }
  /* Reference's own title tile only carries a title + one line of dsc +
     button — no separate eyebrow. Ours was the odd one out competing for
     the same vertical space as the now-full-size type; dropped here only
     (still shown everywhere else eyebrow is used sitewide). */
  .mosaic-main .eyebrow { display: none; }
  .mosaic-main .hero-lede { font-size: clamp(1.05rem, -0.35rem + 2.9vw, 1.75rem); line-height: 1.2; }
  .mosaic-main .btn { font-size: clamp(1rem, 0.55rem + 1.1vw, 1.3125rem); padding: 1em 1.7em; }
}
.hero-lede { font-size: 1.05rem; max-width: 46ch; }
.hero-actions { margin-top: 0.9em; display: flex; flex-direction: column; gap: 0.5em; align-items: flex-start; }
.hero-fineprint { font-size: 0.85rem; color: var(--ink-faint); margin: 0; }

.mosaic-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (min-width: 900px) { .mosaic-pair { gap: 11px; } }

.mosaic-tile {
  border-radius: var(--radius-lg);
  padding: 26px 24px;
  min-height: 148px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Plain flat tint below 900px on purpose, not a fallback — below that
     width the photo is a single whole image on its own (see .mosaic-photo),
     the two small tiles are just text, matching the reference: on its own
     mobile layout the photo is one full-width image, not sliced into the
     support tiles at all. The photo-backed treatment is desktop-only,
     further down — that's where these two tiles sit next to the photo tile
     and "one photo across three windows" actually means something. */
  background-color: var(--tile-dark);
  transition: background-color 700ms ease;
}
.statement-text {
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 1.5rem;
  color: #fff;
  margin: 0 0 0.35em;
  line-height: 1.15;
}
.statement-sub { font-size: 0.88rem; color: var(--tile-dark-sub); margin: 0; transition: color 700ms ease; }

.trust-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.trust-list li {
  font-size: 0.88rem;
  color: var(--tile-dark-sub);
  margin: 0;
  transition: color 700ms ease;
}

@media (min-width: 900px) {
  /* This block must stay AFTER the base rules above — same selectors,
     same specificity, so source order is what decides the winner. Had it
     backwards once already: the override sat before the base rule and
     silently lost every time, regardless of viewport or cache.
     Reference's support tiles measure 335×324px at a 1280px viewport —
     effectively square (ratio 1.03), not a tall strip. aspect-ratio holds
     that shape off whatever width the column split lands on, independent
     of the headline tile's height. */
  .mosaic-tile {
    aspect-ratio: 1;
    min-height: 0;
    padding: 24px 26px;
    background-repeat: no-repeat, no-repeat;
    /* Same photo the big tile is showing, not a flat fill — the tint keeps
       text readable over whatever the photo happens to be doing underneath.
       Desktop-only: here the tile sits right next to the photo tile, so a
       shared crop reads as one photo continuing across them. rgba() + the
       *-rgb channel-list custom property, not color-mix(): if color-mix()
       isn't supported, the WHOLE background-image list (both layers) is
       invalid and the browser drops it entirely, straight back to a flat
       background-color with no photo at all. rgba() has been safe
       everywhere custom properties themselves work. */
    background-image:
      linear-gradient(rgba(var(--tile-dark-rgb), 0.6), rgba(var(--tile-dark-rgb), 0.6)),
      var(--mosaic-photo-url);
  }
  .statement-text { font-size: 2.2rem; }
  .statement-sub { font-size: 1.15rem; }
  .mosaic-trust .statement-text { margin-bottom: 0.3em; }
  .trust-list { gap: 8px; }
  .trust-list li { font-size: 1.15rem; }

  /* Lines the two tiles up as one continuous frame with the photo tile:
     each is a window onto the SAME image (--mosaic-photo-url), zoomed and
     shifted so the strip they show picks up exactly where the next one
     starts. Sizes/positions are percentages derived from the reference's
     own measured geometry (682x426 headline tile, 11px gaps, 335x324
     support tiles, 557x761 photo — see plan journal), not eyeballed, so
     they stay correct at any viewport width, not just 1280px. */
  .mosaic-statement, .mosaic-trust {
    background-size: 100% 100%, 373% 235%;
  }
  .mosaic-statement { background-position: 0 0, 0% 100%; }
  .mosaic-trust { background-position: 0 0, 38% 100%; }
}

.mosaic-photo {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  min-height: 320px;
}
@media (min-width: 900px) {
  /* .mosaic-col has no intrinsic height of its own once its rows are
     fr-based, so this is the side that sets the row's real height; the
     column stretches to match via align-items: stretch on .hero-mosaic. */
  .mosaic-photo { min-height: 560px; }
}

.photo-carousel, .carousel-track { position: relative; width: 100%; height: 100%; min-height: inherit; }
.carousel-slide {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 900ms ease;
}
.carousel-slide.is-active { opacity: 1; }

/* Paired with carousel.js's crop-ready gate: at 900px+ the photo is
   JS-cropped to fill three mosaic tiles, and that math isn't trustworthy
   until fonts have settled (see carousel.js) — hide it until then so
   there's only ever one visible geometry, not a jump between two. */
@media (min-width: 900px) {
  .photo-carousel:not(.crop-ready) .carousel-slide { visibility: hidden; }
}

.carousel-controls {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: flex;
  gap: 8px;
  z-index: 2;
}
.carousel-btn {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: none;
  background: #fff;
  color: var(--slate-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow-card);
  font-size: 1rem;
  line-height: 1;
}
.carousel-btn:hover { background: var(--rust-tint); color: var(--rust-dark); }

section > .wrap { padding-top: 46px; padding-bottom: 46px; }

.section-lede { max-width: 62ch; }

.cost-panel { background: var(--paper-raised); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.cost-table-wrap { overflow-x: auto; margin-top: 1.4em; border-radius: var(--radius-md); box-shadow: var(--shadow-card); }
.cost-table { width: 100%; border-collapse: collapse; min-width: 480px; background: var(--paper); border-radius: var(--radius-md); overflow: hidden; }
.cost-table th, .cost-table td { text-align: left; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.cost-table th {
  font-family: var(--font-head);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #dfe6ea;
  background: var(--slate-dark);
}
.cost-table td.num, .cost-table th:nth-child(2), .cost-table th:nth-child(3) { font-family: var(--font-mono); }
.cost-table tbody tr:last-child td { border-bottom: none; }
.cost-price { font-weight: 700; color: var(--slate-dark); font-size: 1.05em; }

/* One row gets a light call-out treatment, not because it's cheapest or
   priciest but because it's what most homeowners actually end up choosing —
   a real, defensible reason to point at it, not an arbitrary "best deal"
   badge. Left accent bar instead of a full-row fill so it reads as a
   highlight, not an alert. */
.cost-table tr.is-recommended td { background: var(--rust-tint); }
.cost-table tr.is-recommended td:first-child { border-left: 3px solid var(--rust); padding-left: 15px; }
.cost-tag {
  display: inline-block;
  margin-left: 10px;
  padding: 0.2em 0.6em;
  border-radius: 999px;
  background: var(--rust);
  color: #fff;
  font-family: var(--font-head);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  vertical-align: middle;
}
.table-note { font-size: 0.86rem; color: var(--ink-faint); margin-top: 1em; margin-bottom: 0; }

.how-it-works { background: var(--paper-raised); border-bottom: 1px solid var(--line); }
.steps {
  display: grid;
  gap: 28px;
  margin-top: 1.8em;
  grid-template-columns: 1fr;
}
@media (min-width: 700px) { .steps { grid-template-columns: repeat(3, 1fr); gap: 24px; } }
.step-card { position: relative; }
.step-num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--slate-dark);
  color: #fff;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 1.1rem;
  margin-bottom: 0.7em;
}
.step-card h3 { margin-bottom: 0.35em; }
.step-card p { margin: 0; font-size: 0.96rem; color: var(--ink-soft); }
/* Connects the three steps into one line on desktop, echoing "a process"
   rather than three unrelated cards — a plain rule, not a gradient. */
@media (min-width: 700px) {
  .step-card:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 20px;
    left: calc(100% + 12px);
    width: calc(24px - 12px);
    border-top: 2px dashed var(--line-strong);
  }
}

.reassure { background: var(--paper); }
.reassure-grid { display: grid; gap: 18px; margin-top: 1.6em; grid-template-columns: 1fr; }
@media (min-width: 700px) { .reassure-grid { grid-template-columns: repeat(3, 1fr); } }
.reassure-item {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 20px 22px;
}
.reassure-item h3 { color: var(--slate-dark); margin-bottom: 0.4em; font-size: 1.05rem; }
.reassure-item p { margin: 0; font-size: 0.94rem; color: var(--ink-soft); }

.factors-grid { display: grid; gap: 18px; margin-top: 1.6em; grid-template-columns: 1fr; }
@media (min-width: 700px) { .factors-grid { grid-template-columns: repeat(2, 1fr); } }
.factor-card {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 20px 22px;
}
.factor-card h3 { color: var(--slate-dark); margin-bottom: 0.4em; }
.factor-card p { margin: 0; font-size: 0.96rem; }

.materials { background: var(--slate-dark); }
.materials h2, .materials .section-lede { color: #f2ede1; }
.materials h2 { color: #ffffff; }
.materials-grid {
  display: grid;
  gap: 18px;
  margin-top: 1.8em;
  grid-template-columns: 1fr;
}
@media (min-width: 560px) { .materials-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px) {
  /* Reference's own cards measured narrow (~115px at a 1280px viewport),
     but pinning this grid to that exact width left it stranded as a small
     island in the middle of a much wider dark section on a wide window —
     the reference's SECTION container is probably narrower than this
     one's, not just the card row. Filling the section's own content width
     instead — same fix as the hero's --content-wide cap, just applied
     here too — keeps it proportionate at any width instead of matching
     one specific measurement and breaking at every other size. */
  .materials-grid { grid-template-columns: repeat(5, 1fr); gap: 16px; }
}
.material-card {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius-md);
  overflow: hidden;
}
/* Reference's own card photo is a short, wide band, not a square — roughly
   a quarter of the card's total height (measured off the screenshot: photo
   ~65px of a ~250px-tall card, card ~116px wide, so close to 1.8:1). A
   square image was eating half the card and made ours nearly twice as
   tall as the reference's for the same content. */
.material-card picture { display: block; }
.material-card img { width: 100%; height: auto; aspect-ratio: 1.8 / 1; object-fit: cover; display: block; }
.material-card h3 { color: #ffffff; font-size: 1.05rem; margin: 0.8em 0.9em 0.35em; }
.material-card p { color: #d7dde1; font-size: 0.87rem; line-height: 1.45; margin: 0 0.9em 0.9em; }

.signs { background: var(--slate-dark); }
.signs h2, .signs p { color: #f2ede1; }
.signs h2 { color: #ffffff; }
.signs-list { list-style: none; margin: 1.4em 0; padding: 0; display: grid; gap: 10px; }
.signs-list li {
  position: relative;
  padding-left: 26px;
  color: #dfe6ea;
  font-size: 0.98rem;
}
.signs-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.5em;
  width: 9px; height: 9px;
  border: 2px solid var(--rust);
  border-radius: 2px;
  transform: rotate(45deg);
}

.invest { background: var(--paper-raised); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.invest-inner {
  display: grid;
  gap: 28px;
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 760px) {
  .invest-inner { grid-template-columns: 0.9fr 1.1fr; gap: 44px; }
}
/* .invest-photo's own height:100% rule below needs the grid to keep
   stretching IT directly — display:contents drops the <picture> wrapper
   out of layout entirely so the <img> is still the real grid item, same
   as before the AVIF/WebP <source> markup was added around it. */
.invest-inner picture { display: contents; }
.invest-photo {
  width: 100%;
  height: 260px;
  object-fit: cover;
  border-radius: var(--radius-lg);
  display: block;
}
@media (min-width: 760px) { .invest-photo { height: 100%; min-height: 380px; } }
.invest-copy .btn { margin-top: 0.4em; }
.invest-copy p { margin-bottom: 1em; }

.state-hero { background: var(--paper-raised); border-bottom: 1px solid var(--line); }
.state-hero .hero-actions { margin-top: 1.4em; }
.state-context p { max-width: 68ch; }
.state-context p + p { margin-top: 1em; }
.state-links { background: var(--paper-raised); border-top: 1px solid var(--line); }
.state-links-grid { display: flex; flex-wrap: wrap; gap: 10px 28px; margin-top: 1.2em; }
.state-links-grid a { color: var(--slate-dark); font-weight: 600; }

.faq-list { margin-top: 1.6em; }
.faq-item { padding: 26px 0; border-bottom: 1px solid var(--line); }
.faq-item:first-child { border-top: 1px solid var(--line); }
.faq-item h3 { font-size: 1.15rem; margin: 0 0 10px; }
.faq-item p { margin: 0; color: var(--ink-soft); }

.cta-band { background: var(--paper-raised); border-top: 1px solid var(--line); }
.cta-band-inner { text-align: center; }
.cta-band-inner p { max-width: 52ch; margin-left: auto; margin-right: auto; }
.cta-band-inner .btn { margin-top: 0.6em; }
