/* ==========================================================================
   Titan Roofing — website design system
   Recreated from the Figma prototype "Titan Roofing Pros" (the prototype's own
   name; the company DBAs as Titan Roofing / Titan Roofing LLC), then rebuilt on
   the real Dev Assets handoff from Hook Agency (fonts, logos, photography,
   scribble SVGs). Real brand fonts:
     - Display (all-caps hero/H1): Zalando Sans Expanded (Black 900)
     - Headings + body:            DM Sans
   ========================================================================== */

@font-face {
  font-family: 'Zalando Sans Expanded';
  src: url('../fonts/ZalandoSansExpanded-Variable.woff2') format('woff2'),
       url('../fonts/ZalandoSansExpanded-Variable.ttf') format('truetype-variations');
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: 'DM Sans';
  src: url('../fonts/DMSans-Variable.woff2') format('woff2'),
       url('../fonts/DMSans-Variable.ttf') format('truetype-variations');
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* Brand color tokens (sampled from prototype) */
  --red: #e01f26;            /* primary CTA red */
  --red-dark: #b71f25;       /* section band red */
  --maroon: #8f2b30;         /* two-column heading red */
  --ink: #121212;            /* near-black page background */
  --ink-2: #1a1a1a;          /* raised dark surface */
  --ink-3: #232323;          /* dark card / footer bar */
  --white: #ffffff;
  --off-white: #f5f5f5;      /* light section background */
  --gray-100: #ececec;       /* brand-logo bar background */
  --gray-200: #e0e0e0;
  --gray-500: #8a8a8a;
  --body-on-white: #4b4b4b;
  --body-on-dark: #cfcfcf;

  --font-display: 'Zalando Sans Expanded', 'Arial Black', sans-serif;
  --font-sans: 'DM Sans', 'Segoe UI', sans-serif;

  --container: 1180px;
  --header-h: 92px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.65;
  color: var(--body-on-white);
  background: var(--white);
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }

.container { max-width: var(--container); margin: 0 auto; padding: 0 24px; }

/* --------------------------------------------------------------------------
   Typography
   -------------------------------------------------------------------------- */
.display {
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  line-height: 1.02;
  letter-spacing: 0.01em;
  color: var(--white);
}
h1.display { font-size: clamp(44px, 6.5vw, 92px); }
h2.display { font-size: clamp(32px, 4.5vw, 56px); }
/* Phones: the display face is wide, and one long word (CONSTRUCTION,
   REPRESENTATIVE, UNDERSTANDING) at the 44px floor runs past a 375px screen,
   which makes mobile browsers zoom the whole page out. Lower floor, and let
   the browser hyphenate when a single word still cannot fit. */
@media (max-width: 600px) {
  /* Display headings on phones: sized so the longest words ("Calculator",
     "Replacement", "Understanding") fit on a line. No hyphenation and no
     mid-word breaks (owner, 2026-10-08: "Calcu-lator" is not acceptable);
     break-word only steps in if a word still cannot fit at all. */
  h1.display { font-size: clamp(24px, 7.6vw, 44px); overflow-wrap: break-word; hyphens: manual; }
  h2.display { font-size: clamp(22px, 6.8vw, 40px); overflow-wrap: break-word; hyphens: manual; }
}

h2.title, h3.title {
  font-family: var(--font-sans);
  font-weight: 700;
  color: var(--ink);
  line-height: 1.2;
}
h2.title { font-size: clamp(28px, 3.2vw, 42px); }
h3.title { font-size: clamp(20px, 2.2vw, 26px); }
.title--maroon, h2.title--maroon, h3.title--maroon { color: var(--maroon); }
.title--white, h2.title--white, h3.title--white { color: var(--white); }

