/* Iron Shore override styles, concatenated in the previous link order so the cascade is unchanged. */

/* ---- brand-override.css ---- */
/* Iron Shore Roofing brand re-skin overrides */
:root {
  --color-primary: #1a5fd4;
  --color-primary-dark: #124294;
  --color-primary-light: #3b7ef5;
  --color-accent: #1a5fd4;
  --color-accent-dark: #124294;
  --color-accent-light: #3b7ef5;
  --color-bg: #07090f;
  --color-bg-alt: #0c0f18;
  --color-surface: #111827;
  --color-surface-light: #192236;
  --color-surface-border: rgba(255,255,255,0.07);
  --color-text: #ffffff;
  --color-text-muted: #8998ad;
  --color-text-dim: #3e4f65;
  --font-body: "Open Sans", sans-serif;
}

body, p, span, li, a, input, select, textarea, button {
  font-family: var(--font-body);
}

h1, h2, h3, h4, h5, h6 {
  font-family: "Barlow Condensed", sans-serif !important;
  font-weight: 900 !important;
}

/* Manufacturer brand wordmarks in the "Products We Install" section.
   Verified against the pre-redesign site's own backup: the old site never
   used logo image files here -- each brand name was set in large bold
   Barlow Condensed text, colored in that brand's own signature color
   (GAF red, CertainTeed blue italic, etc.), with a small brand-blue accent
   tick underneath. Restoring that exact typographic treatment instead of
   pasted-in logo image files. Brand-specific colors are applied inline by
   mobile-cta.js (initProductLogos). Applies on desktop and mobile. */
.product-brand {
  font-family: "Barlow Condensed", sans-serif;
  font-size: 30px;
  font-weight: 900;
  letter-spacing: 0.03em;
  line-height: 1.1;
  text-transform: none;
  color: #fff;
  display: inline-block;
  margin-bottom: 4px;
  padding-bottom: 0;
  border-bottom: none;
}

/* Small brand-blue accent tick beneath the wordmark -- this is the site's
   own blue mixed in with each product's brand color above it, matching the
   old site's .mat-line treatment (a short 40x3px bar, not a full-width
   underline dragging under the whole word). */
.product-brand::after {
  content: "";
  display: block;
  width: 40px;
  height: 3px;
  background: var(--color-primary, #1a5fd4);
  margin-top: 8px;
  margin-bottom: 14px;
}

/* Free Estimate CTA buttons -- old site used a distinct orange (#e05c1a)
   for these specifically (hero CTA + form submit), while nav/outline
   buttons stayed brand blue. The current build unified everything under
   .btn-primary, so this now applies to all filled Free Estimate buttons,
   matching the old site's most prominent CTA color. Desktop + mobile. */
.btn-primary,
#ish-mobile-cta-bar .ish-cta-quote {
  background: #e05c1a !important;
}

.btn-primary:hover {
  background: #c94f16 !important;
}


/* Roof Transformations gallery -- remove hover label overlays sitewide (Home + About).
   Images stay; the mismatched "Replacement/Reroof/Repair" tags go. Applies on all
   viewports since the overlay was CSS-only (opacity 0->1 on hover, no separate
   mobile rule), so one display:none covers desktop and mobile. */
.gallery-item-overlay {
  display: none !important;
}


/* ---- mobile-optimize.css ---- */
/* Iron Shore Roofing - Mobile-only visual pass (v6)
   Scoped entirely to max-width: 767px. Desktop styles are untouched.
   v6: removed rounded/gradient "bubbly" styling to match the site's
   existing flat, sharp-cornered desktop look. Fixed 3 grids that don't
   naturally collapse on mobile (products-grid, process-grid, and the
   unclassed "What Makes Us Different" image+content grid, tagged via JS
   as .ish-why-grid). Redesigned the process steps as a vertical stepper. */

#ish-mobile-cta-bar { display: none; }

@media (max-width: 767px) {

  html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

  /* Horizontal-scroll bug: a second .hero-form-card (the "Get a Free
     Estimate" CTA section further down the page, not the hero) rendered at
     its 420px desktop width with no responsive constraint, pushing the page
     630px wide on a 390px screen. Constrain it, plus a safety-net clip on
     the root so no future stray element can force a horizontal scrollbar. */
  html, body { overflow-x: hidden; max-width: 100vw; }

  .hero-form-card {
    width: 100% !important;
    max-width: 420px;
    box-sizing: border-box;
  }

  /* ================= Tap targets & form usability ================= */
  a, button, .btn, .btn-primary, .btn-secondary, .btn-outline, input[type="submit"] {
    min-height: 44px;
  }

  input, select, textarea {
    font-size: 16px !important;
    min-height: 48px;
  }

  textarea { min-height: 96px; }

  body { padding-bottom: calc(64px + env(safe-area-inset-bottom)); }

  /* ================= Top info strip: condense ================= */
  .topbar {
    padding-top: 6px !important;
    padding-bottom: 6px !important;
    font-size: 11px !important;
  }

  /* Topbar redesign: showing only the phone number left it looking like a
     bare, unbalanced strip. Bring back one more piece of desktop's trust
     info (licensed & insured) so the bar reads as intentional, condensed to
     fit two items side by side instead of just the phone floating alone. */
  .topbar .container { display: flex !important; }
  .topbar-items { display: flex !important; gap: 0; }
  .topbar-items > .topbar-item { display: none; }
  .topbar-items > .topbar-item:nth-of-type(3) {
    display: inline-flex !important;
    align-items: center;
    gap: 5px;
    font-size: 11px;
  }
  .topbar-inner { min-height: 0; }
  .topbar-phone {
    font-size: 12px !important;
    line-height: 1.2 !important;
    height: auto !important;
    display: inline-flex !important;
    align-items: center;
    gap: 5px;
  }

  /* Header logo: back on the left (centering it made the header worse --
     reverting to the standard logo-left, actions-right mobile pattern). */
  .main-nav .container {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    min-height: 0;
    padding-top: 10px;
    padding-bottom: 10px;
  }
  .main-nav .nav-logo {
    display: flex;
    align-items: center;
  }
  .main-nav .nav-logo img {
    height: 52px !important;
    width: 100px !important;
    max-width: none !important;
    object-fit: cover !important;
    object-position: top !important;
  }
  .main-nav .nav-links { display: none !important; }
  .main-nav .nav-actions {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  /* Nav "Free Estimate" pill: previously inherited the site-wide mobile
     button padding (13px top/bottom sized for full-width form CTAs), which
     made it huge and wrapped "Free" and "Estimate" onto two lines. Compact,
     single-line pill sized for its actual context next to a logo + hamburger. */
  .main-nav .btn-sm {
    padding: 7px 12px !important;
    font-size: 11px !important;
    min-height: 32px;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
  }

  /* ================= Sticky header: shadow once scrolled ================= */
  .main-nav {
    box-shadow: 0 2px 12px rgba(0,0,0,0.35);
    transition: padding 0.2s ease, box-shadow 0.2s ease;
  }

  body.ish-scrolled .main-nav {
    background-color: rgba(7,9,15,0.97) !important;
    box-shadow: 0 4px 16px rgba(0,0,0,0.45);
  }

  /* ================= Buttons: sizing only, no radius/gradient ================= */
  .btn, .btn-primary, .btn-secondary, .btn-outline {
    padding-top: 13px;
    padding-bottom: 13px;
  }

  .btn-primary:active, .btn-outline:active {
    opacity: 0.85;
  }

  /* ================= Hero ================= */
  .hero { position: relative; overflow: hidden; }

  .hero-bg::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(7,9,15,0.55) 0%, rgba(7,9,15,0.85) 70%, rgba(7,9,15,1) 100%);
    pointer-events: none;
  }

  .hero-inner { padding-top: clamp(20px, 5vw, 32px); padding-bottom: clamp(20px, 5vw, 32px); }

  .hero-content h1, section:first-of-type h1 {
    font-size: clamp(30px, 8.5vw, 42px) !important;
    line-height: 1.08 !important;
    letter-spacing: -0.01em;
    text-shadow: 0 4px 20px rgba(0,0,0,0.5);
  }

  .hero-subtitle {
    font-size: 15.5px;
    line-height: 1.5;
  }

  .hero-badges {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .hero-form-card {
    box-shadow: 0 12px 32px rgba(0,0,0,0.45);
    border: 1px solid rgba(255,255,255,0.12) !important;
  }

  .hero-form-title { font-size: 19px; }

  /* ================= Section rhythm ================= */
  .section-padding {
    padding-top: clamp(36px, 9vw, 56px) !important;
    padding-bottom: clamp(36px, 9vw, 56px) !important;
  }

  .section-label {
    display: inline-block;
    padding-bottom: 4px;
    border-bottom: 2px solid var(--color-primary, #1a5fd4);
    letter-spacing: 0.08em;
  }

  .section-title {
    font-size: clamp(24px, 7vw, 32px) !important;
    line-height: 1.15 !important;
  }

  .section-subtitle { font-size: 15px; line-height: 1.55; }

  /* ================= Cards: flat, bordered, no radius ================= */
  .service-card, .why-card, .product-card, .review-card {
    border: 1px solid rgba(255,255,255,0.1);
    overflow: hidden;
  }

  .service-card-body { padding: 18px !important; }

  /* .service-card-icon intentionally has no mobile override. The site
     owner wants these to match the desktop version exactly: a plain blue
     lucide glyph, no background badge. A prior pass here gave it a filled
     square (the .why-icon badge treatment), which looked different from
     desktop -- removed so mobile just inherits the same unstyled wrapper
     rule desktop already uses. */

  .card, [class*="card"] { padding: 16px !important; }

  /* ================= Reviews: horizontal scroll strip =================
     .review-grid is a CSS grid that collapses to a single column at this
     breakpoint (base site CSS), stacking every review card vertically and
     forcing a long scroll just to get past the section. Turn it into a
     swipeable horizontal row instead so the section stays compact: cards
     sit side by side, each showing a peek of the next one, and the page
     doesn't have to scroll through all of them to reach what's below. */
  .review-grid {
    display: flex !important;
    grid-template-columns: none !important;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    gap: 14px !important;
    padding-bottom: 6px;
    margin-bottom: -6px;
    scrollbar-width: none;
  }

  .review-grid::-webkit-scrollbar { display: none; }

  .review-grid > .review-card {
    flex: 0 0 82%;
    max-width: 340px;
    scroll-snap-align: start;
  }

  /* "See All Customer Reviews" links out to the business's Google Maps
     profile, which doesn't exist yet -- hide just this link on mobile
     until that profile is set up. Targeted by href since .btn-outline
     .btn-sm is a generic button class reused elsewhere on the site. */
  a[href="https://www.google.com/maps/place/Iron+Shore+Roofing"] {
    display: none !important;
  }

  /* ================= Stats bar ================= */
  .stat-value {
    font-size: clamp(24px, 7vw, 30px) !important;
  }

  .stat-label { font-size: 12px; letter-spacing: 0.03em; }

  /* ================= Grids: single column, comfortable gap ================= */
  .grid, [class*="grid-cols-2"], [class*="grid-cols-3"], [class*="grid-cols-4"],
  .products-grid, .process-grid {
    grid-template-columns: 1fr !important;
    gap: 18px !important;
  }

  form .form-row, form [class*="grid-cols-2"] { grid-template-columns: 1fr !important; }
  form label { font-size: 14px; }

  /* ================= "What Makes Us Different": image + content stack =================
     .ish-why-grid / .ish-why-imgcol / .ish-why-contentcol are tagged by mobile-cta.js
     since this section's wrapper divs ship with no class names to target. */
  .ish-why-grid {
    display: block !important;
  }

  .ish-why-imgcol {
    width: 100% !important;
    margin-bottom: 22px;
  }

  .ish-why-imgcol img {
    width: 100%;
    height: 220px;
    object-fit: cover;
    display: block;
  }

  .ish-why-contentcol { width: 100% !important; }

  /*                   "Serving All of Long Island": same classless        
     image+content grid disease as "What Makes Us Different" -- tagged via
     JS as .ish-areas-grid / .ish-areas-textcol / .ish-areas-imgcol. The
     town pill list (.area-towns) is already a flex-wrap row and just needed
     its parent column freed up to full width. */
  .ish-areas-grid { display: block !important; }
  .ish-areas-textcol { width: 100% !important; }
  .ish-areas-imgcol {
    width: 100% !important;
    margin-top: 22px;
  }
  .ish-areas-imgcol img {
    width: 100%;
    height: 200px;
    object-fit: cover;
    display: block;
  }
  .area-towns {
    margin-top: 14px;
  }
  .area-towns > * {
    font-size: 13px;
  }

  /*                   Bottom "Get a Free Roof Estimate Today" CTA: same     
     classless two-column grid (text + .hero-form-card) not collapsing on
     mobile, so the quote form was squeezed into a ~140px sliver with
     clipped fields. Tagged via JS as .ish-finalcta-grid /
     .ish-finalcta-textcol / .ish-finalcta-formcol. */
  .ish-finalcta-grid { display: block !important; }
  .ish-finalcta-textcol { width: 100% !important; }
  .ish-finalcta-formcol {
    width: 100% !important;
    margin-top: 28px;
  }

  /* The plain-text phone link next to "Request an Estimate" had no
     white-space control, so on narrow screens it wrapped mid-number --
     "(516)" on one line, "363-3622" on the next. Keep it intact. */
  .ish-finalcta-textcol a[href^="tel:"] {
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    margin-top: 12px;
  }

  /* Prevent the stat numbers from jittering in width as they count up. */
  .stat-value { font-variant-numeric: tabular-nums; }

  .why-card {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 14px 0;
    border: none;
    border-bottom: 1px solid rgba(255,255,255,0.1);
  }

  .why-card:last-child { border-bottom: none; }

  .why-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-primary, #1a5fd4);
  }

  .why-icon svg { width: 18px; height: 18px; }

  /* ================= Process steps: vertical stepper ================= */
  .process-grid {
    position: relative;
    padding-left: 20px;
    border-left: 2px solid rgba(26,95,212,0.35);
  }

  .process-step {
    position: relative;
    padding: 0 0 28px 0;
  }

  .process-step:last-child { padding-bottom: 0; }

  .process-number {
    position: absolute;
    left: -29px;
    top: 0;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-primary, #1a5fd4);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
  }

  .process-step h3 {
    font-size: 16px;
    margin-bottom: 4px;
  }

  .process-step p {
    font-size: 14px;
    line-height: 1.5;
  }

  /* ================= Images ================= */
  .hero-bg img, .service-card-image, .nav-logo img {
    display: block;
  }

  /* Mobile menu drawer header logo: reuses the same logo component as the
     topbar, but the drawer applies its own inline height (60px) without a
     matching width, leaving the browser's default width:140px from the
     topbar rule in place. That 140x60 box doesn't match the logo file's
     real 400x309 aspect ratio, so with no object-fit specified the image
     was stretched/squashed to fill it. Same crop technique as the topbar
     fix: bigger box, object-fit:cover anchored top, crops out the dead
     space + illegible tagline instead of distorting the artwork. */
  .mobile-menu-header img {
    display: block;
    width: 180px !important;
    height: 94px !important;
    object-fit: cover !important;
    object-position: top !important;
  }

  /* ================= Mobile nav menu ================= */
  .mobile-nav-links { padding-top: 8px; padding-bottom: 8px; }

  .mobile-nav-link {
    min-height: 48px;
    display: flex;
    align-items: center;
    font-size: 17px;
  }

  /* ================= Scroll-reveal micro-animation ================= */
  .ish-reveal {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity 0.5s ease, transform 0.5s ease;
  }

  .ish-reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
  }

  /* ================= Sticky bottom CTA bar ================= */
  #ish-mobile-cta-bar {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    width: 100%;
    box-shadow: 0 -4px 16px rgba(0,0,0,0.4);
    padding-bottom: env(safe-area-inset-bottom);
  }

  #ish-mobile-cta-bar a {
    flex: 1 1 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    height: 58px;
    font-family: var(--font-heading, "Oswald", sans-serif);
    font-weight: 600;
    font-size: 15px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    text-decoration: none;
    border: none;
  }

  #ish-mobile-cta-bar .ish-cta-call {
    background: #12203f;
    color: #fff;
  }

  #ish-mobile-cta-bar .ish-cta-quote {
    background: var(--color-primary, #1a5fd4);
    color: #fff;
  }

  #ish-mobile-cta-bar svg { width: 18px; height: 18px; flex-shrink: 0; }

}