.eyebrow {
  display: block;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  margin-bottom: 14px;
}
.eyebrow--red { color: var(--red); }
.eyebrow--gray { color: var(--gray-500); }
.eyebrow--light { color: #d9d9d9; }

.lead { max-width: 640px; }
.on-dark { color: var(--body-on-dark); }

/* Hand-drawn scribble accents — real brush SVGs from the Dev Assets handoff.
   .scribble        = red underline stroke beneath the word
   .scribble--behind = fat red highlight sitting behind the word (hero style)
   .scribble--dark   = charcoal highlight, for headings on red bands */
.scribble { position: relative; display: inline-block; z-index: 0; }
.scribble::after {
  content: '';
  position: absolute;
  left: -4%; right: -4%; bottom: -0.24em;
  height: 0.42em;
  background: url('../scribbles/red-underline-scribble.webp') no-repeat center / 100% 100%;
  z-index: -1;
}
.scribble--behind::after {
  left: -7%; right: -5%; top: 0.2em; bottom: 0.06em;
  height: auto;
  background-image: url('../scribbles/red-highlight-scribble.webp');
}
/* Was the 283x53 charcoal highlight — a fat blob sitting behind the word, which
   on the red band read as a random bulky smear rather than an accent. Now the
   thin 214x12 double-stroke underline instead, flood-filled charcoal through a
   mask (same technique as the social icons), so it reads as a deliberate rule.
   Used on the About page's "Live By" and the FAQ hero's "Answers" — both sit on
   a red band, which is the whole reason this variant exists. */
.scribble--dark::after {
  background-image: none;
  background-color: var(--ink);
  left: -2%; right: -2%;
  bottom: -0.16em;
  height: 0.18em;
  -webkit-mask: url('../scribbles/red-underline-scribble.webp') no-repeat center / 100% 100%;
  mask: url('../scribbles/red-underline-scribble.webp') no-repeat center / 100% 100%;
}

/* --------------------------------------------------------------------------
   Buttons — square corners everywhere (no border radius in this design)
   -------------------------------------------------------------------------- */
.btn {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 600;
  padding: 13px 30px;
  border: 2px solid transparent;
  cursor: pointer;
  transition: all .15s ease;
  text-align: center;
}
.btn--red { background: var(--red); color: var(--white); }
.btn--red:hover { background: #c11920; }
.btn--outline-white { border-color: var(--white); color: var(--white); background: transparent; }
.btn--outline-white:hover { background: var(--white); color: var(--ink); }
.btn--outline-dark { border-color: var(--ink); color: var(--ink); background: transparent; }
.btn--outline-dark:hover { background: var(--ink); color: var(--white); }
.btn--outline-red { border-color: var(--red); color: var(--red); background: transparent; }
.btn--outline-red:hover { background: var(--red); color: var(--white); }

/* Section dividers — hard angled cut.
   -------------------------------------------------------------------------
   Third attempt at this. The handoff shipped a 1440x129 distressed-brush strip,
   which read cheap and marker-like. That was replaced with a soft smoke
   gradient plus a hairline, which read glitchy: a 108px blur bands badly on real
   panels, and the hairline sitting at 62% looked like a rendering seam rather
   than a design element — exactly the two things the owner pointed at.

   So: no blur, no gradient, no hairline. One straight edge, cut on the
   diagonal, with the two section colours meeting along it. There is nothing to
   band because there is no gradient, and nothing to mistake for an artifact
   because the only line in the frame runs corner to corner.

   The angle comes from the element's own proportions rather than a fixed
   degree, so it stays a clean corner-to-corner cut at any width: about 3° on a
   desktop viewport, steeper and more emphatic on a phone. Pitched like a roof,
   which is the point.

   --from is the section above, --to the section below. site.js overwrites both
   from the real neighbours on load, because the .grunge--{x}-on-{y} class names
   are wrong on 49 of the 59 instances; the values below are only the no-JS
   fallback. Markup is untouched — every existing divider picks this up. */
.grunge {
  --from: var(--ink);
  --to: var(--white);

  position: relative;
  height: 76px;
  overflow: hidden;

  /* ONE paint layer. No clip-path, no stacked element — and that is the whole
     point, not a simplification.

     Drawing this as two layers, either way round, put a hairline at the seam.
     A triangle clipped over a flat base always has one full-width edge sitting
     exactly on a box edge: bottom edge on the box bottom in the first version,
     top edge on the box top in the second. Layout here is fractional — 54 of
     the 58 dividers have an edge landing mid-pixel, one bottom measures
     855.95px — so that physical row is only partly covered by the triangle and
     the colour underneath bleeds through at partial alpha. First version leaked
     the upper colour along the bottom seam; the second moved the same leak to
     the top seam, where white against the red core-values band was worse.

     A single hard-stop gradient has nothing underneath to leak. `to bottom
     right` is doing real work: for corner keywords CSS angles the gradient line
     so the two other corners — bottom-left and top-right — both sit at the 50%
     position, so a hard stop there runs exactly corner to corner, at any
     width, with no angle to keep in sync. The top edge is entirely --from and
     the bottom edge entirely --to, so neither element boundary can expose a
     third colour. The only antialiased edge left is the diagonal, blending the
     two section colours into each other, which is what it should do. */
}
/* 2026-09-25: the owner rejected the diagonal cut too ("the fold looks really
   bad", homepage and About). Fourth pass: no divider at all. Sections meet on a
   straight edge and the band collapses. Everything above stays so the angled
   cut can come back with one line if wanted; the JS colour resolution is
   harmless at zero height. Pages that overlap a photo across the seam (the
   homepage hero) already do it with a negative margin, which needs no band. */
/* 2026-09-29: brush-stroke dividers (owner's artwork, the same stroke as the
   homepage fold). The stroke is a mask, so one image paints in any colour:
   site.js resolves --from / --to from the real neighbours and picks a variant.
     up (default)   band = section above, stroke = section below rising into it
     .grunge--down  band = section below, stroke = section above hanging down
     .grunge--mirror  flipped left-right, so neighbouring dividers differ
     .grunge--over  no band: the stroke lies over a photo section (the hero
                    above, or a full-width photo below) like the homepage fold
   Solid "up" bands tuck half their height into the section above's padding
   (same colour, so invisible) to keep the page from growing. */
.grunge {
  --bh: max(5.3vw, 44px);
  height: var(--bh);
  overflow: visible;
  z-index: 1;
  background: var(--from);
  margin-top: calc(-.5 * var(--bh));
}
.grunge::before { background-image: var(--from-img, none); }
.grunge::after {
  background-color: var(--to);
  background-image: var(--to-img, none);
  -webkit-mask: url('../img/fold-brush-red.webp') center bottom / auto 100% repeat-x;
  mask: url('../img/fold-brush-red.webp') center bottom / auto 100% repeat-x;
}
/* Layout lands on fractional pixels, so the stroke overhangs its solid edge by
   2px into the section it belongs to; otherwise the partly covered last row
   lets the other colour through as a hairline. */
.grunge:not(.grunge--down)::after { bottom: -2px; }
.grunge--down::after { top: -2px; }
.grunge--down { background: var(--to); margin-top: 0; }
.grunge--down::before { background-image: var(--to-img, none); }
.grunge--down::after { background-color: var(--from); background-image: var(--from-img, none); transform: scaleY(-1); }
.grunge--mirror::after { transform: scaleX(-1); }
.grunge--down.grunge--mirror::after { transform: scale(-1, -1); }
.grunge--over { background: transparent; margin-top: calc(-1 * var(--bh)); }
.grunge--over::before { display: none; }
.grunge--over.grunge--down { margin-top: 0; margin-bottom: calc(-1 * var(--bh)); }
/* In-hero streaks on blog posts sit inside the photo, not between sections. */
.grunge.streak { height: 0; margin: 0; }

.grunge::before,
.grunge::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Both neighbours the same colour, or no way to draw one: collapse. */
.grunge.is-null { height: 0; margin: 0; }

.grunge--flat { background-image: none; }

.grunge--black-on-red { --from: var(--red-dark); --to: var(--ink); }
.grunge--red-on-black { --from: var(--ink); --to: var(--red-dark); }
.grunge--white-on-red { --from: var(--red-dark); --to: var(--white); }
.grunge--white-on-black { --from: var(--ink); --to: var(--white); }

/* Angled white paint band that slices between sections (Company Promise →
   Process, Process → Service Area). Real 1440x271 asset. */
.angle-band {
  height: 150px;
  background: no-repeat center / 100% 100%;
  background-image: url('../scribbles/white-angled-scribble-1.svg');
}
.angle-band--2 { background-image: url('../scribbles/white-angled-scribble-2.svg'); }
.angle-band--charcoal { background-image: url('../scribbles/charcoal-angled-scribble.svg'); }

/* --------------------------------------------------------------------------
   Header — dark bar: nav left, centered logo, phone + CTA right
   -------------------------------------------------------------------------- */
.site-header {
  background: rgba(18, 18, 18, 0.96);
  color: var(--white);
  height: var(--header-h);
  display: flex;
  align-items: center;
  position: sticky;
  top: 0;
  z-index: 100;
}
.site-header .container {
  max-width: 1360px;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
}
.nav { display: flex; gap: 28px; font-weight: 500; font-size: 15.5px; }
.nav > li { position: relative; }
/* Five top-level items since Reviews joined the bar (2026-10-01): labels never
   wrap, and the bar tightens on narrower desktops instead of breaking a line. */
.nav > li > a { white-space: nowrap; }
@media (max-width: 1280px) {
  .nav { gap: 18px; font-size: 14.5px; }
  .header-right { gap: 14px; }
  .header-phone { font-size: 15.5px; }
}
.header-phone, .header-right .btn { white-space: nowrap; }
@media (max-width: 1100px) {
  .nav { gap: 13px; font-size: 14px; }
  .nav .caret { font-size: 8px; }
  .site-header .logo img { height: 42px; }
  .header-right { gap: 10px; }
  .header-phone { font-size: 14px; gap: 5px; }
  .header-right .btn { padding: 12px 14px; font-size: 14px; }
}
@media (max-width: 980px) {
  .nav { gap: 10px; font-size: 13.5px; }
  .site-header .logo img { height: 38px; }
  .header-phone { font-size: 13.5px; }
  .header-right .btn { padding: 11px 10px; font-size: 13.5px; }
}
.nav a { color: var(--white); display: inline-flex; align-items: center; gap: 6px; }
.nav a:hover { color: var(--red); }
.nav .caret { font-size: 10px; opacity: .9; transition: transform .15s ease; }
.nav > li:hover > a { color: var(--red); }
.nav > li:hover .caret { transform: rotate(180deg); }

/* Dropdown menus — open on hover, keyboard-reachable via :focus-within */
.nav .submenu {
  position: absolute;
  top: 100%;
  left: -18px;
  min-width: 244px;
  background: var(--ink);
  border-top: 3px solid var(--red);
  box-shadow: 0 20px 44px rgba(0, 0, 0, .45);
  padding: 8px 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
  z-index: 120;
}
.nav > li:hover > .submenu,
.nav > li:focus-within > .submenu { opacity: 1; visibility: visible; transform: translateY(0); }
.nav .submenu li + li { border-top: 1px solid rgba(255, 255, 255, .07); }
.nav .submenu a {
  display: block;
  padding: 11px 22px;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--body-on-dark);
  white-space: nowrap;
}
.nav .submenu a:hover { background: var(--red); color: var(--white); }
/* Services dropdown — Residential | Commercial, one column each.
   The markup is two `.submenu-col` groups (heading + its own list), so the
   split is fixed by structure, not by row count: the earlier 8-row auto-flow
   grid spilled into a third column as soon as either group grew past eight
   rows. Stacked in one column the menu ran past the bottom of a 720px
   viewport; side by side it fits and mirrors the footer's two service lists.
   Scoped above 900px — below that the menu is a stacked accordion instead. */
@media (min-width: 901px) {
  .nav .submenu--services {
    display: grid;
    grid-template-columns: repeat(2, minmax(206px, max-content));
  }
  /* One divider between the columns instead of a row rule across the gap. */
  .nav .submenu--services > li + li {
    border-top: none;
    border-left: 1px solid rgba(255, 255, 255, .10);
  }
}
.nav .submenu .submenu-head {
  display: block;
  padding: 10px 22px 6px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gray-500);
}
/* Hair gap between trigger and panel would drop the hover — bridge it */
.nav > li.has-submenu::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 100%;
  height: 18px;
}

.logo { display: inline-block; line-height: 0; }
.logo img { height: 52px; width: auto; }
.site-footer .logo img { height: 62px; }

.header-right { display: flex; align-items: center; justify-content: flex-end; gap: 22px; }
.header-phone { font-weight: 700; font-size: 17px; color: var(--white); display: inline-flex; align-items: center; gap: 8px; }
.header-phone .phone-ico { color: var(--red); display: inline-flex; align-items: center; }
.header-phone .phone-ico svg { display: block; }

/* --------------------------------------------------------------------------
   Footer — black, logo + hours/email/social left, link columns,
   location cards, legal bar
   -------------------------------------------------------------------------- */
.site-footer { background: var(--ink); color: var(--body-on-dark); padding-top: 70px; }
/* Footer call to action (2026-09-30): a charcoal panel with a red top rule,
   headline left, the two actions right. Sits above the link columns on every
   page. Phones stack it and stretch the buttons full width. */
.footer-cta {
  display: grid; grid-template-columns: minmax(0, 1.4fr) auto; gap: 32px 48px; align-items: center;
  margin-bottom: 64px; padding: 44px 48px;
  background: #232323; border-top: 4px solid var(--red);
}
.footer-cta .eyebrow { margin-bottom: 10px; }
.footer-cta h2 { font-size: clamp(30px, 3.4vw, 46px); line-height: 1.02; color: var(--white); }
.footer-cta p { margin-top: 12px; max-width: 560px; font-size: 16px; }
.footer-cta__actions { display: flex; flex-direction: column; gap: 12px; min-width: 240px; }
.footer-cta__actions .btn { text-align: center; }
/* Red truck cutout in the panel (owner, 2026-10-02). The "shadow outline" is
   drawn in CSS so it follows the cutout's edge: a thin light rim, then a soft
   drop shadow underneath. It rides a little above the panel's top edge. */
.footer-cta--truck { grid-template-columns: minmax(0, 1.25fr) minmax(0, 300px) auto; gap: 32px 36px; }
.footer-cta__truck {
  display: block; width: 100%; height: auto; margin: -78px 0 -22px;
  filter: drop-shadow(0 0 1px rgba(255,255,255,.9)) drop-shadow(0 0 1px rgba(255,255,255,.9)) drop-shadow(0 22px 18px rgba(0,0,0,.6));
}
@media (max-width: 1150px) {
  .footer-cta--truck { grid-template-columns: minmax(0, 1.4fr) auto; }
  .footer-cta__truck { display: none; }
}
@media (max-width: 760px) {
  .footer-cta--truck { grid-template-columns: 1fr; }
  .footer-cta__truck { display: block; order: -1; width: 230px; margin: -70px auto 0; }
}
@media (max-width: 760px) {
  .footer-cta { grid-template-columns: 1fr; padding: 32px 22px; margin-bottom: 48px; }
  .footer-cta__actions { min-width: 0; }
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.3fr repeat(4, minmax(120px, 1fr));
  gap: 36px;
}
/* 900-1000px: the four link columns could not shrink below their headings and
   pushed the page ~14px wider than the screen (sideways scroll on every page). */
@media (max-width: 1000px) {
  .footer-grid { grid-template-columns: 1.1fr repeat(4, minmax(0, 1fr)); gap: 22px; }
}
.footer-brand .logo { text-align: left; margin-bottom: 26px; }
.footer-meta { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; color: var(--white); font-weight: 600; }
.footer-meta .ico { color: var(--red); }
.footer-social { display: flex; gap: 10px; margin-top: 18px; }
.footer-social a {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--red); color: var(--white);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 14px;
  transition: background .16s ease, color .16s ease;
}
/* Real brand marks. They were "▶", "f" and "◎" — a play triangle, a letter and
   a circle glyph standing in for logos. Each is now the actual mark, flood-
   filled white through a CSS mask (the same technique used to recolour the
   brush assets), which keeps the red circle untouched and the markup to a
   single empty <a> per network. */
.footer-social a::before {
  content: '';
  width: 16px; height: 16px;
  background: currentColor;
  -webkit-mask: no-repeat center / contain;
  mask: no-repeat center / contain;
}
/* Selectors are qualified with .footer-social a so they outrank the shorthand
   above — `-webkit-mask: no-repeat center / contain` resets mask-image to none,
   and the unqualified `.social--x::before` was the lower-specificity rule, so
   the icons silently rendered as empty squares. */
.footer-social a.social--youtube::before {
  -webkit-mask-image: url('../img/social/youtube.svg');
  mask-image: url('../img/social/youtube.svg');
}
.footer-social a.social--facebook::before {
  -webkit-mask-image: url('../img/social/facebook.svg');
  mask-image: url('../img/social/facebook.svg');
}
.footer-social a.social--instagram::before {
  -webkit-mask-image: url('../img/social/instagram.svg');
  mask-image: url('../img/social/instagram.svg');
}
.footer-social a:hover { background: var(--white); color: var(--red); }
.footer-col h4 { color: var(--white); font-size: 17px; font-weight: 700; margin-bottom: 16px; }
.footer-col li { margin-bottom: 10px; font-size: 14.5px; }
.footer-col a:hover { color: var(--white); }

.footer-locations {
  display: grid; grid-template-columns: 1fr 1fr; gap: 28px;
  margin: 48px 0 56px;
}
.loc-card { background: var(--off-white); text-align: center; padding: 26px 20px; position: relative; }
.loc-card .loc-tag {
  position: absolute; top: -14px; left: 50%; transform: translateX(-50%);
  background: var(--red); color: var(--white);
  font-size: 13px; font-weight: 600; padding: 4px 16px;
}
.loc-card h5 { color: var(--maroon); letter-spacing: .12em; font-size: 16px; text-transform: uppercase; margin-bottom: 8px; }
.loc-card .loc-addr { color: var(--ink-3); font-size: 15px; }
.loc-card .loc-phone { color: var(--red); font-weight: 700; margin-top: 6px; }

.footer-legal {
  border-top: 1px solid #2c2c2c;
  padding: 20px 0;
  font-size: 13px;
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  color: #9a9a9a;
}

/* --------------------------------------------------------------------------
   Shared section patterns
   -------------------------------------------------------------------------- */
.section { padding: 90px 0; }
.section--dark { background: var(--ink); color: var(--body-on-dark); }
.section--red { background: var(--red-dark); color: var(--white); }
.section--light { background: var(--off-white); }
.section-head-center { text-align: center; max-width: 760px; margin: 0 auto 48px; }

/* Core values type wall — shared, because the seven values appear on both About
   and Careers and must look identical in each. Promoted out of about.html's
   page styles when Careers picked it up.
   Charcoal by default for light sections; white inside a red band. */
.values-wall {
  max-width: 1120px; margin: 0 auto;
  text-align: center;
  list-style: none;
}
.values-wall li {
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  color: var(--ink);
  /* Ceiling sized so the longest value, SET THE STANDARD, still sets on one
     line at container width; floor at 22px so it cannot force a 360px viewport
     to scroll sideways. Both measured, not estimated. */
  font-size: clamp(22px, 5.9vw, 84px);
  line-height: 1.04;
  letter-spacing: -0.005em;
}
.section--red .values-wall li { color: var(--white); }

/* Values tree (About, Careers): Faith is the root, the six others sit inside a
   ruled frame hung from it by a stem. Same display face as the wall; the
   nested lines step down so the frame fits the container at 84px root. */
.values-tree { text-align: center; color: var(--ink); }
.section--red .values-tree { color: var(--white); }
.values-root {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  color: inherit; font-size: clamp(40px, 8.4vw, 120px); line-height: 1; letter-spacing: -0.005em;
}
.values-stem { width: 3px; height: 54px; background: currentColor; margin: 10px auto 0; opacity: .9; }
.values-nested {
  display: inline-block; max-width: none;
  border: 3px solid currentColor; padding: 30px clamp(20px, 5vw, 70px) 34px;
}
.values-nested li { font-size: clamp(18px, 4.3vw, 60px); line-height: 1.12; }
@media (max-width: 600px) {
  .values-stem { height: 34px; }
  .values-nested { border-width: 2px; padding: 18px 16px 20px; }
}