/* ---- system-hero.css ---- */
/* ==========================================================================
   Iron Shore Roofing — "The Iron Shore Roofing System" hero
   --------------------------------------------------------------------------
   Additive, progressively-enhanced layer. Everything is scoped to
   `.hero.ish-sys-on`, a class added by system-hero.js only after it has
   successfully built the scene. If the JS or this stylesheet fails to load,
   the original hero renders untouched.

   Nothing below the hero is targeted by this file.
   ========================================================================== */

.hero.ish-sys-on {
  /* Brand tokens (reused from the site's existing palette) */
  --ish-navy-deep: #070b13;
  --ish-navy: #0b1120;
  --ish-navy-soft: #141a2b;
  --ish-sky-edge: #262c3e;          /* matches the illustration's own sky */
  --ish-blue: #1a5fd4;              /* --color-primary */
  --ish-blue-light: #3b7ef5;        /* --color-primary-light */
  --ish-text-dim: #8998ad;

  /* Layout knobs */
  --ish-art-w: 55%;                 /* right column width  */
  --ish-copy-max: min(460px, 36vw); /* keeps 60-80px+ clear of the artwork */
  --ish-sb-h: 92px;                 /* stage bar height    */

  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  overflow: hidden;
  /* Tall enough that the artwork column is always wider than the artwork's own
     3:1.8 ratio, so the frame below resolves by width and never gets clamped
     (which would break its aspect box and misalign the mask + sweep). */
  min-height: max(620px, calc(31vw + 130px));
  background:
    radial-gradient(120% 90% at 8% 42%, rgba(26, 95, 212, 0.10) 0%, rgba(26, 95, 212, 0) 60%),
    linear-gradient(100deg,
      var(--ish-navy-deep) 0%,
      var(--ish-navy) 34%,
      var(--ish-navy-soft) 55%,
      var(--ish-sky-edge) 100%);
}

/* The original photographic background is replaced by the navy field above.
   Kept in the DOM (not removed) so the untouched markup still validates. */
.hero.ish-sys-on .hero-bg { display: none !important; }

/* Defensive: if the retired storm-hero layer is ever re-introduced, it must
   not paint underneath this hero. */
.hero.ish-sys-on .storm-hero-scene,
.hero.ish-sys-on .sh-overlay { display: none !important; }

/* The hero's inline lead-form card is retired for this layout; the primary
   CTA routes to the same estimate destination it always did. */
.hero.ish-sys-on .hero-form-card { display: none !important; }

/* --------------------------------------------------------------------------
   Left navy field — solid behind the copy, feathered into the illustration
   -------------------------------------------------------------------------- */
.hero.ish-sys-on .ish-panel {
  position: absolute;
  left: 0;
  top: 0;
  bottom: var(--ish-sb-h);
  width: 58%;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(7, 11, 19, 0.97) 0%,
    rgba(7, 11, 19, 0.95) 62%,
    rgba(7, 11, 19, 0.78) 78%,
    rgba(7, 11, 19, 0.34) 90%,
    rgba(7, 11, 19, 0) 100%);
}

/* --------------------------------------------------------------------------
   Right illustration column
   -------------------------------------------------------------------------- */
.hero.ish-sys-on .ish-art {
  position: absolute;
  right: 0;
  top: 0;
  bottom: var(--ish-sb-h);
  width: var(--ish-art-w);
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  pointer-events: none;
}

/* Box is given the artwork's exact intrinsic ratio, so `height:auto` maths
   out to the same result as object-fit:contain with zero layout shift. */