/* Image placeholder blocks — swap for real photography */
.ph {
  background: linear-gradient(135deg, #3a3a3a, #222);
  color: #bbb; display: flex; align-items: center; justify-content: center;
  font-size: 13px; letter-spacing: .08em; text-transform: uppercase; text-align: center;
  min-height: 220px;
}
.ph--light { background: linear-gradient(135deg, #d8d8d8, #c2c2c2); color: #666; }

/* Video card with play button */
.video-card { position: relative; box-shadow: 0 18px 50px rgba(0,0,0,.28); }
/* A still photo in a video-card slot (most slots since 2026-09-28) fills the card. */
.video-card img { display: block; width: 100%; height: auto; }
.video-card--live video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; background: var(--ink); }
.video-card .play {
  position: absolute; inset: 0; margin: auto;
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--red); color: var(--white);
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; padding-left: 4px;
}

/* YouTube click-to-play facade.
   Nothing from YouTube loads until someone actually presses play: the poster is
   our own webp served from our own domain, and the iframe is only created on
   click. A bare <iframe> here would pull roughly half a megabyte of player and
   set third-party cookies on every visit to the page, for a video most visitors
   never start. */
.video-embed { position: relative; aspect-ratio: 16 / 9; background: var(--ink-2); overflow: hidden; }
.video-embed .ve-play {
  position: absolute; inset: 0;
  width: 100%; height: 100%; padding: 0;
  border: 0; background: none; cursor: pointer; display: block;
}
.video-embed img { display: block; width: 100%; height: 100%; object-fit: cover; }
.video-embed .play { pointer-events: none; transition: transform .18s ease, background .18s ease; }
.video-embed .ve-play:hover .play { transform: scale(1.08); background: var(--red-dark); }
.video-embed .ve-play:focus-visible { outline: 3px solid var(--red); outline-offset: 3px; }
.video-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* Caption under each, so a pair reads as Part 1 / Part 2 rather than two
   unrelated clips. */
.video-caption {
  margin: 12px 0 0; font-size: 14.5px; font-weight: 600;
  color: var(--body-on-dark); text-align: left;
}
.video-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 26px; }
@media (max-width: 760px) { .video-pair { grid-template-columns: 1fr; } }

/* Service cards (Residential / Commercial on red band).
   White cards sit inside dark/red sections that set body text to a light
   color — reset it here or the copy renders light-on-white. */
.svc-card { background: var(--white); padding: 20px 20px 28px; color: var(--body-on-white); }
.section--red .svc-card p,
.section--dark .svc-card p { color: var(--body-on-white); }
.section--dark .tab-panel,
.section--red .tab-panel { color: var(--body-on-white); }
/* Card photo. The placeholder it replaces was a fixed 230px-tall box, which at
   full width on a phone would letterbox a 16:9 shot into a strip; aspect-ratio
   keeps the framing intact at every width and holds the row height steady while
   the image loads. */
.svc-card .svc-photo { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
/* Photo is a link to the service landing page. Hover/focus dims it, nudges the
   photo, and reveals a button; touch devices (no hover) show a lighter dim and
   the button always so the affordance isn't hidden behind a gesture they can't
   make. Card links stay real <a>s for keyboard and crawlers. */
.svc-photo-link { position: relative; display: block; overflow: hidden; text-decoration: none; }
.svc-photo-link .svc-photo { transition: transform .45s ease; }
.svc-photo-link::after {
  content: ''; position: absolute; inset: 0;
  background: rgba(18, 18, 18, 0); transition: background-color .3s ease;
}
.svc-photo-cta {
  position: absolute; inset: 0; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transform: translateY(10px);
  transition: opacity .3s ease, transform .3s ease;
}
.svc-photo-link:hover::after,
.svc-photo-link:focus-visible::after { background: rgba(18, 18, 18, .55); }
.svc-photo-link:hover .svc-photo { transform: scale(1.04); }
.svc-photo-link:hover .svc-photo-cta,
.svc-photo-link:focus-visible .svc-photo-cta { opacity: 1; transform: none; }
.svc-photo-link:focus-visible { outline: 3px solid var(--red); outline-offset: 2px; }
@media (hover: none) {
  .svc-photo-link::after { background: rgba(18, 18, 18, .3); }
  .svc-photo-cta { opacity: 1; transform: none; }
}
/* Card titles now match the .display treatment the owner pointed at — the page
   hero on this very section's page ("GOOD ROOFING STARTS WITH RESPECT"): display
   face, 900, uppercase, the same 0.01em tracking. Colour moves from the softer
   --maroon to the bright --red.
   Size is a clamp rather than the old flat 26px. Zalando Expanded is a very wide
   face and uppercase at 900 is wider still, so the longest label — "TPO & PVC
   ROOFING MEMBRANE" — has to give ground on narrower cards instead of spilling
   out of one. */
.svc-card h3 {
  color: var(--red);
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  font-size: clamp(17px, 1.75vw, 23px);
  line-height: 1.12;
  margin: 18px 0 10px;
}
.chip-row { display: flex; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
/* Chips are links now, not decoration, so they need to look and behave like it:
   a hover state, a visible keyboard focus ring, and no underline. Padding is
   tightened from 18px to 14px because the real labels run to "TPO & PVC Roofing
   Membrane" — six of these per card at the old padding pushed the rows deeper
   than the card's photo. */
.chip {
  display: inline-block;
  background: var(--gray-200); color: #6b6b6b;
  font-size: 14px; font-weight: 600;
  padding: 6px 14px; border-radius: 999px;
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
a.chip:hover { background: var(--red); color: var(--white); }
a.chip:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

/* Brand logo strip: a slow, seamless horizontal marquee.
   Two copies of the logo set sit side by side in .brand-track; translating the
   track by exactly half its width and looping is what makes it seamless. Speed
   is set in seconds per loop, so the pace stays the same whatever the width.
   Grayscale keeps the mixed-colour originals reading as one set on the gray
   band; the dark band inverts them to light. */
.brand-strip { background: var(--gray-100); padding: 26px 0; overflow: hidden; }
.brand-marquee { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.brand-track {
  display: flex; align-items: center; gap: clamp(56px, 7vw, 120px); width: max-content;
  padding-right: clamp(56px, 7vw, 120px);
  filter: grayscale(1); opacity: .8;
  animation: brand-scroll 36s linear infinite;
}
.brand-marquee:hover .brand-track { animation-play-state: paused; }
@keyframes brand-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .brand-track { animation: none; } }
.brand-track img { height: 38px; width: auto; max-width: 240px; object-fit: contain; flex: none; }
.brand-track img.is-badge { height: 66px; }
.brand-track img.is-tall { height: 80px; }  /* the portrait BBB seal */
.brand-strip--dark { background: var(--ink-2); border-top: 1px solid #2c2c2c; border-bottom: 1px solid #2c2c2c; }
.brand-strip--dark .brand-track { filter: grayscale(1) invert(1); opacity: .85; }
@media (max-width: 700px) {
  .brand-track img { height: 28px; }
  .brand-track img.is-badge { height: 50px; }
  .brand-track img.is-tall { height: 60px; }
}


/* Big social links (About, Careers). Two full-width tiles; the brand colour
   sweeps in from the left on hover, the icon lifts, the arrow slides. */
.social-band-section { padding-top: 40px; }
.social-band { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.social-tile {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; align-items: center; gap: 22px;
  padding: 30px 30px; background: var(--ink); color: var(--white); text-decoration: none;
  border: 1px solid #2c2c2c;
  transition: transform .25s ease, box-shadow .25s ease;
}
.social-tile::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--tile, var(--red));
  transform: translateX(-101%); transition: transform .4s cubic-bezier(.2,.8,.2,1);
}
.social-tile--facebook { --tile: #1877f2; }
.social-tile--instagram { --tile: linear-gradient(45deg, #f58529, #dd2a7b 55%, #8134af); }
.social-tile:hover, .social-tile:focus-visible { transform: translateY(-4px); box-shadow: 0 18px 40px rgba(0,0,0,.28); outline: none; }
.social-tile:hover::before, .social-tile:focus-visible::before { transform: translateX(0); }
.social-tile__icon {
  flex: none; width: 64px; height: 64px; border-radius: 50%; background: var(--white);
  display: grid; place-items: center; transition: transform .3s ease;
}
.social-tile__icon::before { content: ''; width: 32px; height: 32px; background: var(--ink); -webkit-mask: no-repeat center / contain; mask: no-repeat center / contain; }
.social-tile--facebook .social-tile__icon::before { -webkit-mask-image: url('../img/social/facebook.svg'); mask-image: url('../img/social/facebook.svg'); }
.social-tile--instagram .social-tile__icon::before { -webkit-mask-image: url('../img/social/instagram.svg'); mask-image: url('../img/social/instagram.svg'); }
.social-tile:hover .social-tile__icon { transform: scale(1.08) rotate(-6deg); }
.social-tile__text { display: flex; flex-direction: column; gap: 4px; }
.social-tile__text strong { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; font-size: clamp(17px, 1.6vw, 22px); line-height: 1.1; }
.social-tile__text span { font-size: 14.5px; color: #d9d9d9; }
.social-tile__arrow { margin-left: auto; font-size: 30px; line-height: 1; transition: transform .3s ease; }
.social-tile:hover .social-tile__arrow { transform: translateX(8px); }
@media (max-width: 900px) { .social-band { grid-template-columns: 1fr; } .social-tile { padding: 22px 20px; gap: 16px; } .social-tile__icon { width: 52px; height: 52px; } }

/* Split CTA band — red gradient, white copy left, photo right overlapping the
   band edges (service landing pages) */
.cta-split { background: linear-gradient(90deg, #7c1417, var(--red-dark) 55%, #c8474c); color: var(--white); position: relative; z-index: 1; padding: 64px 0; }
.cta-split .container { display: grid; grid-template-columns: 1.2fr 1fr; gap: 56px; align-items: center; }
.cta-split h2 { font-family: var(--font-sans); font-weight: 700; color: var(--white); font-size: clamp(28px, 3.2vw, 40px); line-height: 1.2; margin-bottom: 14px; }
.cta-split p { max-width: 560px; margin-bottom: 26px; }
.cta-split .photo { margin: -110px 0; box-shadow: 0 18px 50px rgba(0,0,0,.3); }
@media (max-width: 900px) {
  .cta-split .container { grid-template-columns: 1fr; }
  .cta-split .photo { margin: 0; }
}

/* Review cards */
.review-card { background: var(--white); border: 1px solid var(--gray-200); box-shadow: 0 10px 30px rgba(0,0,0,.07); padding: 22px; color: var(--body-on-white); }
/* The cards sit on dark sections, whose light body gray they inherited; the
   review copy reads in the on-white gray and the reviewer name in ink. */
.review-card p { color: var(--body-on-white); }
.review-card .review-head strong { color: var(--ink); }
.review-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.review-head .avatar { width: 40px; height: 40px; border-radius: 50%; background: #ccc; }
.review-head .g { margin-left: auto; font-weight: 700; color: #4285f4; }
.stars { color: #f5b400; letter-spacing: 2px; font-size: 14px; }
.review-card .read-more { color: var(--red); font-size: 13px; font-weight: 600; }
/* Posted date under the stars on the live review strips */
.review-card .rc-date { display: block; margin-top: 4px; font-size: 12.5px; color: #6b6b6b; }
.carousel-dots { display: flex; gap: 10px; justify-content: center; margin-top: 28px; }
.carousel-dots span { width: 9px; height: 9px; border-radius: 50%; background: #d2d2d2; }
.carousel-dots span.active { background: var(--red); }
/* Dots are buttons once the carousel is wired, so they need the same look
   without the UA button chrome. */
.carousel-dots button {
  width: 9px; height: 9px; border-radius: 50%; padding: 0;
  border: 0; background: #d2d2d2; cursor: pointer;
  transition: background .16s ease, transform .16s ease;
}
.carousel-dots button.active { background: var(--red); transform: scale(1.25); }
.carousel-dots button:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }

/* Review carousel — the prototype drew dots under a static three-card grid,
   promising a scroll that did not exist. Horizontal scroller with snap points,
   arrows, and dots generated from the real card count. */
.review-carousel { position: relative; }
.rc-track {
  display: grid;
  grid-auto-flow: column;
  /* Three cards across, matching the .grid-3 the dots were drawn under.
     A fixed track size, NOT minmax(0, …): with a zero minimum the grid shrinks
     every track to fit the container, so four cards squeezed into the width and
     there was nothing left to scroll. */
  grid-auto-columns: calc((100% - 52px) / 3);
  gap: 26px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Native scrollbar hidden: the arrows and dots are the affordance, and a bar
     under a dark band looks like a rendering fault. Keyboard scrolling still
     works because the track is focusable. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.rc-track::-webkit-scrollbar { display: none; }
.rc-track > * { scroll-snap-align: start; }
.rc-track:focus-visible { outline: 2px solid var(--red); outline-offset: 4px; }
.rc-btn {
  position: absolute; top: 50%; transform: translateY(-50%);
  z-index: 2;
  width: 44px; height: 44px; padding: 0;
  border: 0; cursor: pointer;
  background: var(--red); color: var(--white);
  font-size: 24px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  transition: background .16s ease, color .16s ease, opacity .16s ease;
}
.rc-btn:hover { background: var(--white); color: var(--red); }
.rc-btn:focus-visible { outline: 2px solid var(--white); outline-offset: 2px; }
/* The hover and focus ring above both resolve to white, which works on the dark
   band this carousel was built for and disappears on the homepage's white one.
   --light swaps them for the same treatment against a light background. */
.review-carousel--light .rc-btn:hover { background: var(--ink); color: var(--white); }
.review-carousel--light .rc-btn:focus-visible { outline-color: var(--red); }
.rc-btn[disabled] { opacity: .3; cursor: default; }
.rc-btn[disabled]:hover { background: var(--red); color: var(--white); }
.rc-prev { left: -22px; }
.rc-next { right: -22px; }
@media (max-width: 1240px) {
  /* Inside the container once there is no room to sit outside it. */
  .rc-prev { left: 6px; }
  .rc-next { right: 6px; }
}
@media (max-width: 900px) {
  .rc-track { grid-auto-columns: calc((100% - 26px) / 2); }
}
@media (max-width: 640px) {
  .rc-track { grid-auto-columns: 100%; }
}

/* FAQ accordion */
.faq-item { background: var(--off-white); margin-bottom: 22px; }
/* Light variant — Thank You / 404 show the same accordion on a WHITE section:
   dark heading + red scribble, outline-red "See All FAQs", dark answer copy,
   outline-dark "Watch Video". Wrap the section in .faq-light. */
.faq-light .faq-a { color: var(--body-on-white); }
.faq-q {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 14px 18px 22px;
  color: var(--ink); font-weight: 700; font-size: 17px;
  /* Now a real <button> rather than a div, so the accordion is keyboard
     operable and announces its state. Reset the UA styling so it still renders
     as the design's full-width bar. */
  width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; font-family: inherit; line-height: 1.35;
}
.faq-q:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
.faq-toggle {
  width: 34px; height: 34px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--ink); color: var(--white); font-size: 20px; font-weight: 400;
}
.faq-item.open .faq-toggle { background: var(--red); }
/* The open answer hangs off its question bar as one card: pulled up over the
   item's bottom margin, same width, its own tinted ground and even padding. */
.faq-a { margin: -22px 0 22px; padding: 20px 22px 22px; background: rgba(255,255,255,.06); color: var(--body-on-dark); }
.faq-a p { margin: 0; }
.faq-a p + p { margin-top: 12px; }
.faq-light .faq-a { background: var(--off-white); border-top: 1px solid var(--gray-200); }

/* Section head row — heading block left, button right (Our Services,
   The Titan Journal…). Previously defined only in index.html's local styles;
   promoted here because interior pages reuse it. */
.our-services-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 40px; }
/* On phones the heading block and its "See All …" button stack and centre,
   per the mobile spec; side by side the button ran past the right edge. */
@media (max-width: 900px) { .our-services-head { flex-direction: column; align-items: center; text-align: center; gap: 18px; margin-bottom: 28px; } }

/* Article cards */
.article-card { background: var(--white); padding: 18px 18px 26px; }
/* Card photo: every thumbnail crops to the same 16:9 tile whatever the source shape. */
.article-card .article-photo { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.article-meta { color: var(--red); font-size: 13.5px; font-weight: 600; margin: 14px 0 8px; display: flex; gap: 8px; }
.article-card h3 { color: var(--ink); font-size: 19px; font-weight: 700; line-height: 1.35; margin-bottom: 8px; }
.article-card p { font-size: 14.5px; color: #7a7a7a; }

/* Interior-page hero banner — red-tinted photo, left-aligned display title,
   black grunge streak along the bottom edge (Meet The Team, service pages…) */
.page-hero {
  position: relative;
  background: linear-gradient(rgba(183,31,37,.82), rgba(183,31,37,.82)), #5a1114;
  color: var(--white);
  padding: 70px 0 90px;
}
.page-hero h1 { font-size: clamp(36px, 4.6vw, 60px); max-width: 640px; }
/* Service pages: the H1 carries the search phrase on three short lines, so it
   runs a step smaller than the generic page hero and is not width-capped. */
.svc-hero h1 { max-width: none; font-size: clamp(34px, 4.2vw, 58px); text-wrap: balance; }
/* Phones: the desktop line breaks split single words at 34px, so let the
   headline wrap on its own and balance the lines. */
@media (max-width: 640px) { .svc-hero h1 br { display: none; } }
/* With the lead form beside it the copy column is ~620px and the expanded
   display face runs ~0.9em per capital, so a search headline wraps naturally
   at a smaller size instead of forcing breaks that split single words. */
.svc-hero .container:has(.hero-form) h1 { font-size: clamp(30px, 3.1vw, 44px); text-wrap: balance; }
.page-hero .hero-photo {
  position: absolute; inset: 0;
  opacity: .35; mix-blend-mode: multiply;
}

/* Team member cards (Meet The Team) — white card, light photo, name + red role */
.team-heading {
  font-family: var(--font-sans); font-weight: 700; color: var(--ink);
  font-size: clamp(30px, 3.4vw, 44px); text-align: center;
  margin: 70px 0 44px;
}
/* Flex, not grid: a row with fewer cards than columns centres instead of
   leaving a hole on the right. Card width is fixed per variant so rows of
   different lengths still line up with each other. */
.team-grid { display: flex !important; flex-wrap: wrap; justify-content: center; gap: 26px; }
.team-grid > .team-card { flex: 0 0 250px; max-width: 100%; }
.team-grid--3 > .team-card { flex-basis: 300px; }
.team-card {
  background: var(--white);
  border: 1px solid #ececec;
  box-shadow: 0 8px 26px rgba(0,0,0,.06);
  padding: 20px 20px 24px;
  text-align: center;
}
.team-card .ph, .team-card .ph--light { min-height: 240px; }
.team-card--lg .ph, .team-card--lg .ph--light { min-height: 290px; }
.team-card h3 {
  font-family: var(--font-sans); font-weight: 700; color: var(--ink);
  font-size: 22px; margin-top: 18px;
}
.team-card--lg h3 { font-size: 26px; }
.team-card .role {
  color: var(--red); font-weight: 600; font-size: 13.5px; margin-top: 4px;
  /* Every role is set in caps. The prototype applied this to the large cards
     only, which left the smaller cards in title case on the same page.
     Tracking is .08em rather than .12em: caps need some, but the longer titles
     ("COMMERCIAL PROJECT MANAGER", "AI DEVELOPMENT ENGINEER") overflow their
     card and wrap to two lines at .1em — the first by a fraction of a pixel. */
  text-transform: uppercase; letter-spacing: .08em;
}
.team-card--lg .role { letter-spacing: .12em; font-size: 14px; }
/* Hover state in the prototype: red-tinted photo overlay + expand icon */
.team-card:hover .ph, .team-card:hover .ph--light {
  background: linear-gradient(rgba(190,32,38,.55), rgba(190,32,38,.55)), #888;
}

/* Real team portraits — assets/img/team/, built by scripts/build-team-photos.mjs.
   Occupies the same box as the .ph placeholder and repeats its hover treatment,
   so a card looks and behaves identically whether that person's photo has
   arrived yet or not (most of the team is still on placeholders). */
.team-photo { position: relative; overflow: hidden; background: var(--off-white); }
.team-photo img {
  display: block; width: 100%; height: auto; aspect-ratio: 260 / 290;
  object-fit: cover; object-position: center top;
}
/* Phones: two portraits per row at the photo's own 260x290 proportion. The
   old fixed 240px/290px heights stretched a full-width card's photo wider
   than tall and cropped into the person (owner, 2026-10-06). */
@media (max-width: 700px) {
  .team-grid { gap: 14px; }
  .team-grid > .team-card, .team-grid--3 > .team-card { flex: 1 1 calc(50% - 7px); max-width: calc(50% - 7px); padding: 12px 12px 16px; }
  .team-card h3, .team-card--lg h3 { font-size: 18px; margin-top: 12px; }
  .team-card .role, .team-card--lg .role { font-size: 12px; letter-spacing: .08em; }
}
.team-photo::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(rgba(190,32,38,.55), rgba(190,32,38,.55));
  opacity: 0; transition: opacity .18s ease;
}
.team-card:hover .team-photo::after { opacity: 1; }

/* Pre-footer CTA heading. Held on one line — at a fixed 46px it wrapped as
   "TRUST IN TITAN / TODAY", breaking the phrase in the wrong place. nowrap
   keeps it whole and the clamp shrinks it before it can overflow the column,
   which is narrowest between the 900px and 1240px marks where the banner is
   still two columns. */
.cta-banner .cta-title {
  font-size: clamp(20px, 3.4vw, 46px);
  white-space: nowrap;
}

/* Pre-footer CTA banner + founder quote (shared by most pages) */
.cta-banner {
  background: linear-gradient(rgba(190,32,38,.85), rgba(190,32,38,.85)), #6b1a1d;
  color: var(--white);
  padding: 90px 0;
}
.cta-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 60px; align-items: center; }
.founder-quote { display: flex; align-items: center; gap: 14px; margin: 26px 0 30px; }
.founder-quote .avatar { width: 52px; height: 52px; border-radius: 50%; background: #ddd; flex: none; overflow: hidden; }
.founder-quote .avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Free-estimate widget — the card in the pre-footer band on 15 pages.
   Black with red and white, matching the Meet The Team hero rather than the
   prototype's white card. The rating strip is gone: three logos and a row of
   small grey stars under a call to action cluttered the one thing the card is
   there to do. */
.lead-form {
  background: var(--ink);
  color: var(--white);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .45);
}
.lead-form .steps {
  background: #191919;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  padding: 18px 26px;
  display: flex; align-items: center; gap: 10px;
}
/* Was "▣ → ▢ → ▢" in text glyphs. Drawn now, so it scales cleanly and the
   current step actually reads as current. */
.lead-form .step-dot {
  width: 10px; height: 10px; border-radius: 50%; flex: none;
  background: rgba(255, 255, 255, .22);
}
.lead-form .step-dot.is-current {
  background: var(--red);
  box-shadow: 0 0 0 4px rgba(224, 31, 38, .22);
}
.lead-form .step-line { flex: 1; height: 1px; background: rgba(255, 255, 255, .16); }
.lead-form .body { padding: 32px 34px 34px; text-align: center; }
.lead-form h3 {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  color: var(--white);
  font-size: clamp(19px, 2vw, 25px); line-height: 1.15;
  margin-bottom: 10px;
}
.lead-form .sub { color: #9d9d9d; font-size: 15px; margin-bottom: 22px; }
.svc-pick { display: flex; gap: 16px; justify-content: center; margin-bottom: 24px; }
/* Base (light) buttons stay for the contact page's wizard, which sits on a
   white panel and reuses .svc-pick. */
.svc-pick button {
  width: 128px; padding: 18px 10px 12px; border: 1px solid var(--gray-200);
  background: var(--off-white); font-family: var(--font-sans); font-size: 14px; cursor: pointer;
}
/* Dark variant, scoped to this widget only. */
.lead-form .svc-pick button {
  width: 142px; padding: 15px 10px;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, .22);
  color: var(--white);
  font-size: 14.5px; font-weight: 600;
  transition: border-color .16s ease, background .16s ease;
}
.lead-form .svc-pick button:hover { border-color: rgba(255, 255, 255, .55); }
.lead-form .svc-pick button.is-selected {
  border-color: var(--red);
  background: rgba(224, 31, 38, .16);
}
.lead-form .svc-pick button:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
.lead-form .lf-error {
  color: var(--red); font-size: 13px; font-weight: 600; margin: -8px 0 14px;
}
/* Below ~480px two fixed-width options plus the card padding demand more than
   the viewport, and the whole page scrolls sideways. Let them share the space
   instead. (The 128px original was already close to the edge; widening them to
   142px is what tipped it over.) */
@media (max-width: 520px) {
  .lead-form .body { padding: 28px 18px 30px; }
  .lead-form .steps { padding: 16px 18px; }
  .lead-form .svc-pick { gap: 12px; }
  .lead-form .svc-pick button { width: auto; flex: 1 1 0; min-width: 0; }
}

/* Utility layout */
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 26px; }

/* --------------------------------------------------------------------------
   Mobile nav — hamburger + full-screen panel, and the sticky bottom call bar.
   The prototype specifies both but never showed the open menu state, so the
   panel is a conventional slide-down built from the real nav structure.
   -------------------------------------------------------------------------- */
.nav-toggle {
  display: none;
  width: 42px; height: 42px;
  background: none; border: 0; padding: 0;
  cursor: pointer;
  flex-direction: column; justify-content: center; gap: 5px;
}
.nav-toggle span {
  display: block; height: 3px; width: 26px;
  background: var(--red);
  transition: transform .2s ease, opacity .2s ease;
}
.mobile-call-bar { display: none; }

@media (max-width: 900px) {
  /* These layouts are CSS grids, so flex-basis alone never collapsed them:
     on a phone the footer's five columns and every two-column section stayed
     side by side, the page ran 915px wide and mobile browsers zoomed the
     whole site out to fit. One column each below 900px. */
  .two-col, .grid-3, .grid-2, .footer-grid, .footer-locations, .cta-grid { grid-template-columns: 1fr; }
  .team-grid > .team-card, .team-grid--3 > .team-card { flex-basis: 100%; }

  /* Header: hamburger left, logo center, CTA hidden (it lives in the call bar) */
  /* Equal side columns so the logo sits dead centre; the right side is a
     phone icon only (the number itself lives in the call bar), which keeps
     the two sides narrow enough for a bigger logo (owner, 2026-10-08). */
  .site-header .container { grid-template-columns: 1fr auto 1fr; gap: 12px; }
  .nav-toggle { display: flex; justify-self: start; }
  .header-right { justify-self: end; }
  .header-right .btn { display: none; }
  .header-phone { font-size: 0; }
  .header-phone span.phone-ico { display: inline-flex; font-size: 24px; }
  .site-header .logo img { height: 50px; }
  /* iOS Safari counts the closed off-canvas menu (parked one screen to the
     left) into the page width and lets the whole page drag sideways. Hide it
     while closed and clip the page to the viewport as a backstop. */
  html, body { overflow-x: hidden; overflow-x: clip; }
  /* Menu open: body pinned at its scroll position (see site.js setOpen), the
     header bar stays put so the close button is reachable. */
  body.nav-locked { position: fixed; left: 0; right: 0; width: 100%; overflow: hidden; }
  body.nav-locked .site-header { position: fixed; top: 0; left: 0; right: 0; }

  .nav-open .nav-toggle span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
  .nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
  .nav-open .nav-toggle span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

  /* Slide-down panel */
  .nav {
    position: fixed;
    top: var(--header-h); left: 0; right: 0; bottom: 0;
    display: flex;
    flex-direction: column;
    gap: 0;
    background: var(--ink);
    padding: 10px 0 90px;
    overflow-y: auto;
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform .22s ease, visibility 0s linear .22s;
    z-index: 90;
  }
  .nav-open .nav { transform: translateX(0); visibility: visible; transition: transform .22s ease, visibility 0s; }
  .nav > li { border-bottom: 1px solid rgba(255,255,255,.08); }
  .nav > li > a {
    display: flex; width: 100%;
    justify-content: space-between;
    padding: 16px 24px;
    font-size: 17px;
    font-weight: 600;
  }
  .nav .caret { font-size: 12px; padding: 14px 20px 14px 22px; margin: -14px -24px -14px 0; border-left: 1px solid rgba(255,255,255,.1); }

  /* Submenus become inline accordions */
  .nav .submenu {
    position: static;
    opacity: 1; visibility: visible; transform: none;
    display: none;
    min-width: 0;
    background: #0b0b0b;
    border-top: 0;
    box-shadow: none;
    padding: 4px 0 10px;
  }
  .nav > li.open .submenu { display: block; }
  .nav > li.open .caret { transform: rotate(180deg); }
  .nav .submenu a { padding: 12px 34px; font-size: 15px; }
  .nav > li.has-submenu::after { content: none; }

  /* Sticky bottom call bar (mobile-only, per the design's mobile spec) */
  .mobile-call-bar {
    display: grid;
    grid-template-columns: 1fr 1fr;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    background: var(--white);
    box-shadow: 0 -6px 20px rgba(0,0,0,.18);
    z-index: 130;
    /* Sit above the phone's home indicator / browser bottom bar. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .mobile-call-bar a {
    padding: 15px 10px;
    text-align: center;
    font-weight: 700;
    font-size: 15.5px;
    color: var(--ink);
  }
  .mobile-call-bar a + a { background: var(--red); color: var(--white); }
  body { padding-bottom: calc(54px + env(safe-area-inset-bottom, 0px)); }
}

/* Visually hidden but read by search engines and screen readers */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

/* Service area map: <picture> with a phone crop; width/height attributes reserve space, so keep the ratio. */
.service-map { height: auto; max-width: 100%; display: block; }

/* Breadcrumb trail at the top of service and city heroes (red ground). */
.crumbs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: #f3d9da; }
.crumbs a { color: #f3d9da; }
.crumbs a:hover { color: var(--white); }
.crumbs span { color: var(--white); }

/* Phones and tablets (owner, 2026-10-08): the hero stacks copy over the form,
   so the form is a screen or two down. Breadcrumbs go (three uppercase links
   above the headline were the first thing on screen), the hero loses its
   desktop top padding, and a small arrow link right under the headline jumps
   to the form. The link never shows on desktop, where the form is beside
   the copy. The breadcrumb markup stays for search engines. */
.hero-cta-mobile { display: none; }
#quote-form { scroll-margin-top: 90px; }
@media (max-width: 900px) {
  .crumbs { display: none; }
  .page-hero.svc-hero { padding-top: 34px; }
  .svc-hero .container { gap: 34px; }
  .svc-hero .eyebrow { margin-bottom: 10px; }
  .hero-points { gap: 10px; margin-top: 14px; }
  .hero-points li { font-size: 15.5px; }
  /* The button comes right after the headline, above the paragraph, so it is
     on screen the moment the page loads on any phone. */
  .svc-hero .container > div:first-child { display: flex; flex-direction: column; }
  .svc-hero .container > div:first-child > .eyebrow { order: 0; }
  .svc-hero .container > div:first-child > h1 { order: 1; }
  .svc-hero .container > div:first-child > .hero-cta-mobile { order: 2; }
  .svc-hero .container > div:first-child > p { order: 3; }
  .svc-hero .container > div:first-child > .hero-points { order: 4; }
  /* A stamped tag, not a bar: a dashed capsule with a hatched offset shadow
     behind it, a solid white ring holding a red down arrow, then short
     uppercase text. Sits flush left between the headline and the intro with
     the same breathing room on both sides. The arrow bobs gently so it reads
     as "down there", and holds still for people who turn motion off. */
  .hero-cta-mobile { position: relative; isolation: isolate; display: inline-flex; align-items: center; gap: 14px; align-self: flex-start; margin: 22px 0 24px; padding: 7px 22px 7px 7px; border: 1.5px dashed rgba(255,255,255,.8); border-radius: 999px; background: #8f1a20; color: var(--white); text-decoration: none; -webkit-tap-highlight-color: transparent; transition: transform .15s; }
  .hero-cta-mobile::before { content: ""; position: absolute; inset: 0; border-radius: inherit; transform: translate(6px, 6px); background: repeating-linear-gradient(-45deg, rgba(255,255,255,.55) 0 1.5px, transparent 1.5px 6px); z-index: -1; }
  .hero-cta-mobile::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: #8f1a20; z-index: -1; }
  .hero-cta-mobile__ring { flex: 0 0 auto; width: 42px; height: 42px; border-radius: 50%; background: var(--white); color: var(--red); display: grid; place-items: center; box-shadow: 0 4px 12px rgba(0,0,0,.25); }
  .hero-cta-mobile__ring svg { width: 20px; height: 20px; animation: hero-cta-bob 1.8s ease-in-out infinite; }
  .hero-cta-mobile__text { font-size: 14px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; line-height: 1.2; white-space: nowrap; }
  .hero-cta-mobile:active { transform: translate(3px, 3px); }
  .hero-cta-mobile:active::before { transform: translate(3px, 3px); }
  .svc-hero .container > div:first-child > p { margin-top: 0; }
  @keyframes hero-cta-bob { 0%, 100% { transform: translateY(-2px); } 50% { transform: translateY(2px); } }
  @media (prefers-reduced-motion: reduce) { .hero-cta-mobile__ring svg { animation: none; } }
}

/* Related services + areas served (service pages, above the FAQ). */
.related-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); gap: 56px; align-items: start; }
.related-grid .title { margin-top: 6px; }
.related-grid p { margin: 14px 0 0; }
.related-list { display: grid; gap: 10px; margin-top: 22px; }
.related-list a { color: var(--ink); font-weight: 700; font-size: 17px; }
.related-list a:hover { color: var(--red); }
.area-list { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px 20px; margin: 22px 0 26px; }
.area-list a { color: var(--body-on-white); font-weight: 600; }
.area-list a:hover { color: var(--red); }
@media (max-width: 900px) { .related-grid { grid-template-columns: 1fr; gap: 40px; } .area-list { grid-template-columns: repeat(2, 1fr); } }

/* ---------- Guide: written content blocks (heading left, prose right) ----------
   Longer copy for search, set as a reading column so it does not turn into a
   wall of text. One block per topic, hairline between blocks. */
.guide { display: flex; flex-direction: column; }
.guide-block { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.7fr); gap: 56px; align-items: start; padding: 44px 0; border-top: 1px solid var(--gray-200); }
.guide-block:first-child { border-top: 0; padding-top: 0; }
.guide-block:last-child { padding-bottom: 0; }
.guide-head .title { margin-top: 6px; font-size: clamp(22px, 2.1vw, 30px); line-height: 1.15; text-wrap: balance; }
.guide-body p { margin: 0 0 16px; max-width: 68ch; font-size: 17px; line-height: 1.7; }
.guide-body > :last-child { margin-bottom: 0; }
.guide-points { list-style: none; margin: 22px 0 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.guide-points li { background: var(--white); border: 1px solid var(--gray-200); padding: 16px 18px; font-size: 15px; line-height: 1.55; color: var(--body-on-white); }
.guide-points li:last-child:nth-child(odd) { grid-column: 1 / -1; }
.guide-points strong { display: block; margin-bottom: 4px; color: var(--ink); font-size: 16px; }
@media (max-width: 900px) {
  .guide-block { grid-template-columns: 1fr; gap: 18px; padding: 34px 0; }
  .guide-points { grid-template-columns: 1fr; }
}

/* Guide blocks with a photo (homepage, 2026-10-01, owner: "two-column content
   that alternates"): photo on one side, heading and copy on the other, sides
   swapping row to row. Blocks without a photo keep the heading | copy layout. */
.guide-block--photo { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 64px; align-items: center; padding: 56px 0; border-top: 0; }
.guide-block--photo:nth-child(even) .guide-photo { order: 2; }
.guide-photo { margin: 0; box-shadow: 0 18px 50px rgba(0,0,0,.18); }
.guide-photo img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }
.guide-block--photo .guide-head { margin-bottom: 18px; }
.guide-block--photo .guide-head .title { font-size: clamp(26px, 2.6vw, 36px); }
.guide-block--photo .guide-body p { font-size: 16.5px; }
.guide-block--photo .guide-points { grid-template-columns: 1fr; gap: 10px; }
.guide-block--photo .guide-points li:last-child:nth-child(odd) { grid-column: auto; }
@media (max-width: 900px) {
  .guide-block--photo { grid-template-columns: 1fr; gap: 22px; padding: 34px 0; }
  .guide-block--photo:nth-child(even) .guide-photo { order: 0; }
}

/* FAQ in two columns: heading, blurb and button on the left (sticks while the
   list scrolls), questions on the right. Same pattern as the Pricing page. */
.faq-split { display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); gap: 56px; align-items: start; }
.faq-split__head { position: sticky; top: 110px; }
.faq-split__head p { margin: 14px 0 22px; }
.faq-split__list > .faq-item:first-child { margin-top: 0; }
@media (max-width: 960px) {
  .faq-split { grid-template-columns: 1fr; gap: 28px; }
  .faq-split__head { position: static; }
}

/* Photo band ("full-width-content", copy over the right third of a photo) on
   phones: there is no quiet third to put copy on, so the photo becomes a
   plain image on top and the copy sits below it on the dark ground. The
   selectors carry an element name to outrank each page's inline rules
   (owner, 2026-10-08: text over the roofer photo was hard to read). */
@media (max-width: 900px) {
  section.full-width-content { padding: 0; background: var(--ink); }
  section.full-width-content .bg { position: static; }
  section.full-width-content .bg::after { content: none; }
  section.full-width-content .bg img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
  section.full-width-content .container { padding-top: 36px; padding-bottom: 46px; }
  section.full-width-content .fwc-copy { max-width: none; margin-left: 0; }
}

/* ---------- Service-area map with logo pins (Service Areas page + homepage) ----------
   Six Titan-mark pins, each a link; positions are percent coordinates for the
   desktop and phone crops (docs/seo/service-area-points.json). */
.area-map { position: relative; width: 100%; max-width: 1000px; margin: 30px auto 0; line-height: 0; }
.area-map .service-map { width: 100%; height: auto; display: block; }
.map-marker { position: absolute; left: var(--dx); top: var(--dy); width: 5.2%; transform: translate(-50%, -100%); display: block; text-decoration: none; color: var(--white); z-index: 2; }
.map-marker__logo { display: block; width: 100%; height: auto; filter: drop-shadow(0 3px 4px rgba(0,0,0,.6)); }
.map-marker__pill { position: absolute; top: 50%; left: 100%; transform: translateY(-50%); margin-left: 4px; white-space: nowrap; font-size: 14px; font-weight: 700; line-height: 1; padding: .5em 1em; border-radius: 999px; background: rgba(255,255,255,.22); border: 1px solid rgba(255,255,255,.5); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); }
.map-marker--left .map-marker__pill { left: auto; right: 100%; margin-left: 0; margin-right: 4px; }
.map-marker:hover, .map-marker:focus-visible { z-index: 5; outline: none; }
@media (min-width: 701px) {
  .map-marker { transition: transform .25s cubic-bezier(.34,1.56,.64,1); }
  .map-marker__pill { transition: background-color .18s ease, border-color .18s ease, transform .25s cubic-bezier(.34,1.56,.64,1), box-shadow .18s ease; }
  .map-marker__logo { transition: filter .18s ease; }
  /* Hover: the pin jumps up and grows, the pill goes red and swells, and a
     red ring radiates from the pin's foot (owner: make it obvious). */
  .map-marker::after { content: ''; position: absolute; left: 50%; bottom: 0; width: 14px; height: 14px; margin-left: -7px; margin-bottom: -7px; border-radius: 50%; border: 3px solid var(--red); opacity: 0; pointer-events: none; }
  .map-marker:hover, .map-marker:focus-visible { animation: marker-bob .9s ease-in-out infinite alternate; }
  .map-marker:hover .map-marker__pill, .map-marker:focus-visible .map-marker__pill { background: var(--red); border-color: var(--red); transform: translateY(-50%) scale(1.12); box-shadow: 0 6px 18px rgba(224,31,38,.55); }
  .map-marker:hover .map-marker__logo, .map-marker:focus-visible .map-marker__logo { filter: drop-shadow(0 0 14px rgba(224,31,38,1)) drop-shadow(0 6px 8px rgba(0,0,0,.6)); }
  .map-marker:hover::after, .map-marker:focus-visible::after { animation: marker-ring 1.2s ease-out infinite; }
  .map-marker:active { animation: none; transform: translate(-50%, -100%) scale(1.2) translateY(-4px); }
  @keyframes marker-bob { from { transform: translate(-50%, -100%) scale(1.35) translateY(-8px); } to { transform: translate(-50%, -100%) scale(1.35) translateY(-18px); } }
  @keyframes marker-ring { 0% { transform: scale(.6); opacity: .95; } 100% { transform: scale(5); opacity: 0; } }
}
@media (max-width: 700px) {
  .map-marker { left: var(--mx); top: var(--my); width: 8%; }
  .map-marker__pill { font-size: 10.5px; padding: .45em .75em; margin-left: 3px; }
  .map-marker--m-left .map-marker__pill { left: auto; right: 100%; margin-left: 0; margin-right: 3px; }
  .map-marker--m-right .map-marker__pill { left: 100%; right: auto; margin-right: 0; margin-left: 3px; }
}
.area-map--card { max-width: none; margin: 0; }
/* The homepage card is narrower than the Service Areas map, so its pins run smaller. */
.area-map--card .map-marker { width: 4.8%; }
.area-map--card .map-marker__pill { font-size: 12px; padding: .45em .85em; }

/* ---------- Phone heading sizes (last so they outrank the hero rules above) ----------
   No hyphenation and no mid-word breaks; each hero scales with the screen so
   its longest word ("Replacement", "Representative") stays whole at 360px. */
@media (max-width: 600px) {
  .page-hero h1, .svc-hero h1, .svc-hero .container:has(.hero-form) h1 { font-size: clamp(22px, 8vw, 44px); overflow-wrap: break-word; hyphens: manual; text-wrap: balance; }
  html .job-hero h1 { font-size: clamp(20px, 7.2vw, 44px); }
  html .post-title-card h1 { font-size: clamp(20px, 6.4vw, 30px); overflow-wrap: break-word; hyphens: manual; }
  .svc-panel-title h3 { font-size: clamp(24px, 3vw, 42px); }
}