.hero.ish-sys-on .ish-art-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 1600 / 889;
  margin-left: auto;
  overflow: hidden;
  /* Feather the leading edge so the artwork emerges from the navy instead of
     sitting on it as a rectangle. Other edges get only a whisper of falloff. */
  -webkit-mask-image:
    linear-gradient(to right, transparent 0%, rgba(0,0,0,0.45) 5%, #000 14%),
    linear-gradient(to bottom, transparent 0%, #000 6%, #000 95%, transparent 100%),
    linear-gradient(to left, transparent 0%, #000 2%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 0%, rgba(0,0,0,0.45) 5%, #000 14%),
    linear-gradient(to bottom, transparent 0%, #000 6%, #000 95%, transparent 100%),
    linear-gradient(to left, transparent 0%, #000 2%);
  mask-composite: intersect;
  opacity: 0;
  transform: translate3d(0, 20px, 0);
}

.hero.ish-sys-on.ish-ready .ish-art-frame {
  animation: ish-art-in 1000ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

@keyframes ish-art-in {
  from { opacity: 0; transform: translate3d(0, 20px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* Parallax lives on its own layer so it never fights the reveal transform.
   The 1.02 scale guarantees the 7px drift can't expose a bare edge. */
.hero.ish-sys-on .ish-art-shift {
  position: absolute;
  inset: 0;
  transform: scale(1.02) translate3d(var(--ish-px, 0px), var(--ish-py, 0px), 0);
  will-change: transform;
}

.hero.ish-sys-on .ish-art-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: right center;
}

/* Branded light sweep: a soft band angled to the roof slope, travelling from
   the exposed rafters up toward the finished shingles. */
.hero.ish-sys-on .ish-sweep {
  position: absolute;
  left: -35%;
  right: -35%;
  top: 37%;
  height: 22%;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: var(--ish-sweep-o, 0);
  transform: rotate(-19deg) translate3d(0, var(--ish-sweep-y, 260%), 0);
  will-change: transform, opacity;
  background: linear-gradient(180deg,
    rgba(59, 126, 245, 0) 0%,
    rgba(96, 156, 255, 0.10) 34%,
    rgba(198, 224, 255, 0.20) 50%,
    rgba(96, 156, 255, 0.10) 66%,
    rgba(59, 126, 245, 0) 100%);
}

/* --------------------------------------------------------------------------
   Copy column
   -------------------------------------------------------------------------- */
.hero.ish-sys-on .hero-inner {
  position: relative;
  z-index: 3;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  width: 100%;
  padding-top: 40px;
  padding-bottom: 40px;
  /* The site's own rules zero the horizontal padding on .hero-inner, which
     left the copy flush to the viewport edge below 1280px and 20px out of
     alignment with the navigation above it. Restore the container gutter. */
  padding-left: 20px;
  padding-right: 20px;
}

.hero.ish-sys-on .hero-content {
  max-width: var(--ish-copy-max);
  padding-right: 8px;
}

.hero.ish-sys-on .hero-accent {
  margin-bottom: 20px;
}

.hero.ish-sys-on .ish-eyebrow {
  margin: 0 0 12px;
  font-family: Oswald, sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 1.9px;
  text-transform: uppercase;
  color: var(--ish-blue-light);
}

.hero.ish-sys-on .hero-content h1 {
  margin: 0 0 18px;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 900;
  font-size: clamp(38px, 3.3vw, 52px);
  line-height: 1.04;
  letter-spacing: 0.3px;
  color: #fff;
  text-transform: uppercase;
}

.hero.ish-sys-on .hero-content h1 span {
  display: block;
  color: var(--ish-blue-light);
}

.hero.ish-sys-on .hero-subtitle {
  margin: 0 0 28px;
  max-width: 44ch;
  font-size: 17px;
  line-height: 1.62;
  color: #b7c2d2;
}

/* The stacked check-list belongs to the previous hero copy deck. */
.hero.ish-sys-on .hero-badges { display: none !important; }

.hero.ish-sys-on .hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 0 0 22px;
}

/* Reuses the site's existing .btn-primary / .btn-outline components; only the
   hero-specific sizing is adjusted so the CTA stays visually dominant. */
.hero.ish-sys-on .hero-ctas .btn-primary {
  padding: 15px 28px !important;
  font-size: 15px !important;
  box-shadow: 0 10px 26px rgba(224, 92, 26, 0.28);
}

.hero.ish-sys-on .hero-ctas .btn-outline {
  padding: 13px 24px !important;
  font-size: 15px !important;
  border-color: rgba(59, 126, 245, 0.85);
  background: rgba(26, 95, 212, 0.10);
}

.hero.ish-sys-on .hero-ctas .btn-outline:hover {
  background: rgba(26, 95, 212, 0.22);
}

.hero.ish-sys-on .ish-trust {
  margin: 0;
  font-size: 13.5px;
  letter-spacing: 0.3px;
  color: var(--ish-text-dim);
}

/* --------------------------------------------------------------------------
   Stage indicators
   -------------------------------------------------------------------------- */
.hero.ish-sys-on .ish-stagebar {
  position: relative;
  z-index: 3;
  flex: 0 0 auto;
  min-height: var(--ish-sb-h);
  display: flex;
  align-items: center;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  background: linear-gradient(180deg, rgba(7, 11, 19, 0.30) 0%, rgba(7, 11, 19, 0.72) 100%);
  backdrop-filter: blur(2px);
}

.hero.ish-sys-on .ish-stages {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.hero.ish-sys-on .ish-stage { margin: 0; }

.hero.ish-sys-on .ish-stage-btn {
  display: block;
  width: 100%;
  padding: 12px 14px 12px 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: var(--ish-text-dim);
  font-family: inherit;
  transition: color 260ms ease;
}

.hero.ish-sys-on .ish-stage-num {
  display: block;
  margin-bottom: 3px;
  font-family: Oswald, sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1.4px;
  color: rgba(137, 152, 173, 0.62);
  transition: color 260ms ease;
}

.hero.ish-sys-on .ish-stage-label {
  display: block;
  margin-bottom: 10px;
  font-family: Oswald, sans-serif;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.55px;
  text-transform: uppercase;
  color: #93a2b6;
  transition: color 260ms ease;
}

.hero.ish-sys-on .ish-stage-track {
  display: block;
  height: 2px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.13);
  overflow: hidden;
}

.hero.ish-sys-on .ish-stage-fill {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--ish-blue) 0%, var(--ish-blue-light) 100%);
  transform: scaleX(var(--f, 0));
  transform-origin: left center;
}

/* Active / completed states — colour, brightness and the progress line all
   carry the same information, so motion is never the only signal. */
.hero.ish-sys-on .ish-stage-btn.is-active .ish-stage-label,
.hero.ish-sys-on .ish-stage-btn:hover .ish-stage-label,
.hero.ish-sys-on .ish-stage-btn:focus-visible .ish-stage-label {
  color: #ffffff;
}

.hero.ish-sys-on .ish-stage-btn.is-active .ish-stage-num,
.hero.ish-sys-on .ish-stage-btn:hover .ish-stage-num,
.hero.ish-sys-on .ish-stage-btn:focus-visible .ish-stage-num {
  color: var(--ish-blue-light);
}

.hero.ish-sys-on .ish-stage-btn.is-active .ish-stage-track {
  background: rgba(59, 126, 245, 0.22);
}

.hero.ish-sys-on .ish-stage-btn.is-done .ish-stage-label { color: #cdd7e4; }

.hero.ish-sys-on .ish-stage-btn:focus-visible {
  outline: 2px solid var(--ish-blue-light);
  outline-offset: 3px;
}

/* ==========================================================================
   Tablet — narrower split, artwork pulled in so the gap never closes
   ========================================================================== */
@media (min-width: 1000px) and (max-width: 1279px) {
  .hero.ish-sys-on {
    /* The artwork gives back a little width here so the copy column stays
       wide enough to hold both CTAs on one row, while the clear gap between
       text and illustration still stays above 60px. */
    --ish-art-w: 46%;
    --ish-copy-max: min(470px, 46vw);
    --ish-sb-h: 86px;
    min-height: 560px;
  }
  .hero.ish-sys-on .ish-panel { width: 60%; }
  .hero.ish-sys-on .hero-subtitle { font-size: 16px; }
}

/* ==========================================================================
   Stacked layout — copy first, full illustration underneath, never overlapping
   ========================================================================== */
@media (max-width: 999px) {
  .hero.ish-sys-on {
    --ish-sb-h: auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    background:
      linear-gradient(180deg,
        var(--ish-navy-deep) 0%,
        var(--ish-navy) 42%,
        var(--ish-navy-soft) 72%,
        var(--ish-sky-edge) 100%);
  }

  .hero.ish-sys-on .ish-panel { display: none; }

  .hero.ish-sys-on .hero-inner {
    order: 1;
    display: block;
    padding-top: 34px;
    padding-bottom: 26px;
    /* Match the artwork's gutter so copy and illustration align. */
    padding-left: clamp(14px, 4vw, 28px);
    padding-right: clamp(14px, 4vw, 28px);
  }

  .hero.ish-sys-on .hero-content {
    max-width: 640px;
    padding-right: 0;
  }

  .hero.ish-sys-on .hero-content h1 {
    font-size: clamp(32px, 7.4vw, 46px) !important;
    line-height: 1.06 !important;
  }

  .hero.ish-sys-on .hero-subtitle {
    font-size: 16px;
    margin-bottom: 24px;
  }

  .hero.ish-sys-on .ish-trust {
    margin-bottom: 4px;
  }

  /* Artwork becomes a normal-flow block directly beneath the copy. */
  .hero.ish-sys-on .ish-art {
    order: 2;
    position: static;
    width: 100%;
    max-width: 100%;
    bottom: auto;
    display: block;
    padding: 0 clamp(14px, 4vw, 28px);
    box-sizing: border-box;
  }

  .hero.ish-sys-on .ish-art-frame {
    width: 100%;
    margin: 0 auto;
    /* Softer, symmetric falloff now that the artwork is centred. */
    -webkit-mask-image:
      linear-gradient(to right, transparent 0%, #000 4%, #000 96%, transparent 100%),
      linear-gradient(to bottom, transparent 0%, #000 4%, #000 96%, transparent 100%);
    -webkit-mask-composite: source-in;
    mask-image:
      linear-gradient(to right, transparent 0%, #000 4%, #000 96%, transparent 100%),
      linear-gradient(to bottom, transparent 0%, #000 4%, #000 96%, transparent 100%);
    mask-composite: intersect;
  }

  /* No pointer parallax on touch layouts. */
  .hero.ish-sys-on .ish-art-shift { transform: none; }

  .hero.ish-sys-on .ish-stagebar {
    order: 3;
    min-height: 0;
    margin-top: 18px;
    padding: 16px 0 22px;
    background: none;
    backdrop-filter: none;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
  }

  .hero.ish-sys-on .ish-stages {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
  }

  .hero.ish-sys-on .ish-stage-btn { padding: 8px 8px 8px 0; }
  .hero.ish-sys-on .ish-stage-num { font-size: 10px; }
  .hero.ish-sys-on .ish-stage-label {
    font-size: 11.5px;
    letter-spacing: 0.3px;
    margin-bottom: 8px;
  }
}

/* Narrow phones — stages wrap to two rows so labels never get crushed. */
@media (max-width: 620px) {
  .hero.ish-sys-on .ish-stages {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px 16px;
  }
  .hero.ish-sys-on .ish-stage-label { font-size: 12.5px; }

  /* Comfortably tappable, full-width CTAs. */
  .hero.ish-sys-on .hero-ctas {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
  }
  .hero.ish-sys-on .hero-ctas .btn-primary,
  .hero.ish-sys-on .hero-ctas .btn-outline {
    width: 100%;
    text-align: center;
    padding: 16px 20px !important;
    font-size: 15px !important;
    box-sizing: border-box;
  }
}

/* ==========================================================================
   Reduced motion — full static illustration, all four stages legible
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .hero.ish-sys-on .ish-art-frame,
  .hero.ish-sys-on.ish-ready .ish-art-frame {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .hero.ish-sys-on .ish-art-shift {
    transform: none !important;
    transition: none !important;
  }
  .hero.ish-sys-on .ish-sweep { display: none !important; }
  .hero.ish-sys-on .ish-stage-fill {
    transform: scaleX(1) !important;
    transition: none !important;
  }
  .hero.ish-sys-on .ish-stage-label { color: #e7edf5 !important; }
  .hero.ish-sys-on .ish-stage-num { color: var(--ish-blue-light) !important; }
  .hero.ish-sys-on .ish-stage-track { background: rgba(59, 126, 245, 0.22) !important; }
}

/* Same treatment when the JS reduced-motion branch takes over. */
.hero.ish-sys-on.ish-rm .ish-art-frame { animation: none !important; opacity: 1 !important; transform: none !important; }
.hero.ish-sys-on.ish-rm .ish-sweep { display: none !important; }
.hero.ish-sys-on.ish-rm .ish-stage-fill { transform: scaleX(1) !important; }
.hero.ish-sys-on.ish-rm .ish-stage-label { color: #e7edf5 !important; }
.hero.ish-sys-on.ish-rm .ish-stage-num { color: var(--ish-blue-light) !important; }
.hero.ish-sys-on.ish-rm .ish-stage-track { background: rgba(59, 126, 245, 0.22) !important; }


/* ---- coast-hero.css ---- */
/* ==========================================================================
   Iron Shore Roofing — Coastal video hero
   --------------------------------------------------------------------------
   Additive, progressively-enhanced layer. Everything is scoped to
   `.hero.ch-on`, a class added by coast-hero.js only after it has
   successfully built the scene. If the JS or this stylesheet fails to load,
   the original hero renders untouched.

   Geometry notes (measured from the source artwork, 1280x720):
     · The highest point of the roof/chimney sits at y = 147  → 20.4% of the
       frame height. Everything above that line is open sky.
     · The plane therefore flies inside the top 0–18.5% band of the *video
       frame* (not the container), so it can never cross the roofline no
       matter how the video is cropped. coast-hero.js computes the rendered
       video box and publishes it as --ch-vw / --ch-vh / --ch-vx.
     · The video is anchored `center top`, so that sky band is never the part
       that gets cropped away.

   Nothing below the hero is targeted by this file.
   ========================================================================== */

.hero.ch-on {
  /* Brand tokens — reused from the site's existing palette */
  --ch-navy-deep: #070b13;
  --ch-navy: #0b1120;
  --ch-blue: #1a5fd4;         /* --color-primary */
  --ch-blue-light: #3b7ef5;   /* --color-primary-light */
  --ch-text-dim: #93a2b6;

  /* Published by coast-hero.js (px). Fallbacks keep the layout sane if the
     measuring pass has not run yet. */
  --ch-vw: 100%;
  --ch-vh: 100%;
  --ch-vx: 0px;
  --ch-plane-w: 380px;
  --ch-plane-top: 34px;
  --ch-stage-w: 100vw;

  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  overflow: hidden;
  isolation: isolate;
  /* Fixed by CSS alone, so the hero reserves its space before any media
     loads — no layout shift. */
  /* Nudged up only enough to seat the trust strip. Kept deliberately modest:
     on desktop the media box is sized from the hero's height, so every extra
     pixel of height also widens the artwork and eats into the navy the copy
     sits on. */
  min-height: clamp(620px, calc(27vw + 200px), 780px);
  background:
    radial-gradient(120% 90% at 6% 45%, rgba(26, 95, 212, 0.13) 0%, rgba(26, 95, 212, 0) 58%),
    linear-gradient(100deg, var(--ch-navy-deep) 0%, var(--ch-navy) 62%, #101827 100%);
}

/* Retire the layers belonging to earlier hero iterations. Kept in the DOM
   (not removed) so the untouched React markup still validates. */
.hero.ch-on .hero-bg,
.hero.ch-on .hero-form-card,
.hero.ch-on .hero-badges,
.hero.ch-on .storm-hero-scene,
.hero.ch-on .sh-overlay,
.hero.ch-on .ish-art,
.hero.ch-on .ish-panel,
.hero.ch-on .ish-stagebar,
.hero.ch-on .ish-eyebrow { display: none !important; }

/* --------------------------------------------------------------------------
   Layer 0 — waterfront video
   -------------------------------------------------------------------------- */
/* The media box is sized by coast-hero.js to the artwork's own 16:9 ratio and
   anchored to the right, so on desktop the *whole* scene is visible — sky,
   horizon, surf, dune and the complete house, never cropped mid-porch. The
   copy panel occupies the navy to its left. */
.hero.ch-on .ch-media {
  position: absolute;
  top: 0;
  right: 0;
  width: var(--ch-vw);
  height: var(--ch-vh);
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Feather the leading edge so the artwork emerges from the navy instead of
   sitting on it as a rectangle. Only applied when there is navy to emerge
   from — see .ch-inset, set by the measuring pass. */
.hero.ch-on.ch-inset .ch-media {
  -webkit-mask-image: linear-gradient(to right, transparent 0%, rgba(0, 0, 0, 0.5) 7%, #000 21%);
  mask-image: linear-gradient(to right, transparent 0%, rgba(0, 0, 0, 0.5) 7%, #000 21%);
}

.hero.ch-on .ch-video,
.hero.ch-on .ch-still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Top-anchored: the sky band the plane flies in is never cropped away. */
  object-position: center top;
  display: block;
  border: 0;
}

/* The video is visible from the start and the still sits behind it as a true
   fallback.

   This used to be inverted — the video was opacity:0 and only revealed by a
   one-shot `playing` listener. That made a single missed event enough to hide
   a perfectly good video behind the poster forever, which is precisely the
   "it's just a still image" failure. The video element's own `poster` is the
   same frame as the still, so showing it immediately costs nothing visually
   and removes the failure mode entirely. */
.hero.ch-on .ch-video {
  opacity: 1;
  z-index: 1;
}

.hero.ch-on .ch-still { z-index: 0; }

/* Kill every native media affordance.

   This is a decorative background, never a player. iOS Safari draws a large
   centred "start playback" glyph over any inline video it has not started, and
   because the video now sits at opacity 1 that glyph became visible — it looked
   like the hero was a tap-to-play video. Suppressing these pseudo-elements
   means a refused or delayed autoplay degrades to the poster frame silently,
   with no control furniture on top of the artwork. */
.hero.ch-on .ch-video::-webkit-media-controls,
.hero.ch-on .ch-video::-webkit-media-controls-panel,
.hero.ch-on .ch-video::-webkit-media-controls-panel-container,
.hero.ch-on .ch-video::-webkit-media-controls-play-button,
.hero.ch-on .ch-video::-webkit-media-controls-overlay-play-button,
.hero.ch-on .ch-video::-webkit-media-controls-start-playback-button {
  display: none !important;
  -webkit-appearance: none !important;
  appearance: none !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* If the video genuinely cannot decode, drop it out so the still behind is
   what shows. Set by coast-hero.js on a real `error` event only. */
.hero.ch-on.ch-novideo .ch-video { display: none !important; }

/* --------------------------------------------------------------------------
   Layer 1 — plane + banner
   -------------------------------------------------------------------------- */
/* The plane sits *under* the scrim, and the layer itself fades toward the
   copy side. Two things fall out of that: the plane can never compete with
   the headline, and its exit reads as flying off into the haze rather than
   sliding off a rectangle. */
.hero.ch-on .ch-plane-layer {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
  /* Fully gone before it reaches the copy panel — a part-faded plane over
     flat navy reads as a smudge, not as depth. The two stops are pinned to
     the artwork's actual left edge by the measuring pass, so the fade lands
     in the same place relative to the scene at every viewport width. */
  -webkit-mask-image: linear-gradient(to right,
    transparent 0%, transparent var(--ch-fade-a, 25%), #000 var(--ch-fade-b, 40%));
  mask-image: linear-gradient(to right,
    transparent 0%, transparent var(--ch-fade-a, 25%), #000 var(--ch-fade-b, 40%));
}

.hero.ch-on .ch-plane-fly {
  position: absolute;
  left: 0;
  top: var(--ch-plane-top);
  width: var(--ch-plane-w);
  will-change: transform;
  /* Parked off the right edge until the animation starts. */
  transform: translate3d(calc(var(--ch-stage-w) + 40px), 0, 0);
}

/* The negative delay starts the cycle already underway, so the plane is
   entering frame on arrival rather than making visitors wait for it. */
.hero.ch-on.ch-fly .ch-plane-fly {
  animation: ch-fly var(--ch-fly-dur, 44s) linear infinite;
  animation-delay: calc(var(--ch-fly-dur, 44s) * -0.06);
}

.hero.ch-on .ch-plane-bob {
  display: block;
  will-change: transform;
}

.hero.ch-on.ch-fly .ch-plane-bob {
  animation: ch-bob 6.5s ease-in-out infinite;
}

.hero.ch-on .ch-plane {
  display: block;
  width: 100%;
  height: auto;
  /* Seats the cut-out into the scene instead of letting it sit on top. */
  filter: drop-shadow(0 6px 14px rgba(7, 11, 19, 0.28));
}

/* Travel occupies the first 60% of the cycle; the remainder is an empty sky
   beat so the hero stays calm rather than becoming a conveyor belt. */
@keyframes ch-fly {
  0%   { transform: translate3d(calc(var(--ch-stage-w) + 40px), 0, 0); }
  60%  { transform: translate3d(calc(-1 * var(--ch-plane-w) - 40px), 0, 0); }
  100% { transform: translate3d(calc(-1 * var(--ch-plane-w) - 40px), 0, 0); }
}

@keyframes ch-bob {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%      { transform: translate3d(0, -6px, 0) rotate(-0.7deg); }
}

/* --------------------------------------------------------------------------
   Layer 2 — readability scrim
   -------------------------------------------------------------------------- */
.hero.ch-on .ch-scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    /* seats the hero under the dark sticky nav */
    linear-gradient(180deg, rgba(7, 11, 19, 0.55) 0%, rgba(7, 11, 19, 0) 18%),
    /* settles the bottom edge into the section below */
    linear-gradient(0deg, rgba(7, 11, 19, 0.45) 0%, rgba(7, 11, 19, 0) 22%),
    /* The copy panel. Stops sit further right than before: the taller hero
       widens the artwork (its width derives from the hero's height), so the
       dark field has to reach further to keep the subtitle and CTAs on solid
       ground. The house itself starts well right of the last stop. */
    linear-gradient(90deg,
      rgba(7, 11, 19, 0.94) 0%,
      rgba(7, 11, 19, 0.90) 30%,
      rgba(7, 11, 19, 0.68) 44%,
      rgba(7, 11, 19, 0.30) 58%,
      rgba(7, 11, 19, 0.07) 74%,
      rgba(7, 11, 19, 0) 86%);
}

/* A whisper of brand blue in the copy field, matching the previous hero. */
.hero.ch-on .ch-scrim::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 6% 45%,
    rgba(26, 95, 212, 0.16) 0%, rgba(26, 95, 212, 0) 58%);
}

/* --------------------------------------------------------------------------
   Layer 3 — copy
   -------------------------------------------------------------------------- */
.hero.ch-on .hero-inner {
  position: relative;
  z-index: 3;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  width: 100%;
  padding-top: 40px;
  /* Reserves the trust strip's shelf so the copy can never sit under it. */
  padding-bottom: 96px;
  /* The site's own rules zero the horizontal padding on .hero-inner; restore
     the container gutter so the copy lines up with the navigation above. */
  padding-left: 20px;
  padding-right: 20px;
}

.hero.ch-on .hero-content {
  /* Slightly narrower than before so the larger display type still resolves
     inside the navy and never runs out over the bright part of the artwork. */
  max-width: min(470px, 38vw);
  padding-right: 8px;
}

.hero.ch-on .hero-accent { margin-bottom: 16px; }

/* Eyebrow — Iron Shore's own logo tagline, set as a tracked label above the
   headline. Gives the hero the layered "label / display / support / action"
   rhythm the reference builds its authority from. */
.hero.ch-on .ch-eyebrow {
  margin: 0 0 14px;
  font-family: Oswald, sans-serif;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 3.2px;
  text-transform: uppercase;
  color: var(--ch-blue-light);
}

.hero.ch-on .hero-content h1 {
  margin: 0 0 20px;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 900;
  /* Larger and tighter than before: the display line is what carries the
     "premium/cinematic" read, so it gets the most room. */
  font-size: clamp(42px, 4.15vw, 66px);
  line-height: 0.98;
  letter-spacing: -0.2px;
  color: #fff;
  text-transform: uppercase;
  text-shadow: 0 3px 28px rgba(0, 0, 0, 0.5);
}

.hero.ch-on .hero-content h1 span {
  display: block;
  color: var(--ch-blue-light);
}

.hero.ch-on .hero-subtitle {
  margin: 0 0 30px;
  max-width: 42ch;
  font-size: 17px;
  line-height: 1.62;
  color: #c2cddb;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
}

.hero.ch-on .hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 0 0 22px;
}

/* Reuses the site's existing .btn-primary / .btn-outline components; only the
   hero-specific sizing is adjusted so the CTA stays visually dominant. */
.hero.ch-on .hero-ctas .btn-primary {
  padding: 15px 30px;
  font-size: 15px;
  box-shadow: 0 10px 26px rgba(224, 92, 26, 0.30);
}

.hero.ch-on .hero-ctas .btn-outline {
  padding: 13px 26px;
  font-size: 15px;
  border-color: rgba(59, 126, 245, 0.85);
  background: rgba(26, 95, 212, 0.14);
  backdrop-filter: blur(2px);
}

.hero.ch-on .hero-ctas .btn-outline:hover {
  background: rgba(26, 95, 212, 0.26);
}

/* The old single-line trust text is superseded by the strip below. Kept in the
   DOM so the copy still exists for anything reading the page as text. */
.hero.ch-on .ch-trust {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Trust strip — pinned to the foot of the hero
   --------------------------------------------------------------------------
   Four proof points on a hairline-topped translucent shelf, each with a
   thin-line glyph. This is the single most useful idea in the desktop
   reference: it converts a throwaway line of small print into the hero's
   credibility anchor without costing any vertical space in the copy column.

   Absolutely positioned so the headline stays optically centred in the full
   hero; .hero-inner reserves matching padding so the two can never collide.
   -------------------------------------------------------------------------- */
.hero.ch-on .ch-trustbar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  align-items: center;
  /* --ch-gutter is measured from the copy column by the measuring pass, so the
     first proof point lines up exactly under the headline at any width. */
  padding: 0 var(--ch-gutter, 20px);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  background: linear-gradient(180deg, rgba(7, 11, 19, 0.42) 0%, rgba(7, 11, 19, 0.78) 100%);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.hero.ch-on .ch-tb-item {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
  padding: 20px 18px 20px 0;
}

/* Hairline separators between the columns, matching the reference. */
.hero.ch-on .ch-tb-item + .ch-tb-item {
  border-left: 1px solid rgba(255, 255, 255, 0.10);
  padding-left: 22px;
}

.hero.ch-on .ch-tb-icon {
  flex: 0 0 auto;
  width: 21px;
  height: 21px;
  color: var(--ch-blue-light);
}

.hero.ch-on .ch-tb-label {
  font-family: Oswald, sans-serif;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 1.5px;
  line-height: 1.25;
  text-transform: uppercase;
  color: #d5dee9;
}

/* ==========================================================================
   Tablet
   ========================================================================== */
@media (min-width: 768px) and (max-width: 1023px) {
  .hero.ch-on {
    min-height: clamp(600px, 70vh, 700px);
  }

  .hero.ch-on .hero-content { max-width: min(430px, 50vw); }
  .hero.ch-on .hero-content h1 { font-size: clamp(36px, 5.2vw, 48px); }
  .hero.ch-on .hero-subtitle { font-size: 16px; }

  /* Two columns of two at this width — four across gets too cramped to read. */
  .hero.ch-on .ch-trustbar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero.ch-on .ch-tb-item { padding: 14px 14px 14px 0; }
  .hero.ch-on .ch-tb-item:nth-child(odd) { border-left: 0; padding-left: 0; }
  .hero.ch-on .ch-tb-item:nth-child(n + 3) { border-top: 1px solid rgba(255, 255, 255, 0.08); }
  .hero.ch-on .hero-inner { padding-bottom: 132px; }

  .hero.ch-on .ch-scrim {
    background:
      linear-gradient(180deg, rgba(7, 11, 19, 0.55) 0%, rgba(7, 11, 19, 0) 18%),
      linear-gradient(0deg, rgba(7, 11, 19, 0.50) 0%, rgba(7, 11, 19, 0) 24%),
      linear-gradient(90deg,
        rgba(7, 11, 19, 0.96) 0%,
        rgba(7, 11, 19, 0.92) 38%,
        rgba(7, 11, 19, 0.70) 56%,
        rgba(7, 11, 19, 0.32) 74%,
        rgba(7, 11, 19, 0.08) 92%,
        rgba(7, 11, 19, 0) 100%);
  }
}

/* ==========================================================================
   Mobile — copy sits over the scene, plane keeps its own reserved band
   ========================================================================== */
@media (max-width: 767px) {
  /* The scene runs full width as a band across the top — the entire coastal
     frame, uncropped — and dissolves into navy where the copy sits. Fitting
     it any other way turns the hero into a close-up of the house and loses
     the waterfront entirely. Height is reserved in pure CSS (56.25vw is the
     artwork's 16:9 height at full width), so there is no layout shift. */
  .hero.ch-on {
    min-height: 0;
    justify-content: flex-start;
  }

  .hero.ch-on .ch-media {
    width: 100%;
    height: 56.25vw;
    right: 0;
    -webkit-mask-image: linear-gradient(to bottom, #000 60%, rgba(0, 0, 0, 0.45) 84%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 60%, rgba(0, 0, 0, 0.45) 84%, transparent 100%);
  }

  .hero.ch-on .hero-inner {
    display: block;
    padding-top: calc(85vw + 18px);
    padding-bottom: 26px;
    padding-left: clamp(16px, 5vw, 28px);
    padding-right: clamp(16px, 5vw, 28px);
  }

  /* In normal flow here, beneath the CTAs — the copy is already stacked, so
     there is nothing to pin the strip over and no reason to overlay it. */
  .hero.ch-on .ch-trustbar {
    position: static;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0;
    /* Tight margins here: the strip is worth its space on mobile, but the hero
       already carries the video band, headline and two full-width CTAs, so
       every row has to earn its height. */
    margin: 0 clamp(16px, 5vw, 28px) 18px;
    padding: 2px 0 0;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-top: 1px solid rgba(255, 255, 255, 0.11);
  }

  .hero.ch-on .ch-tb-item {
    gap: 9px;
    padding: 10px 10px 10px 0;
  }

  .hero.ch-on .ch-tb-item + .ch-tb-item { border-left: 0; padding-left: 0; }
  .hero.ch-on .ch-tb-item:nth-child(even) { padding-left: 12px; }
  .hero.ch-on .ch-tb-item:nth-child(n + 3) { border-top: 1px solid rgba(255, 255, 255, 0.07); }

  .hero.ch-on .ch-tb-icon { width: 18px; height: 18px; }
  .hero.ch-on .ch-tb-label { font-size: 10.5px; letter-spacing: 1.1px; }

  .hero.ch-on .ch-eyebrow { font-size: 11px; letter-spacing: 2.6px; margin-bottom: 12px; }

  .hero.ch-on .hero-content {
    max-width: 100%;
    padding-right: 0;
  }

  .hero.ch-on .hero-content h1 {
    font-size: clamp(32px, 8.6vw, 44px) !important;
    line-height: 1.06 !important;
    margin-bottom: 14px;
  }

  .hero.ch-on .hero-subtitle {
    font-size: 15.5px;
    line-height: 1.52;
    max-width: 100%;
    margin-bottom: 22px;
  }

  /* The copy sits below the plane here rather than beside it, so the plane
     stays legible right across the width. */
  .hero.ch-on .ch-plane-layer {
    -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12%);
    mask-image: linear-gradient(to right, transparent 0%, #000 12%);
  }

  /* The copy sits on navy here, not on the scene, so the scrim only has to
     seat the artwork under the dark sticky nav. */
  .hero.ch-on .ch-scrim {
    background: linear-gradient(180deg, rgba(7, 11, 19, 0.48) 0%, rgba(7, 11, 19, 0) 26%);
  }

  .hero.ch-on .ch-scrim::after { opacity: 0.55; }

  /* Comfortably tappable, full-width CTAs. */
  .hero.ch-on .hero-ctas {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    margin-bottom: 18px;
  }

  .hero.ch-on .hero-ctas .btn-primary,
  .hero.ch-on .hero-ctas .btn-outline {
    width: 100%;
    text-align: center;
    padding: 16px 20px;
    box-sizing: border-box;
  }

  .hero.ch-on .ch-trust { font-size: 12.5px; }

  /* Gentler bob at small sizes. */
  @keyframes ch-bob {
    0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
    50%      { transform: translate3d(0, -4px, 0) rotate(-0.5deg); }
  }
}

/* ==========================================================================
   Reduced motion — static scene, plane parked in open sky
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .hero.ch-on .ch-video { display: none !important; }

  .hero.ch-on .ch-plane-fly,
  .hero.ch-on.ch-fly .ch-plane-fly {
    animation: none !important;
    transform: translate3d(var(--ch-park-x, 8%), 0, 0) !important;
  }

  .hero.ch-on .ch-plane-bob,
  .hero.ch-on.ch-fly .ch-plane-bob {
    animation: none !important;
    transform: none !important;
  }

  .hero.ch-on .ch-video { transition: none !important; }
}

/* Same treatment when the JS reduced-motion / save-data branch takes over. */
.hero.ch-on.ch-rm .ch-video { display: none !important; }
.hero.ch-on.ch-rm .ch-plane-fly {
  animation: none !important;
  transform: translate3d(var(--ch-park-x, 8%), 0, 0) !important;
}
.hero.ch-on.ch-rm .ch-plane-bob { animation: none !important; transform: none !important; }


/* ==== Restore hero lead form on coastal hero (2026-07-30) ==== */
.hero.ch-on .hero-inner{
  display:flex;
  flex-direction:row;
  align-items:center;
  justify-content:space-between;
  gap:48px;
  position:relative;
  z-index:5;
}
.hero.ch-on .hero-content{ flex:1 1 auto; max-width:560px; }
.hero.ch-on .hero-form-card{
  display:block !important;
  position:relative;
  z-index:6;
  flex:0 0 400px;
  width:400px;
  max-width:400px;
  background:rgba(11,16,26,.93);
  border:1px solid rgba(255,255,255,.14);
  border-radius:14px;
  box-shadow:0 24px 60px rgba(0,0,0,.5);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
  padding:26px 24px;
}
.hero.ch-on .hero-form-title{ margin:0 0 4px; }
.hero.ch-on .hero-form-subtitle{ margin:0 0 16px; }

@media (min-width:1024px) and (max-width:1180px){
  .hero.ch-on .hero-inner{ gap:28px; }
  .hero.ch-on .hero-form-card{ flex:0 0 340px; width:340px; max-width:340px; padding:22px 20px; }
}

/* Tablet: stack copy above the form, keep the flex column */
@media (min-width:768px) and (max-width:1023px){
  .hero.ch-on .hero-inner{ flex-direction:column; align-items:stretch; gap:24px; }
  .hero.ch-on .hero-content{ max-width:none; }
  .hero.ch-on .hero-form-card{ flex:1 1 auto; width:100%; max-width:520px; }
}

/* Phone: leave the original display:block layout alone, just size the card */
@media (max-width:767px){
  .hero.ch-on .hero-form-card{
    width:100%;
    max-width:none;
    margin:22px 0 0;
    padding:22px 18px;
  }
}

/* Homepage React hero sets hero-roof-aerial.jpg inline on .hero-bg.
   The coastal hero replaces that layer, so the JPEG is never shown.
   !important beats the inline style and keeps the file off the wire. */
html:not(.is-inner) .hero > .hero-bg {
  background-image: none !important;
}


/* ---- icon-badges.css ---- */
/* ==========================================================================
   Iron Shore Roofing — icon badge legibility fix
   --------------------------------------------------------------------------
   THE BUG
   The three icon-badge components are authored in the app bundle as:

       .why-icon, .value-icon, .contact-info-icon {
         background-color: var(--color-primary);
         color:            var(--color-accent);
       }

   The lucide glyphs inside stroke with `currentColor`, so the design intent
   was an accent-coloured symbol sitting on a primary-coloured tile. Both
   custom properties currently resolve to the same blue:

       --color-primary = #1a5fd4
       --color-accent  = #1a5fd4

   so every symbol was drawing blue-on-blue (contrast ratio 1.00) and the
   badges rendered as plain blue squares. The icons were always present and
   correctly chosen — dollar-sign for pricing, shield for insured, map-pin for
   local, award for warranties, sparkles for cleanup, heart/hammer/shield-check
   on About, phone/mail/map-pin/clock on Contact — they simply could not be seen.

   THE FIX
   Give the glyphs an explicit legible colour rather than depending on two
   design tokens happening to differ. White on solid brand blue also matches
   `.process-number`, the one badge on the site that was already rendering
   correctly, so the treatment stays consistent with the existing design
   rather than introducing a new one.

   Deliberately unchanged: badge size, shape (square, matching
   .process-number), position, spacing, and every icon choice. Nothing here
   affects layout, so there is no reflow risk on any page.

   Note: the underlying --color-accent / --color-primary collision is left
   alone on purpose. That token may be relied on elsewhere where blue is
   correct, and retuning a global palette variable is a wider change than
   this fix warrants.
   ========================================================================== */

.why-icon,
.value-icon,
.contact-info-icon {
  /* lucide strokes inherit this through currentColor */
  color: #ffffff;
}

/* Belt and braces: if a future build hardcodes the stroke attribute instead
   of using currentColor, this still holds the icon legible. */
.why-icon > svg,
.value-icon > svg,
.contact-info-icon > svg {
  color: inherit;
  stroke: currentColor;
}

/* At 18–24px a 2px stroke on saturated blue can look slightly heavy; easing it
   a touch keeps the glyph crisp without changing its size or position. */
.why-icon > svg,
.contact-info-icon > svg {
  stroke-width: 1.9;
}

.value-icon > svg {
  stroke-width: 1.8;
}


/* ---- home-polish.css ---- */
/* ==========================================================================
   Iron Shore Roofing — homepage styling refresh
   --------------------------------------------------------------------------
   Reference direction: modern dark editorial styling — wide-tracked eyebrow
   labels, oversized condensed display headings, hairline structure instead of
   filled boxes, generous vertical rhythm, and a circular arrow affordance on
   service links.

   HARD CONSTRAINTS OBSERVED
   · No font families are changed. The site already runs Barlow Condensed /
     Oswald / Open Sans, which is the same type category as the reference; the
     premium read is achieved with scale, tracking and spacing instead.
   · No brand colours are introduced. Blue #1a5fd4 / #3b7ef5 and the orange
     CTA are untouched; every new line and tint is white-at-low-alpha.
   · Nothing is restructured. No grid becomes rows, no element is removed, no
     copy is rewritten. This file only restyles what is already there.
   · `border-radius: 0` is preserved throughout — the existing components and
     both references share that sharp-cornered language.

   SPECIFICITY NOTE
   mobile-optimize.css sets !important on .section-padding, .section-title,
   .service-card and .area-town inside max-width queries. Size and spacing
   changes here are therefore scoped to min-width so they cannot fight the
   deliberate mobile tuning; only treatment-level rules (borders, tracking,
   image filters) apply at every width.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Section labels — wide-tracked eyebrow with a leading rule
   -------------------------------------------------------------------------- */
.section-label {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  letter-spacing: 3.4px;
}

.section-label::before {
  content: "";
  width: 26px;
  height: 1px;
  background: var(--color-primary-light, #3b7ef5);
  flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   2. Display headings — bigger, tighter, more deliberate
   -------------------------------------------------------------------------- */
.section-title {
  line-height: 0.99;
  letter-spacing: -0.3px;
}

@media (min-width: 768px) {
  .section-title {
    font-size: clamp(38px, 3.7vw, 54px);
  }
}

/* --------------------------------------------------------------------------
   3. Vertical rhythm — more air between sections
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .section-padding {
    padding-top: 112px;
    padding-bottom: 112px;
  }
}

/* Hairline seam between adjacent bands so the page reads as deliberate
   sections rather than a continuous dark scroll. */
.section-dark + .section-darker,
.section-darker + .section-dark,
.section-dark + .section-dark,
.section-darker + .section-darker {
  border-top: 1px solid rgba(255, 255, 255, 0.055);
}

/* --------------------------------------------------------------------------
   4. Service cards — hairline frames, live imagery, circular arrow
   -------------------------------------------------------------------------- */
.service-card {
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.09);
  background: rgba(255, 255, 255, 0.012);
  transition: border-color 260ms ease, transform 260ms ease, background-color 260ms ease;
}

.service-card:hover,
.service-card:focus-visible {
  border-color: rgba(59, 126, 245, 0.55);
  background: rgba(26, 95, 212, 0.05);
}

@media (min-width: 1024px) {
  .service-card:hover,
  .service-card:focus-visible {
    transform: translateY(-4px);
  }
}

.service-card-image {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 11;
  object-fit: cover;
  /* Sits the photography into the dark page instead of letting it glare, then
     brings it fully to life on hover. */
  filter: saturate(0.82) brightness(0.9) contrast(1.04);
  transition: filter 420ms ease, transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.service-card:hover .service-card-image,
.service-card:focus-visible .service-card-image {
  filter: saturate(1) brightness(1) contrast(1);
  transform: scale(1.04);
}

@media (min-width: 768px) {
  .service-card-body {
    padding: 26px 24px 28px;
  }
}

/* Descriptions differ in length, which left the arrow links sitting at
   different heights across a row. Bottom-aligning them makes the row scan as a
   set rather than three loose cards. */
.service-card {
  display: flex;
  flex-direction: column;
}

.service-card-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

.service-card-link {
  margin-top: auto;
  padding-top: 18px;
}

/* The circular arrow affordance from the reference. Applied to the existing
   link element, so if its inner glyph is ever swapped the layout still holds. */
.service-card-link {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}

.service-card-link > svg {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  padding: 7px;
  box-sizing: border-box;
  border: 1px solid currentColor;
  border-radius: 50%;
  transition: background-color 240ms ease, transform 240ms ease;
}

.service-card:hover .service-card-link > svg {
  background: rgba(59, 126, 245, 0.16);
  transform: translateX(3px);
}

/* --------------------------------------------------------------------------
   5. Why-us rows — structured hairline rows
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .why-card {
    padding: 18px 20px 18px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  }

  .why-card:last-child {
    border-bottom: 0;
  }
}

/* --------------------------------------------------------------------------
   6. Review cards — framed, with a quote mark
   -------------------------------------------------------------------------- */
.review-card {
  position: relative;
  border: 1px solid rgba(255, 255, 255, 0.085);
  background: rgba(255, 255, 255, 0.014);
  transition: border-color 240ms ease;
}

.review-card:hover {
  border-color: rgba(59, 126, 245, 0.4);
}

.review-text {
  position: relative;
  z-index: 1;
}

/* --------------------------------------------------------------------------
   7. Process steps — one continuous rule, left-aligned like everything else
   --------------------------------------------------------------------------
   Two corrections here.

   First: a border-top on each .process-step produced four disconnected
   hairline stubs separated by the 32px grid gap, which read as a rendering
   fault rather than structure. The rule belongs on the grid so it runs
   unbroken across the row with the numbered steps hanging beneath it.

   Second: this section and the FAQ were the only two of nine whose headers
   were centred — the other seven are left-aligned, and so is the numbered
   "01 / 02 / 03 / 04" treatment Iron Shore already used in its previous hero.
   Aligning them is what makes the page scan as one deliberate system.
   The centring is set inline by the app, hence !important.
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .process-grid {
    border-top: 1px solid rgba(255, 255, 255, 0.11);
    padding-top: 30px;
  }

  .process-step {
    border-top: 0;
    padding-top: 0;
  }
}

section:has(.process-grid) > .container > div:first-child,
section:has(.faq-list) > .container > div:first-child {
  text-align: left !important;
}

.process-step {
  text-align: left !important;
}

.process-number {
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* --------------------------------------------------------------------------
   8. Product cards and tags — hairline chips
   -------------------------------------------------------------------------- */
.product-card {
  border: 1px solid rgba(255, 255, 255, 0.085);
  background: rgba(255, 255, 255, 0.014);
  transition: border-color 240ms ease;
}

.product-card:hover {
  border-color: rgba(59, 126, 245, 0.4);
}

.product-brand {
  letter-spacing: 2.2px;
}

.product-tag {
  border: 1px solid rgba(59, 126, 245, 0.4);
  background: rgba(26, 95, 212, 0.09);
  letter-spacing: 1.1px;
}

/* --------------------------------------------------------------------------
   9. Service-area chips
   -------------------------------------------------------------------------- */
.area-town {
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.02);
  transition: border-color 200ms ease, background-color 200ms ease, color 200ms ease;
}

.area-town:hover {
  border-color: rgba(59, 126, 245, 0.55);
  background: rgba(26, 95, 212, 0.12);
  color: #fff;
}

/* --------------------------------------------------------------------------
   10. Stat bar — divided columns
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .stat-item + .stat-item {
    border-left: 1px solid rgba(255, 255, 255, 0.16);
  }
}

.stat-label {
  letter-spacing: 2px;
}

/* --------------------------------------------------------------------------
   11. FAQ — hairline list with breathing room
   -------------------------------------------------------------------------- */
.faq-item {
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.faq-item:first-child {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

@media (min-width: 768px) {
  .faq-trigger {
    padding-top: 22px;
    padding-bottom: 22px;
  }
}

.faq-trigger:hover {
  color: #fff;
}

/* --------------------------------------------------------------------------
   12. CTA bands — a touch more presence
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .cta-band {
    padding-top: 92px;
    padding-bottom: 92px;
  }
}

.cta-band .section-title,
.cta-band h2 {
  letter-spacing: -0.3px;
}

/* --------------------------------------------------------------------------
   13. Reduced motion — drop the hover motion, keep every colour change
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .service-card,
  .service-card-image,
  .service-card-link > svg,
  .review-card,
  .product-card,
  .area-town {
    transition: none !important;
  }

  .service-card:hover,
  .service-card:focus-visible {
    transform: none !important;
  }

  .service-card:hover .service-card-image,
  .service-card:focus-visible .service-card-image {
    transform: none !important;
  }

  .service-card:hover .service-card-link > svg {
    transform: none !important;
  }
}


/* ==========================================================================
   Topbar phone icon alignment (desktop/tablet only)
   --------------------------------------------------------------------------
   .topbar-phone is display:block, and the site's SVG reset also makes the
   phone icon inside it display:block. Two stacked block-level things fall
   onto separate lines, so the icon rendered above the number instead of
   beside it. Mobile already has its own display:flex fix for this element
   at max-width:767px (mobile-optimize.css) and looks correct; this closes
   the matching gap for everything above that, where no such rule existed.
   ========================================================================== */
@media (min-width: 768px) {
  .topbar-phone {
    display: inline-flex !important;
    align-items: center;
    gap: 6px;
  }
}

/* ==========================================================================
   14. "Our Work" gallery -- hide the label/heading/description copy
   --------------------------------------------------------------------------
   The photos in this section aren't genuine completed jobs -- they're stock/
   placeholder images -- so the "Our Work / Roof Transformations" label,
   heading and description (which frame them as real work) are hidden here.
   The image grid itself is left in place as visual filler. Scoped to the
   one section containing .gallery-grid (unique on the homepage) so no other
   section-label/section-title/section-subtitle elsewhere on the site is
   affected.
   ========================================================================== */
.container:has(> .gallery-grid) > .section-label,
.container:has(> .gallery-grid) > .section-title,
.container:has(> .gallery-grid) > .section-subtitle {
  display: none;
}


/* ---- hero-layout.css ---- */
/* ==========================================================================
   Iron Shore Roofing — hero + page gutter layout
   --------------------------------------------------------------------------
   Fixes two related problems:

   1. Dead space down the left. The site container is capped at 1280px and
      centred, leaving ~320px empty each side on a 1920 screen. The logo, hero
      copy and every section below inherit it.

   2. The hero lead-form card sits on top of the house. `.hero-inner` uses
      `justify-content: space-between`, pinning the card to the container's
      right edge — but the artwork is *also* right-anchored, so the card and
      the house fight for the same space. Measured overlap before this file:
      391px @1920, 472px @1600, 589px @1366.

   THE GEOMETRY
   The artwork is 16:9, right-anchored, and its width is derived from the
   hero's height. The house occupies roughly the right 56% of the frame, so
   its left edge lands near `100vw - 660px` — and that edge slides LEFT as the
   window narrows. The usable "safe lane" to the left of the house therefore
   shrinks faster than the content in it, which is why one fixed arrangement
   cannot clear the house at every width.

   So the layout switches:
     · >= 1500px  copy and card side by side, both sized into the safe lane
     · < 1500px   card stacks beneath the copy, still hard left, still clear
                  of the house
     · <= 1023px  untouched — the existing tablet/mobile treatment already
                  stacks and is tuned separately

   Additive only. Loaded after coast-hero.css. No colour, type or content
   changes; nothing is restructured.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Reclaim the dead side margins, site-wide
   --------------------------------------------------------------------------
   Everything inside .container moves left together — header logo and nav, and
   every section on every page — so alignment stays consistent top to bottom.
   The min() keeps a comfortable gutter at narrower widths; capping at a flat
   1660px alone let the logo sit flush against the window edge at 1600.
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .container {
    max-width: min(1660px, calc(100vw - 96px));
  }
}

/* --------------------------------------------------------------------------
   2. Wide screens — copy and form side by side, inside the safe lane
   -------------------------------------------------------------------------- */
@media (min-width: 1500px) {
  .hero.ch-on .hero-inner {
    /* space-between is what threw the card onto the house. */
    justify-content: flex-start;
    align-items: center;
    gap: clamp(24px, 2vw, 44px);
    max-width: none;
    padding-left: clamp(24px, 2.6vw, 72px);
    padding-right: clamp(20px, 2vw, 48px);
  }

  /* Copy and card scale together with the viewport so the pair stays inside
     the lane instead of the card being pushed into the artwork. */
  .hero.ch-on .hero-content {
    flex: 0 1 auto;
    max-width: clamp(360px, 26vw, 560px);
  }

  .hero.ch-on .hero-form-card {
    flex: 0 1 auto;
    width: clamp(320px, 22vw, 400px);
    margin-left: 0;
    margin-right: 0;
  }
}

/* --------------------------------------------------------------------------
   3. 1024–1499 — same two columns, tightened
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) and (max-width: 1499px) {
  .hero.ch-on .hero-inner {
    justify-content: flex-start;
    align-items: center;
    gap: clamp(18px, 1.8vw, 30px);
    max-width: none;
    padding-left: clamp(20px, 2.4vw, 40px);
    padding-right: 20px;
  }

  .hero.ch-on .hero-content {
    flex: 0 1 auto;
    max-width: clamp(310px, 25vw, 400px);
  }

  .hero.ch-on .hero-form-card {
    flex: 0 1 auto;
    width: clamp(292px, 22vw, 336px);
    margin-left: 0;
    margin-right: 0;
  }

  /* In a narrowed column the headline was wrapping to four lines instead of
     three, which pushed the hero to 689px tall — and via the height/width
     coupling below, dragged the house left and re-created the collision.
     Sizing it to hold three lines keeps the hero short and the house right. */
  .hero.ch-on .hero-content h1 {
    font-size: clamp(34px, 3.4vw, 46px) !important;
  }

  /* The trust strip is 62px; 96px of reserved shelf was more slack than the
     geometry can afford here. */
  .hero.ch-on .hero-inner {
    padding-bottom: 80px;
  }
}





/* --------------------------------------------------------------------------
   4. Very wide screens — keep the copy from drifting off on its own
   -------------------------------------------------------------------------- */
@media (min-width: 2100px) {
  .hero.ch-on .hero-inner {
    padding-left: clamp(72px, 5vw, 140px);
  }
}


/* ---- lp-optimize.css ---- */
/* ==========================================================================
   Iron Shore Roofing — landing-page conversion layer (styles)
   --------------------------------------------------------------------------
   Companion to lp-optimize.js. Mobile is treated as the primary case because
   paid social traffic is overwhelmingly phones.

   Brand is untouched: same blue (#1a5fd4 / #3b7ef5), same orange CTA, same
   Barlow Condensed / Oswald / Open Sans, same square-cornered language. Only
   arrangement, emphasis and density change.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Enable the reordering
   --------------------------------------------------------------------------
   lp-optimize.js writes `order` onto each child of <main>; that only takes
   effect once main is a flex container.
   -------------------------------------------------------------------------- */
main.lp-ordered {
  display: flex;
  flex-direction: column;
}

/* ==========================================================================
   1. MOBILE — the priority case
   ========================================================================== */
@media (max-width: 1023px) {

  /* ---- Critical repair -------------------------------------------------
     The hero was laying the copy and the form out side by side on phones:
     the headline was crushed into a ~180px column and the form card ran off
     the right edge of the screen, unusable. Force a single column. */
  .hero.ch-on .hero-inner {
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    justify-content: flex-start !important;
    gap: 0 !important;
  }

  .hero.ch-on .hero-content {
    width: 100% !important;
    max-width: 100% !important;
    flex: 0 0 auto !important;
    padding-right: 0 !important;
  }

  .hero.ch-on .hero-form-card {
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
    flex: 0 0 auto !important;
    margin: 0 0 4px !important;
    box-sizing: border-box;
  }

  .hero.ch-on .hero-inner {
    padding-bottom: 18px !important;
  }
}

/* ==========================================================================
   1b. PHONES ONLY — band sizing and type scale
   --------------------------------------------------------------------------
   These are vw-derived, so they must not leak into tablet. Scoped to 1023px
   they made the scene band 46vw = 377px on an 820px tablet, which pushed the
   headline and form off the first screen entirely. The structural stacking
   above still applies to the whole sub-1024 range; only the sizing is here.
   ========================================================================== */
@media (max-width: 767px) {

  /* Every pixel above the form costs conversions on paid traffic, so the
     scene band, headline and supporting copy are all tightened. */
  .hero.ch-on .hero-inner {
    padding-top: calc(46vw + 14px) !important;
  }

  .hero.ch-on .ch-media {
    height: 46vw !important;
  }

  .hero.ch-on .hero-content h1 {
    font-size: clamp(30px, 8vw, 40px) !important;
    line-height: 1.02 !important;
    margin-bottom: 10px !important;
  }

  .hero.ch-on .ch-eyebrow {
    margin-bottom: 8px !important;
  }

  .hero.ch-on .hero-accent {
    margin-bottom: 10px !important;
  }

  .hero.ch-on .hero-subtitle {
    font-size: 15px !important;
    line-height: 1.45 !important;
    margin-bottom: 16px !important;
  }

  /* Two buttons across instead of stacked full-width: saves ~60px of scroll
     directly above the form without losing either action. */
  .hero.ch-on .hero-ctas {
    display: grid !important;
    grid-template-columns: 1fr 1fr !important;
    gap: 10px !important;
    margin-bottom: 16px !important;
  }

  .hero.ch-on .hero-ctas .btn-primary,
  .hero.ch-on .hero-ctas .btn-outline {
    width: 100% !important;
    padding: 14px 8px !important;
    font-size: 13px !important;
    text-align: center;
    box-sizing: border-box;
  }

  /* Trust strip sits under the form as reinforcement, not competition. */
  .hero.ch-on .ch-trustbar {
    margin-top: 16px !important;
  }
}

/* Small phones — reclaim a little more above the form. */
@media (max-width: 400px) {
  .hero.ch-on .hero-inner {
    padding-top: calc(43vw + 12px) !important;
  }

  .hero.ch-on .ch-media {
    height: 43vw !important;
  }

  .hero.ch-on .hero-ctas .btn-primary,
  .hero.ch-on .hero-ctas .btn-outline {
    font-size: 12px !important;
    letter-spacing: 0.2px;
  }
}

/* ==========================================================================
   2. The form card — the page's primary action
   ========================================================================== */
.hero-form-card {
  border: 1px solid rgba(59, 126, 245, 0.30);
  box-shadow: 0 24px 60px rgba(4, 8, 15, 0.55);
}

/* Reassurance under the card heading. */
.lp-reassure {
  margin: 8px 0 16px;
  font-size: 13px;
  line-height: 1.5;
  color: #9fb0c6;
}

/* Proof row under the submit button — last thing read before acting. */
.lp-formtrust {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin: 14px 0 0;
  padding: 12px 0 0;
  list-style: none;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
}

.lp-formtrust li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: Oswald, sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: #b7c4d4;
}

.lp-formtrust svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
  color: var(--color-primary-light, #3b7ef5);
}

@media (max-width: 400px) {
  .lp-formtrust {
    gap: 6px 12px;
  }

  .lp-formtrust li {
    font-size: 9.5px;
    letter-spacing: 0.8px;
  }
}

/* ==========================================================================
   3. Density — paid traffic should reach proof faster
   ========================================================================== */
@media (max-width: 1023px) {
  .section-padding {
    padding-top: 52px !important;
    padding-bottom: 52px !important;
  }

  .cta-band {
    padding-top: 48px !important;
    padding-bottom: 48px !important;
  }
}

/* The stat bar is the first credibility beat after the hero — give it more
   presence than a passing strip. */
.stat-bar .stat-value {
  letter-spacing: -0.5px;
}

@media (max-width: 767px) {
  .stat-bar .stat-label {
    font-size: 10px !important;
    letter-spacing: 1.2px !important;
  }
}

/* ==========================================================================
   4. Reduced motion
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .hero-form-card {
    transition: none !important;
  }
}


/* ==========================================================================
   Hero eyebrow legibility on the photo hero
   --------------------------------------------------------------------------
   The eyebrow was brand blue, which worked against the old video hero's flat
   navy panel. The current hero is a photograph whose sky is blue in exactly
   that corner, so blue-on-blue left the line close to unreadable. White with
   a soft shadow reads cleanly over any part of a photo.
   ========================================================================== */
.hero.ch-on .ch-eyebrow {
  color: #ffffff !important;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.65);
}


/* ---- stats-redesign.css ---- */
/* Iron Shore Roofing — Stat bar redesign
   --------------------------------------------------------------------------
   Replaces the flat solid-blue "500+ / 60+ / 100% / 10-Yr" strip with a
   more modern, dimensional treatment: a diagonal brand-blue gradient with a
   soft corner glow, individual glass-panel stat cards (instead of a plain
   row with hairline dividers), and a small icon per stat. Numerals are
   larger and tighter-tracked for more visual weight.

   The count-up animation itself lives in the React bundle and fires on
   scroll into view exactly as before — this file is presentation only, no
   markup or animation logic is touched.
   ========================================================================== */

.stat-bar {
  background: linear-gradient(135deg, var(--color-primary-light, #3b7ef5) 0%, var(--color-primary, #1a5fd4) 58%, #0e3a8f 100%);
  padding: 56px 0;
  position: relative;
  overflow: hidden;
}

/* Soft glow in the top-left corner for depth, instead of a flat fill. */
.stat-bar::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 140% at 12% 0%, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0) 60%);
  pointer-events: none;
}

/* Soft vignette so the bar meets the sections above/below gently instead of
   a hard flat-color cut. */
.stat-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 26px 22px -26px rgba(0,0,0,0.32), inset 0 -26px 22px -26px rgba(0,0,0,0.32);
  pointer-events: none;
}

.stat-bar-inner {
  position: relative;
  z-index: 1;
  align-items: stretch !important;
}

/* Individual glass cards replace the old hairline-divider row. */
.stat-bar .stat-item + .stat-item {
  border-left: none;
}

.stat-item {
  position: relative;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.18);
  padding: 26px 30px 22px;
  transition: transform 0.25s ease, background 0.25s ease, border-color 0.25s ease;
}

@media (hover: hover) {
  .stat-item:hover {
    transform: translateY(-3px);
    background: rgba(255,255,255,0.12);
    border-color: rgba(255,255,255,0.34);
  }
}

/* One small icon per stat, matched to what it represents. Plain white
   glyphs at low-key opacity so they read as accents, not decoration. */
.stat-item::before {
  content: "";
  display: block;
  width: 26px;
  height: 26px;
  margin: 0 auto 12px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  opacity: 0.92;
}

/* Roofs Completed — house */
.stat-item:nth-child(1)::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 11l9-8 9 8'/%3E%3Cpath d='M5 10v10a1 1 0 0 0 1 1h4v-6h4v6h4a1 1 0 0 0 1-1V10'/%3E%3C/svg%3E");
}

/* Towns Served — map pin */
.stat-item:nth-child(2)::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22s7-7.4 7-12a7 7 0 1 0-14 0c0 4.6 7 12 7 12z'/%3E%3Ccircle cx='12' cy='10' r='2.5'/%3E%3C/svg%3E");
}

/* 24-hour response — clock */
.stat-item:nth-child(3)::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E");
}

/* 10-year full-replacement warranty — shield check */
.stat-item:nth-child(4)::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2l8 4v6c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10V6l8-4z'/%3E%3Cpath d='M9 12l2 2 4-4'/%3E%3C/svg%3E");
}

.stat-bar .stat-value {
  font-size: 2.5rem;
  letter-spacing: -0.02em;
  text-shadow: 0 2px 14px rgba(0,0,0,0.22);
}

.stat-bar .stat-label {
  color: rgba(255,255,255,0.84);
  margin-top: 6px;
}

/* The bundle paints 500+ / 60+ / 100% / 30-Yr before the rewrite. Keep
   that frame hidden. lp-optimize.js adds ish-stats-ready once the four
   confirmed lines are in place. Invented review and brand cards are hidden
   the same way, without detaching React's nodes. */
.stat-bar:not(.ish-stats-ready) {
  visibility: hidden;
}

.ish-claim-hidden {
  display: none !important;
}

@media (max-width: 767px) {
  .stat-bar { padding: 24px 0; }
  .stat-bar-inner { gap: 8px !important; }
  .stat-item {
    width: 100%;
    padding: 12px 16px 10px;
  }
  .stat-item::before {
    width: 18px;
    height: 18px;
    margin: 0 auto 6px;
  }
  .stat-bar .stat-value { font-size: clamp(19px, 5.5vw, 22px) !important; }
  .stat-bar .stat-label { margin-top: 1px; }
}
/* ---- town-pages.css ---- */
/* Layout for the four Suffolk town pages injected by town-pages.js.
   Scoped to that block so the existing town pages are unchanged. */
/* Keep the footer hidden with the page body until the town copy is in
   place. A visible footer jumps down the screen once that copy arrives. */
html.ish-town-pending main,
html.ish-town-pending .site-footer { visibility: hidden; }
html.ish-town-ready main,
html.ish-town-ready .site-footer { visibility: visible; }

.ish-town-root h2 {
  margin: 1.5em 0 0.45em;
  font-size: 1.55rem;
}
.ish-town-root h3 {
  margin: 1.15em 0 0.35em;
  font-size: 1.08rem;
}
.ish-town-root p,
.ish-town-root li {
  line-height: 1.65;
}
.ish-town-root ul {
  margin: 0.35em 0 1em;
  padding-left: 1.2em;
}
.ish-town-root a { color: #7fb0ff; }
.ish-town-root table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.8em 0 1.2em;
  font-size: 0.95rem;
}
.ish-town-root th,
.ish-town-root td {
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  text-align: left;
  padding: 8px 10px;
  vertical-align: top;
}
.ish-town-root .sidebar-trust { list-style: none; padding-left: 0; }
.ish-town-root .sidebar-trust li { margin: 0 0 8px; }


/* ---- license-line.css ---- */
/* Keeps the license number on one line beside the copyright. */
.footer-bottom .ish-license {
  white-space: nowrap;
}

.ish-license-contact {
  margin: 6px 0 0;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--color-text-dim, #8998ad);
}


/* ---- service-pages.css ---- */
/* ==========================================================================
   Iron Shore Roofing — service page differentiation
   --------------------------------------------------------------------------
   The five /services/* pages render from one shared template (identical
   DOM structure, identical section order) with only copy and one
   background image differing between them. This file gives each page its
   own accent color, hero badge treatment, and a couple of structural
   variations so they stop reading as copy-pasted.

   Scoping rule: every selector here is either `.sp-*` (new elements this
   feature adds) or prefixed `body[data-service="x"] main ...`. main is a
   sibling of .topbar / nav.main-nav / .mobile-menu / footer.site-footer,
   never their ancestor, so nothing here can reach the nav, mobile menu, or
   footer even via inherited custom properties. See service-pages.js for
   the JS half that sets data-service and injects the one-off elements.
   ========================================================================== */

/* ---- Hero photo overlay tint, per page (layered over the existing photo,
   the photo itself is untouched) ---- */
body[data-service] .hero-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,.15) 0%, rgba(10,14,22,.55) 100%);
}


/* ---- Full reroofs: benefit cards become a left-accent stacked list
   instead of the shared 2x2 grid — a more "spec sheet" feel matching the
   code-compliance / built-for-decades copy. ---- */
body[data-service="reroof"] .benefits-grid {
  display: block;
}
body[data-service="reroof"] .benefit-card {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  border: 1px solid rgba(255,255,255,0.07);
  border-left: 3px solid var(--color-accent);
  margin-bottom: 1px;
}
body[data-service="reroof"] .benefit-number {
  flex: 0 0 auto;
}

/* ---- Roof repair: tighter cards, snappier feel ---- */
body[data-service="repair"] .benefit-card {
  padding: 20px 18px;
}

/* ---- Storm damage: note that the homeowner deals with their carrier.
   This page only. ---- */
.sp-insurance-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
  margin: 24px 0 8px;
  padding: 16px 20px;
  background: rgba(220, 38, 38, 0.08);
  border: 1px solid rgba(220, 38, 38, 0.3);
  border-left: 3px solid var(--color-accent);
}
.sp-insurance-strip-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.6);
}
.sp-insurance-carrier {
  font-size: 14px;
  font-weight: 600;
  color: #fff;
}

/* ---- Free inspections: airier lead paragraph, nods to the "no pressure"
   tone ---- */
body[data-service="inspection"] .detail-content > p:first-of-type {
  font-size: 19px;
  line-height: 1.7;
}

/* ---- Full reroofs: lead with "What's Included" and "Why Choose" before
   Key Benefits, via flex order rather than a JS DOM move. A JS-based
   reorder was tried first (see service-pages.js) but leaked onto other
   service pages: all five /services/* routes share one React-rendered
   .detail-content element, and React reuses that same physical node across
   routes without restoring the child order a script left it in. CSS order
   sidesteps that entirely -- it's re-evaluated per data-service value with
   no persistent DOM mutation, so it can never leak onto another route.
   Source order of main .detail-content's children on every service page:
   1-3: intro <p> tags, 4: <h2>Key Benefits</h2>, 5: <div.benefits-grid>,
   6: <h2>What's Included</h2>, 7: <div.checklist-card>,
   8: <h2>Why Choose Iron Shore</h2>, 9: <div> (why-choose content). */
body[data-service="reroof"] main .detail-content {
  display: flex;
  flex-direction: column;
}
body[data-service="reroof"] main .detail-content > :nth-child(1) { order: 1; }
body[data-service="reroof"] main .detail-content > :nth-child(2) { order: 2; }
body[data-service="reroof"] main .detail-content > :nth-child(3) { order: 3; }
body[data-service="reroof"] main .detail-content > :nth-child(4) { order: 8; }
body[data-service="reroof"] main .detail-content > :nth-child(5) { order: 9; }
body[data-service="reroof"] main .detail-content > :nth-child(6) { order: 4; }
body[data-service="reroof"] main .detail-content > :nth-child(7) { order: 5; }
body[data-service="reroof"] main .detail-content > :nth-child(8) { order: 6; }
body[data-service="reroof"] main .detail-content > :nth-child(9) { order: 7; }

/* ==========================================================================
   SERVICE PAGES - MOBILE OPTIMIZATION            (added 2026-08-06)
   Scope: html.is-inner  - class is set from the route by before-after.js.
   If that script fails, none of this applies: safe no-op fallback.

   Fixes
     1. Hero painted pure black until the photo finally arrived
     2. /services card grid stuck at 2 columns on phones (inline style
        from the React bundle out-ranks every media query -> !important)
     3. Hero eyebrow/subtitle unreadable + badly wrapped on phones
   ========================================================================== */

/* --- 1. Hero never paints black ---------------------------------------- */
html.is-inner .hero { background-color: #0b1421; }

html.is-inner .hero-bg {
  background-color: #0b1421;
  background-position: 50% 45%;
  background-size: cover;
  background-repeat: no-repeat;
}

/* --- 2. Legibility scrim (hero-bg is z-index:0, .container is z-index:1) */
html.is-inner .hero-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(7,14,24,.34) 0%, rgba(7,14,24,.14) 45%, rgba(7,14,24,.52) 100%),
    linear-gradient(90deg,  rgba(7,14,24,.56) 0%, rgba(7,14,24,.16) 55%, rgba(7,14,24,0) 100%);
}

/* --- 3. Phones ---------------------------------------------------------- */
@media (max-width: 900px) {

  html.is-inner .hero-bg::after {
    background: linear-gradient(180deg, rgba(7,14,24,.50) 0%, rgba(7,14,24,.34) 40%, rgba(7,14,24,.62) 100%);
  }

  html.is-inner .hero {
    min-height: 300px !important;
    padding: 34px 0 38px !important;
    display: flex;
    align-items: center;
  }
  html.is-inner .hero > .container { width: 100%; }

  html.is-inner .hero .breadcrumb {
    font-size: 12px !important;
    letter-spacing: .04em;
    margin-bottom: 12px !important;
    color: rgba(255,255,255,.70) !important;
  }
  html.is-inner .hero .breadcrumb span { color: inherit !important; }
  html.is-inner .hero .breadcrumb a    { color: #8ab4ff !important; }

  html.is-inner .hero h1 {
    font-size: clamp(26px, 7.4vw, 34px) !important;
    line-height: 1.1 !important;
    margin: 0 0 12px !important;
    text-wrap: balance;
    text-shadow: 0 2px 16px rgba(0,0,0,.55);
  }

  html.is-inner .hero .hero-subtitle {
    color: #e8eef8 !important;
    font-size: 15px !important;
    line-height: 1.5 !important;
    max-width: 33ch;
    margin: 0 !important;
    text-shadow: 0 1px 12px rgba(0,0,0,.65);
  }

  /* --- 4. The 2-column grid bug --------------------------------------- */
  html.is-inner .services-grid {
    grid-template-columns: 1fr !important;
    gap: 16px !important;
  }
  html.is-inner .featured-service-card { grid-template-columns: 1fr !important; }

  html.is-inner .grid-service-card > img,
  html.is-inner .featured-service-image img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    display: block;
  }

  html.is-inner .grid-service-card-body,
  html.is-inner .featured-service-body { padding: 18px 16px 20px !important; }

  html.is-inner .grid-service-card-body > div:first-child {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
  }
  html.is-inner .grid-service-card-body > div:first-child > span { flex: 0 0 auto; }

  html.is-inner .grid-service-card-body h3,
  html.is-inner .featured-service-body h3 {
    font-size: 19px !important;
    line-height: 1.15 !important;
    margin: 0 !important;
    overflow-wrap: anywhere;
  }

  html.is-inner .grid-service-card-body p,
  html.is-inner .featured-service-body p {
    font-size: 14.5px !important;
    line-height: 1.55 !important;
    margin: 0 0 14px !important;
  }

  html.is-inner .service-tags {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 8px !important;
    margin-bottom: 16px !important;
  }
  html.is-inner .service-tag {
    font-size: 12.5px !important;
    white-space: nowrap;
    padding: 6px 10px !important;
  }

  html.is-inner .service-card-link,
  html.is-inner .featured-service-body .btn-primary {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }
  html.is-inner .featured-service-body .btn-primary { width: 100%; justify-content: center; }
}

/* --- 5. Hero copy contrast on tablet/desktop too -----------------------
   The breadcrumb (#3e4f65) and subtitle (#8998ad) were set for a dark
   panel, not for sitting directly on a sunlit photo. Colour only - the
   desktop type scale and spacing are left exactly as they were.
   (desktop legibility) */
@media (min-width: 901px) {
  html.is-inner .hero .breadcrumb        { color: rgba(255,255,255,.72) !important; }
  html.is-inner .hero .breadcrumb span   { color: inherit !important; }
  html.is-inner .hero .breadcrumb a      { color: #8ab4ff !important; }
  html.is-inner .hero h1                 { text-shadow: 0 2px 18px rgba(0,0,0,.5); }
  html.is-inner .hero .hero-subtitle {
    color: #dde6f3 !important;
    text-shadow: 0 1px 12px rgba(0,0,0,.55);
  }
}


/* ==========================================================================
   TEXT-ONLY HERO - everywhere except the home page          (2026-08-06)

   Final call, and the right one: there is no image in these heroes any more,
   and no graphic standing in for one either. Just the heading and the line
   under it, on the page's own background.

   Every previous attempt tried to make the picture arrive sooner - smaller
   files, cropping, preloads, inline previews, a CSS graphic, a pre-render
   shell. All of it kept the same failure mode: a band that is empty until
   something finishes. Text was never the slow part; it is in the markup and
   paints immediately. So the band is gone rather than filled.

   .hero-bg is display:none, so its image is never requested at all.
   Scoped to html.is-inner, set by index.html on every route change including
   client-side navigation. The home page never gets that class and is
   completely untouched.
   ========================================================================== */

/* the image layer is removed outright - nothing to request, nothing to wait on */
html.is-inner .hero-bg { display: none !important; }

html.is-inner .hero {
  background: none !important;
  background-color: transparent !important;
  min-height: 0 !important;
  padding: 54px 0 40px !important;
  display: block !important;
  border-bottom: 1px solid rgba(255,255,255,.09);
}

html.is-inner .hero > .container { width: 100%; }

html.is-inner .hero .breadcrumb {
  font-size: 12.5px !important;
  letter-spacing: .04em;
  margin-bottom: 14px !important;
  color: rgba(255,255,255,.55) !important;
  text-shadow: none !important;
}
html.is-inner .hero .breadcrumb span { color: inherit !important; }
html.is-inner .hero .breadcrumb a    { color: #7fb0ff !important; }

html.is-inner .hero h1 {
  color: #fff !important;
  font-size: clamp(30px, 4.4vw, 52px) !important;
  line-height: 1.06 !important;
  margin: 0 0 14px !important;
  text-shadow: none !important;
  text-wrap: balance;
}

html.is-inner .hero .hero-subtitle {
  color: #b9c7db !important;
  font-size: clamp(15px, 1.5vw, 19px) !important;
  line-height: 1.5 !important;
  max-width: 60ch;
  margin: 0 !important;
  text-shadow: none !important;
}

@media (max-width: 900px) {
  html.is-inner .hero { padding: 30px 0 26px !important; }
  html.is-inner .hero h1 { font-size: clamp(27px, 7.4vw, 34px) !important; }
  html.is-inner .hero .hero-subtitle { font-size: 15px !important; max-width: 40ch; }
}

/* --- the hero section is retired on inner pages -------------------------
   Taken out of layout and paint entirely. The title and subtitle now live
   in the first content section instead (see PAGE HEAD RELOCATION in
   before-after.js). display:none rather than removal keeps React's tree
   intact. The home page is untouched.                                     */
html.is-inner section.hero { display: none !important; }

/* --- page head: photo panel + service emblem ----------------------------
   Two panels of equal height inside the content section. Left: the photo,
   with the heading sitting on top of it over a scrim. Right: an inline-SVG
   emblem for whatever that page sells.

   Both panels carry a gradient of their own, so the block looks complete
   before the photo decodes - it can degrade to a branded panel, never to an
   empty rectangle. The emblem costs no request at all.                     */
.isr-pagehead {
  /* the host container is sometimes itself a grid (About uses .story-grid,
     two columns). Without this the head becomes a grid ITEM and gets
     squeezed into one cell instead of spanning the section. */
  grid-column: 1 / -1;
  width: 100%;

  display: grid;
  grid-template-columns: 1.55fr 1fr;
  gap: 18px;
  align-items: stretch;
  margin: 0 0 46px;
  min-height: 400px;
}

/* ---------- left: photo with the heading over it ---------- */
.isr-ph-left {
  position: relative;
  overflow: hidden;
  border-radius: 12px;
  display: flex;
  align-items: center;
  padding: 48px 50px;
  border: 1px solid rgba(255,255,255,.10);
  background:
    radial-gradient(120% 140% at 12% 50%, rgba(26,95,212,.45) 0%, rgba(26,95,212,0) 68%),
    linear-gradient(150deg, #122947 0%, #0b1830 60%, #08111d 100%);
}

.isr-ph-photo {
  position: absolute;
  inset: 0;
  background-position: 50% 45%;
  background-size: cover;
  background-repeat: no-repeat;
  z-index: 0;
}

/* scrim so the heading stays readable on any photo */
.isr-ph-left::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(90deg, rgba(6,13,23,.90) 0%, rgba(6,13,23,.72) 48%, rgba(6,13,23,.42) 100%),
    linear-gradient(180deg, rgba(6,13,23,.25) 0%, rgba(6,13,23,.55) 100%);
}

.isr-ph-copy { position: relative; z-index: 2; min-width: 0; }

.isr-ph-eyebrow {
  display: inline-block;
  font-size: 12px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: #6ea6ff; margin-bottom: 12px;
}
.isr-ph-eyebrow::before {
  content: ""; display: inline-block;
  width: 26px; height: 2px; background: #1a5fd4;
  vertical-align: middle; margin-right: 10px;
}

.isr-pagehead h1 {
  color: #fff;
  font-size: clamp(30px, 3.9vw, 48px);
  line-height: 1.04;
  margin: 0 0 12px;
  text-wrap: balance;
  text-shadow: 0 2px 18px rgba(0,0,0,.5);
}
.isr-pagehead h1 .isr-ph-b { color: #4d94ff; }

.isr-ph-sub {
  color: #cfdcee;
  font-size: clamp(15px, 1.4vw, 18px);
  line-height: 1.55;
  max-width: 46ch;
  margin: 0;
  text-shadow: 0 1px 12px rgba(0,0,0,.55);
}

.isr-ph-rule {
  display: block; width: 74px; height: 3px; margin-top: 18px;
  background: linear-gradient(90deg, #1a5fd4, #e86a1a); border-radius: 2px;
}

/* ---------- right: service emblem, same height ---------- */
.isr-ph-emblem {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 18px 24px;
  text-align: center;
}

.isr-ph-emblem-art { position: relative; z-index: 1; display: block; color: #4d94ff; }
.isr-ph-emblem-art svg { width: 128px; height: 128px; display: block; }

.isr-ph-emblem-label {
  position: relative; z-index: 1;
  color: #fff;
  font-size: 14px; font-weight: 700;
  letter-spacing: .13em; text-transform: uppercase;
}

/* the service's key selling point, under the emblem */
.isr-ph-emblem-point {
  position: relative; z-index: 1;
  display: block;
  color: #97a9c2;
  font-size: 14.5px;
  line-height: 1.55;
  max-width: 30ch;
  margin-top: -4px;
}

/* short accent rule tying the emblem to the brand */
.isr-ph-emblem-label::after {
  content: "";
  display: block;
  width: 40px; height: 2px;
  margin: 12px auto 0;
  background: linear-gradient(90deg, #1a5fd4, #e86a1a);
  border-radius: 2px;
}

@media (max-width: 900px) {
  .isr-pagehead {
    grid-template-columns: 1fr;
    gap: 12px;
    margin-bottom: 30px;
    min-height: 0;
  }
  .isr-ph-left { padding: 30px 22px; min-height: 250px; }
  .isr-pagehead h1 { font-size: clamp(27px, 7.4vw, 34px); }
  .isr-ph-sub { font-size: 15px; max-width: 40ch; }
  .isr-ph-emblem { padding: 20px 16px 4px; gap: 10px; }
  .isr-ph-emblem-art svg { width: 76px; height: 76px; }
  .isr-ph-emblem-label { font-size: 13px; }
  .isr-ph-emblem-point { font-size: 14px; max-width: 34ch; }
}

/* ==========================================================================
   ALL SERVICES - mobile                                     (2026-08-06)

   Note on the selectors above: they were originally written against
   .rt-svc. When the page bootstrap was rewritten the marker class became
   .is-inner, which silently disabled all 36 of those rules - including the
   one-column grid fix - and this page reverted to two 159px columns on a
   phone. They are now all .is-inner. Anything added here uses the same hook.

   The React bundle writes grid-template-columns inline on .services-grid,
   which outranks any plain rule, so !important is required to beat it.
   ========================================================================== */
@media (max-width: 900px) {

  /* the inline 2-column value from the bundle */
  html.is-inner .services-grid {
    grid-template-columns: 1fr !important;
    gap: 16px !important;
  }
  html.is-inner .featured-service-card {
    grid-template-columns: 1fr !important;
  }

  /* cards */
  html.is-inner .grid-service-card,
  html.is-inner .featured-service-card {
    border-radius: 12px;
    overflow: hidden;
  }
  html.is-inner .grid-service-card > img,
  html.is-inner .featured-service-image img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    display: block;
  }
  html.is-inner .grid-service-card-body,
  html.is-inner .featured-service-body { padding: 18px 16px 20px !important; }

  /* icon + title share a flex row; at 160px the h3 broke onto four lines */
  html.is-inner .grid-service-card-body > div:first-child {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
  }
  html.is-inner .grid-service-card-body > div:first-child > span { flex: 0 0 auto; }

  html.is-inner .grid-service-card-body h3,
  html.is-inner .featured-service-body h3 {
    font-size: 19px !important;
    line-height: 1.15 !important;
    margin: 0 !important;
    overflow-wrap: anywhere;
  }
  html.is-inner .grid-service-card-body p,
  html.is-inner .featured-service-body p {
    font-size: 14.5px !important;
    line-height: 1.55 !important;
    margin: 0 0 14px !important;
  }

  html.is-inner .service-tags {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 8px !important;
    margin-bottom: 16px !important;
  }
  html.is-inner .service-tag {
    font-size: 12.5px !important;
    white-space: nowrap;
    padding: 6px 10px !important;
  }

  /* tap targets */
  html.is-inner .service-card-link,
  html.is-inner .featured-service-body .btn-primary {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }
  html.is-inner .featured-service-body .btn-primary {
    width: 100%;
    justify-content: center;
  }

  /* section rhythm on a phone */
  html.is-inner .section-padding { padding-top: 34px !important; padding-bottom: 34px !important; }
  html.is-inner .products-grid { grid-template-columns: 1fr !important; gap: 14px !important; }
}


/* ---- trust-section.css ---- */
/* Iron Shore Roofing -- homepage trust/values section, inserted directly
   below the hero by trust-section.js. Reuses the site's existing
   .section-label / .section-title / .section-subtitle typography classes
   for visual consistency, and var(--color-accent) for the brand color.
   Every selector here is scoped to .trust-values / .tb-* (new elements
   this feature adds) -- never touches nav, footer, or any existing rule. */

.trust-values {
  padding: 96px 0;
  background: #0c0f18;
  position: relative;
  overflow: hidden;
}

.trust-values-inner {
  display: flex;
  align-items: center;
  gap: 64px;
  max-width: 1180px;
  margin: 0 auto;
}

.trust-values-copy {
  flex: 1 1 480px;
}

.trust-values-copy .section-title {
  margin-bottom: 20px;
}

.trust-values-copy .section-subtitle {
  max-width: 560px;
}

.trust-values-badge {
  flex: 0 0 260px;
  display: flex;
  justify-content: center;
}

.trust-badge-svg {
  width: 240px;
  height: 240px;
}

.tb-ring-outer {
  fill: none;
  stroke: var(--color-accent, #1a5fd4);
  stroke-width: 1;
  opacity: 0.3;
}

.tb-ring-inner {
  fill: none;
  stroke: var(--color-accent, #1a5fd4);
  stroke-width: 1.5;
  opacity: 0.55;
}

.tb-orbit-group {
  transform-origin: 100px 100px;
  animation: tb-spin 45s linear infinite;
}

.tb-orbit-text {
  fill: var(--color-accent, #1a5fd4);
  font: 700 8px 'Oswald', sans-serif;
  letter-spacing: 2px;
}

.tb-shield {
  fill: rgba(26, 95, 212, 0.12);
  stroke: var(--color-accent, #1a5fd4);
  stroke-width: 3;
}

.tb-check {
  stroke: var(--color-accent, #1a5fd4);
}

@keyframes tb-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .tb-orbit-group { animation: none; }
}

@media (max-width: 900px) {
  .trust-values { padding: 20px 0; }
  .trust-values-inner { flex-direction: column; text-align: center; gap: 10px; }
  .trust-values-copy {
    /* Same cross-axis flex-basis bug as the badge wrapper below: 480px was
       meant as a WIDTH cap for the desktop row layout and becomes a 480px
       minimum HEIGHT once flex-direction switches to column, which was the
       real source of the huge empty gap above the badge on mobile. */
    flex: 1 1 auto;
    width: 100%;
  }
  .trust-values-copy .section-label { font-size: 10px; margin-bottom: 2px; }
  .trust-values-copy .section-title {
    font-size: 17px !important;
    line-height: 1.15 !important;
    margin-bottom: 5px;
  }
  .trust-values-copy .section-title br { display: none; }
  .trust-values-copy .section-subtitle {
    margin-left: auto;
    margin-right: auto;
    font-size: 12px;
    line-height: 1.45;
    max-width: 320px;
  }
  .trust-values-badge {
    /* flex-basis of 260px (set for the desktop row layout, where it fixes
       the badge column's WIDTH) gets reinterpreted as a HEIGHT once
       flex-direction switches to column here -- reset it so the wrapper
       sizes to its actual (now much smaller) content instead of forcing
       260px of empty vertical space. */
    flex: 0 0 auto;
  }
  .trust-badge-svg { width: 56px; height: 56px; }
}


/* ---- warranty-section.css ---- */
/* Iron Shore Roofing -- homepage "10-Year Workmanship Warranty" section,
   inserted directly after the "Why Iron Shore" section by
   warranty-section.js. The wrapper reuses the site's existing
   .section-padding / .section-darker / .container / .section-label /
   .section-title / .section-subtitle / .btn-outline classes as-is for
   layout, color, and type -- every rule below is scoped to .warranty-* /
   .warranty-section (new elements this feature adds) and only covers what
   those shared classes don't already handle: the highlighted "10-Year",
   the covered-items list, the secondary paragraphs, the CTA button spacing,
   and the fine print. Never touches nav, footer, or any existing rule. */

.warranty-content {
  max-width: 760px;
  margin-top: 40px;
}

/* "10-Year" made prominent the same way the hero already highlights its
   second line (white headline, one phrase in the brand's lighter accent
   blue) -- no new graphic, no separate stat callout, just the existing
   in-heading color technique already used elsewhere on this page. */
.warranty-highlight {
  color: var(--color-primary-light, #3b7ef5);
}

.warranty-text {
  color: rgba(255, 255, 255, 0.86);
  font-family: var(--font-body, "Open Sans", sans-serif);
  font-size: 16px;
  line-height: 1.7;
  margin: 0 0 20px;
}

/* Muted gray already used for .section-subtitle and card copy. */
.warranty-text-secondary {
  color: var(--color-text-muted, #8998ad);
  font-size: 14.5px;
}

.warranty-covered-heading {
  color: var(--color-text, #fff);
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 900;
  font-size: 21px;
  line-height: 1.2;
  margin: 8px 0 14px;
}

.warranty-covered-list {
  list-style: none;
  margin: 0 0 28px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.warranty-covered-list li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  color: rgba(255, 255, 255, 0.86);
  font-family: var(--font-body, "Open Sans", sans-serif);
  font-size: 15px;
  line-height: 1.55;
}

.warranty-check {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-top: 3px;
  color: var(--color-primary-light, #3b7ef5);
}

/* Fine print: same muted gray already used for .section-subtitle / card
   text sitewide (an already-vetted contrast level against the dark
   background), just smaller, per spec. */
.warranty-fineprint {
  color: var(--color-text-muted, #8998ad);
  font-size: 13px;
  line-height: 1.6;
  max-width: 720px;
  margin: 0;
}

@media (max-width: 640px) {
  .warranty-content { margin-top: 28px; }
  .warranty-text { font-size: 15px; }
  .warranty-covered-heading { font-size: 19px; margin-top: 4px; }
  .warranty-covered-list { gap: 10px; margin-bottom: 24px; }
  .warranty-covered-list li { font-size: 14.5px; }
  .warranty-fineprint { font-size: 12.5px; }
}


/* ---- about-trust.css ---- */
/* Iron Shore Roofing -- About page: featured Trust & Transparency lead-in,
   inserted by about-trust.js directly above the existing three-card values
   grid. Reuses .section-* typography tokens where practical and matches
   the existing .value-card / .value-icon color language (dark card bg,
   brand blue icon badge) so it reads as part of the same design system.
   Selectors are scoped to .trust-lead / .tl-* -- never touches nav,
   footer, or any existing rule. */

.trust-lead {
  display: flex;
  align-items: center;
  gap: 40px;
  background: rgb(17, 24, 39);
  border: 1px solid rgba(255, 255, 255, 0.07);
  padding: 36px 40px;
}

.trust-lead-art {
  flex: 0 0 auto;
}

.trust-lead-badge {
  position: relative;
  width: 96px;
  height: 96px;
  border-radius: 20px;
  background: var(--color-accent, #1a5fd4);
  display: flex;
  align-items: center;
  justify-content: center;
}

.tl-handshake {
  width: 52px;
  height: 52px;
  color: #fff;
}

.trust-lead-doc {
  position: absolute;
  bottom: -10px;
  right: -10px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgb(17, 24, 39);
  border: 2px solid var(--color-accent, #1a5fd4);
  display: flex;
  align-items: center;
  justify-content: center;
}

.trust-lead-doc svg {
  width: 22px;
  height: 22px;
  color: var(--color-accent, #1a5fd4);
}

.trust-lead-copy {
  flex: 1 1 auto;
}

.trust-lead-kicker {
  font-family: 'Oswald', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-accent, #1a5fd4);
  margin: 0 0 6px;
}

.trust-lead-title {
  font-family: 'Barlow Condensed', sans-serif;
  font-weight: 900;
  font-size: 28px;
  color: #fff;
  margin: 0 0 10px;
}

.trust-lead-text {
  font-family: 'Open Sans', sans-serif;
  font-size: 15px;
  line-height: 1.7;
  color: rgb(137, 152, 173);
  margin: 0;
  max-width: 640px;
}

@media (max-width: 700px) {
  .trust-lead {
    flex-direction: column;
    text-align: center;
    padding: 28px 24px;
    gap: 20px;
  }
  .trust-lead-text {
    max-width: none;
  }
}

