/* ============================================================
   DFI Remodeling, shared site chrome
   Header, footer and cross-page section patterns.
   Loaded after base.css on every page.
   ============================================================ */

/* ---------- Header ----------
   Black band. logo.png is black-background artwork with a white star
   and an azure wordmark, so on the old off-white header it rendered as
   a black box. On the ink band it sits on its own field, and the
   header now bookends the footer, which was already ink. */
.site-header{
  position:sticky; top:0; z-index:50;
  background:rgba(13,15,18,.94);
  backdrop-filter:saturate(160%) blur(14px);
  border-bottom:1px solid rgba(255,255,255,.10);
}
/* Azure hairline under the header, the first dimension line on the page */
.site-header::after{
  content:""; position:absolute; left:0; right:0; bottom:-1px;
  height:2px; background:var(--accent);
}
.header-inner{position:relative; display:flex; align-items:center; gap:var(--space-m); min-height:76px;}
.logo{display:flex; align-items:center; gap:.6rem; text-decoration:none; margin-right:auto;}
.logo img{height:42px; width:auto;}
.logo-text{font-weight:700; font-size:1.05rem; color:#fff; letter-spacing:-.03em; line-height:1.05; font-stretch:112%;}
.logo-text span{
  display:block; font-family:var(--font-mono); font-size:.6rem; font-weight:500;
  letter-spacing:.16em; color:var(--accent); font-stretch:100%;
}
.nav{display:none; gap:1.6rem;}
.nav a{color:rgba(255,255,255,.78); text-decoration:none; font-size:.94rem; font-weight:500; transition:color var(--dur) var(--ease);}
.nav a:hover,.nav a[aria-current="page"]{color:var(--accent);}
.nav a[aria-current="page"]{font-weight:600;}
.header-phone{display:none; align-items:center; gap:.45rem; font-weight:600; color:#fff; text-decoration:none; font-size:.95rem;}
.header-phone:hover{color:var(--accent);}
.nav-toggle{
  display:inline-grid; place-items:center; width:48px; height:48px; flex:none;
  border:1px solid rgba(255,255,255,.24); border-radius:var(--radius);
  background:transparent; color:#fff; cursor:pointer;
  transition:border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.nav-toggle:hover{border-color:var(--accent); background:rgba(255,255,255,.06);}
.nav-toggle .x{display:none;}
.nav-toggle[aria-expanded="true"] .x{display:block;}
.nav-toggle[aria-expanded="true"] .bars{display:none;}

@media (min-width:1000px){
  .nav{display:flex;} .header-phone{display:inline-flex;}
  .header-cta-sm{display:none;} .nav-toggle{display:none;}
}
@media (max-width:999px){
  /* Drops out of the black header, so it stays on the ink field */
  .nav{
    position:absolute; left:0; right:0; top:100%;
    flex-direction:column; gap:0;
    background:var(--ink);
    border-bottom:2px solid var(--accent);
    box-shadow:var(--shadow-lg);
    padding:.25rem clamp(1.25rem,5vw,4rem) .75rem;
  }
  .nav[data-open="true"]{display:flex;}
  .nav a{padding:.95rem .25rem; border-bottom:1px solid rgba(255,255,255,.10); font-size:1rem;}
  .nav a:last-child{border-bottom:0;}
  .header-cta-sm{margin-left:auto;}
}
@media (max-width:520px){
  .header-inner{gap:.6rem;}
  .logo{gap:.45rem;} .logo img{height:36px;}
  .logo-text{font-size:.92rem; white-space:nowrap;}
  .logo-text span{display:none;}
  .header-cta-sm{white-space:nowrap; padding:0 .85rem; font-size:.9rem;}
  .nav-toggle{width:46px; height:46px;}
}

/* ---------- Page header band (interior pages) ---------- */
.page-head{
  background:var(--steel-100);
  border-bottom:1px solid var(--steel-200);
  padding-block:clamp(2.5rem,5vw,4.5rem);
}
/* Heading and lede sit side by side on wide screens. Stacked, the band left
   the right half of every interior page empty. */
/* minmax(0,...) on every column. A plain 1fr has an automatic minimum of
   min-content, so one long unbreakable heading word widens the whole grid and
   pushes the page sideways. This was overflowing services and gallery by 22px
   on a phone. */
.page-head-grid{display:grid; gap:var(--space-m); grid-template-columns:minmax(0,1fr); align-items:end;}
@media (min-width:900px){
  .page-head-grid{grid-template-columns:minmax(0,1.25fr) minmax(0,.75fr); gap:clamp(2rem,5vw,4rem);}
  .page-head .lede{padding-bottom:.35rem;}
}
.page-head h1{max-width:20ch;}
.crumbs{font-size:.85rem; color:var(--ink-muted); margin-bottom:.9rem;}
/* Padded so each crumb clears the 24px minimum target size on a phone */
.crumbs a{color:var(--ink-muted); text-decoration:none; display:inline-block; padding:.35rem 0;}
.crumbs a:hover{color:var(--accent); text-decoration:underline;}
.crumbs span{margin-inline:.4rem; opacity:.5;}

/* ---------- Trust strip ---------- */
.trust{border-block:1px solid var(--steel-200); background:var(--steel-100);}
.trust-list{display:grid; grid-template-columns:repeat(2,1fr); gap:1px; background:var(--steel-200);}
@media (min-width:860px){ .trust-list{grid-template-columns:repeat(4,1fr);} }
.trust-item{background:var(--steel-100); padding:1.4rem 1.1rem; display:flex; gap:.7rem; align-items:flex-start;}
.trust-item svg{flex:none; margin-top:2px; color:var(--accent);}
.trust-item b{display:block; color:var(--ink); font-size:.95rem;}
.trust-item span{font-size:.84rem; color:var(--ink-muted); line-height:1.45;}

/* ---------- Dark band ---------- */
.band{background:var(--ink); color:var(--steel-300);}
.band h2,.band h3{color:#fff;} .band p{color:var(--steel-300);}
.band .btn--ghost{border-color:rgba(255,255,255,.28); color:#fff;}
.band .btn--ghost:hover{border-color:#fff; background:rgba(255,255,255,.08);}

/* ---------- Process steps ---------- */
.steps{display:grid; gap:var(--space-l); grid-template-columns:1fr; counter-reset:s;}
@media (min-width:820px){ .steps{grid-template-columns:repeat(3,1fr); gap:var(--space-xl);} }
.step{border-top:3px solid var(--ink); padding-top:1.1rem;}
/* The step number is set at display scale. These are a real sequence, so the
   numbering carries information rather than decorating. */
.step::before{
  counter-increment:s; content:"0" counter(s);
  display:block; font-family:var(--font-mono); font-size:1.9rem; font-weight:600;
  letter-spacing:-.02em; color:var(--accent); line-height:1; margin-bottom:.7rem;
}
.step h3{margin-bottom:.4rem;}
.step p{font-size:.94rem;}
.band .step{border-top-color:rgba(255,255,255,.35);}

/* ---------- Divided list (services, FAQ style) ---------- */
.rows{border-top:1px solid var(--steel-200);}
.rows > *{border-bottom:1px solid var(--steel-200); padding:1.4rem .25rem;}
.rows a{display:block; text-decoration:none; color:var(--ink); transition:padding-left var(--dur) var(--ease), color var(--dur) var(--ease);}
.rows a:hover{padding-left:.85rem; color:var(--accent);}

/* ---------- CTA band ----------
   Full strength azure, on every page. It is the last thing anyone sees, and
   a pale grey box was the weakest note on the site. Ink on azure is 5.8:1,
   so the type clears AA without diluting the colour. */
.cta-band{background:var(--accent); border-top:3px solid var(--ink); color:var(--ink);}
.cta-band h2{
  color:var(--ink); text-transform:uppercase; font-stretch:118%; font-weight:800;
  font-size:clamp(1.9rem,4.4vw,3.4rem); line-height:.98; letter-spacing:-.02em;
}
/* Full ink, not a softened one. Ink at 82% over azure falls to 3.2:1. */
.cta-band .lede{color:var(--ink);}
.cta-band .btn--primary{background:var(--ink); color:#fff;}
.cta-band .btn--primary:hover{background:#000; box-shadow:var(--shadow-md);}
.cta-band .btn--ghost{border-color:var(--ink); color:var(--ink); border-width:2px;}
.cta-band .btn--ghost:hover{background:var(--ink); color:#fff;}
.cta-actions{display:flex; flex-wrap:wrap; gap:.75rem; margin-top:var(--space-m);}

/* ---------- Footer ---------- */
.site-footer{background:var(--ink); color:var(--steel-300); padding-block:clamp(2.25rem, 4.5vw, 3.25rem) var(--space-l);}
.footer-grid{display:grid; gap:var(--space-l); grid-template-columns:1fr;}
@media (min-width:780px){ .footer-grid{grid-template-columns:1.4fr 1fr 1fr;} }
.site-footer h3{color:#fff; font-size:.78rem; letter-spacing:.11em; text-transform:uppercase; margin-bottom:.9rem;}
.site-footer a{color:var(--steel-300); text-decoration:none;}
.site-footer a:hover{color:#fff;}
.site-footer ul{list-style:none; padding:0; display:grid; gap:.1rem; font-size:.93rem;}
.site-footer ul li{padding:.1rem 0;}
.site-footer ul a{display:inline-block; padding:.6rem 0;}
.footer-bottom{
  border-top:1px solid rgba(255,255,255,.12); margin-top:var(--space-xl);
  padding-top:var(--space-m); display:flex; flex-wrap:wrap; gap:.4rem 1.5rem;
  justify-content:space-between; font-size:.83rem; color:var(--steel-400);
}
.footer-bottom a{display:inline-block; padding:.5rem 0;}

/* Designer credit. Sits quietly: it is a signature, not a second brand on
   the client's page, so it stays muted until hovered. */
.colophon{display:flex; align-items:center; gap:.75rem; flex-wrap:wrap;}
.colophon-sep{opacity:.45;}
.mg-credit{
  display:inline-flex; align-items:center; gap:.5rem;
  text-decoration:none; color:var(--steel-400);
  transition:color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.mg-credit:hover{color:#fff;}
.mg-credit-label{font-size:.78rem; letter-spacing:.04em;}
.mg-credit-name{font-weight:600; color:var(--steel-300);}
.mg-credit:hover .mg-credit-name{color:#fff;}
/* The footer is the ink band, so a dark logo would disappear into it. Held
   slightly back and brought to full strength on hover. */
.mg-credit img{
  height:20px; width:auto; display:block;
  opacity:.72; transition:opacity var(--dur) var(--ease);
}
.mg-credit:hover img{opacity:1;}
.social{display:flex; gap:.9rem; margin-top:1rem;}
.social a{
  display:grid; place-items:center; width:44px; height:44px;
  border:1px solid rgba(255,255,255,.18); border-radius:var(--radius);
  transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.social a:hover{background:rgba(255,255,255,.09); border-color:rgba(255,255,255,.4);}

/* ============================================================
   Service pages
   Layout rule throughout: nothing pairs a short text block with a
   tall image under align-items:center. Splits start at the top,
   images are height capped, photo sets are uniform grids.
   ============================================================ */

/* ---------- Hero ----------
   Same treatment as the home page: photograph edge to edge, headline
   reversed out of it. */
.svc-hero{position:relative; background:var(--ink); overflow:hidden;}
.svc-hero-plate{position:absolute; inset:0;}
.svc-hero-plate img{width:100%; height:100%; object-fit:cover; filter:brightness(.72);}
.svc-hero::before{
  content:""; position:absolute; inset:0; z-index:2;
  background:
    linear-gradient(96deg, rgba(13,15,18,.93) 0%, rgba(13,15,18,.86) 44%,
                          rgba(13,15,18,.52) 70%, rgba(13,15,18,.28) 100%),
    linear-gradient(180deg, rgba(13,15,18,.30) 0%, rgba(13,15,18,0) 40%,
                           rgba(13,15,18,.50) 100%);
}
.svc-hero-copy{
  position:relative; z-index:3;
  padding-block:clamp(2.5rem,7vh,4.5rem) clamp(2.75rem,7vh,4.5rem);
  min-height:min(52vh,460px); display:flex; flex-direction:column; justify-content:flex-end;
}
.svc-hero h1{color:#fff; max-width:17ch; margin-bottom:1rem;}
.svc-hero-lede{color:rgba(255,255,255,.86); font-size:var(--step-1); line-height:1.5; max-width:52ch;}
.svc-hero .crumbs,.svc-hero .crumbs a{color:rgba(255,255,255,.62);}
.svc-hero .crumbs a:hover{color:var(--accent);}
.svc-hero .crumbs b{color:#fff;}
.svc-hero .cta-actions{margin-top:var(--space-l);}

/* No photograph yet. Plain ink, same shape, nothing missing looking. */
.svc-hero--bare{border-bottom:3px solid var(--accent);}
.svc-hero--bare::before{background:none;}

@media (max-width:760px){
  .svc-hero::before{
    background:linear-gradient(180deg, rgba(13,15,18,.52) 0%, rgba(13,15,18,.74) 45%,
                                       rgba(13,15,18,.93) 100%);
  }
}

/* ---------- What is included ---------- */
.scope-card{
  border:2px solid var(--ink);
  background:var(--paper-raised);
  padding:var(--space-l);
}
.scope-title{font-size:var(--step-1); font-stretch:100%; margin-bottom:var(--space-s);}
.scope-list{list-style:none; padding:0; display:grid; gap:.05rem;}
.scope-list li{
  position:relative; padding:.62rem 0 .62rem 1.6rem;
  border-bottom:1px solid var(--steel-200);
  font-size:.96rem; color:var(--ink-soft);
}
.scope-list li:last-child{border-bottom:0;}
/* Tick mark, the same dimension terminator used by .eyebrow */
.scope-list li::before{
  content:""; position:absolute; left:0; top:1.15em;
  width:9px; height:1px; background:var(--accent);
}

/* ---------- Recent work ---------- */
.work-grid{
  display:grid; gap:6px; grid-template-columns:1fr;
  margin-top:var(--space-l);
}
@media (min-width:640px){ .work-grid{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1000px){ .work-grid{grid-template-columns:repeat(3,1fr);} }
.work-grid figure{margin:0;}
.work-grid img{
  width:100%; aspect-ratio:4/3; object-fit:cover; display:block;
}
.band .eyebrow{color:var(--accent);}
.band .eyebrow::after{
  background:linear-gradient(to bottom,
    transparent calc(50% - .5px), rgba(255,255,255,.22) calc(50% - .5px),
    rgba(255,255,255,.22) calc(50% + .5px), transparent calc(50% + .5px));
}
.band .cta-actions{margin-top:var(--space-l);}

/* ---------- Process ---------- */
.process-grid{
  display:grid; gap:var(--space-m); grid-template-columns:1fr;
  margin-top:var(--space-l);
}
@media (min-width:700px){ .process-grid{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1100px){ .process-grid{grid-template-columns:repeat(4,1fr);} }
.process-step{border-top:3px solid var(--ink); padding-top:var(--space-s);}
.process-num{
  display:block; font-family:var(--font-mono); font-size:1.9rem;
  font-weight:600; letter-spacing:-.02em; color:var(--accent);
  line-height:1; margin-bottom:.7rem;
}
.process-step h3{margin-bottom:.4rem;}
.process-step p{font-size:.95rem; color:var(--ink-muted);}

/* ---------- FAQ ---------- */
.faq-list{margin-top:var(--space-l); border-top:3px solid var(--ink); max-width:74ch;}
.faq-item{padding:var(--space-m) 0; border-bottom:1px solid var(--steel-200);}
.faq-item h3{margin-bottom:.5rem;}
.faq-item p{color:var(--ink-soft);}
.faq-more{margin-top:var(--space-m); font-size:.95rem; color:var(--ink-muted);}

/* ---------- Before and after ----------
   The two frames sit flush against each other with a single hairline between,
   so the eye reads them as one continuous image rather than two cards. Any
   gap here weakens the comparison. */
.ba-head{max-width:24ch;}
.ba-list{display:grid; gap:var(--space-xl); margin-top:var(--space-l);}
.ba-meta h3{margin-bottom:.4rem;}
.ba-meta p{color:var(--ink-muted); font-size:.95rem; max-width:62ch;}
.ba-shots{
  display:grid; grid-template-columns:1fr; gap:2px;
  margin-top:var(--space-m); background:var(--steel-300);
}
@media (min-width:760px){ .ba-shots{grid-template-columns:1fr 1fr;} }
.ba-shot{position:relative; margin:0; overflow:hidden;}
.ba-shot img{width:100%; aspect-ratio:4/3; object-fit:cover; display:block;}
/* The label is the whole point of the format, so it is a hard block rather
   than a soft overlay. A visitor must never be unsure which frame is which. */
.ba-shot figcaption{
  position:absolute; top:0; left:0; padding:.45rem .8rem;
  font-family:var(--font-mono); font-size:.64rem; font-weight:600;
  letter-spacing:.18em; text-transform:uppercase;
  background:var(--ink); color:#fff;
}
.ba-shot:last-child figcaption{background:var(--accent); color:var(--ink);}

/* ---------- Phase sequence ----------
   Four stages of one job. Numbered, and the caption sits under the frame
   rather than over it, because these are documentary photographs of a working
   site and an overlay would cover the thing being documented. */
.ph-head{max-width:24ch;}
.ph-grid{display:grid; grid-template-columns:1fr; gap:var(--space-m); margin-top:var(--space-l);}
@media (min-width:640px){ .ph-grid{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1000px){ .ph-grid{grid-template-columns:repeat(4,1fr); gap:6px;} }
.ph-tile{margin:0;}
.ph-tile img{width:100%; aspect-ratio:4/5; object-fit:cover; display:block; background:var(--steel-200);}
.ph-tile figcaption{
  display:flex; align-items:baseline; gap:.6rem; padding-top:.7rem;
  font-family:var(--font-mono); font-size:.72rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase; color:var(--ink);
  border-top:1px solid var(--steel-300); margin-top:.55rem;
}
.ph-num{color:var(--accent);}

/* ---------- Reviews ----------
   Three reviews, so an equal three column row would read as a stock template
   and flatten the strongest quote into the weakest. The lead review takes the
   wider column at display scale and the rest stack beside it.

   No card boxes. The quotes are separated by the same hairline rules used by
   .faq-item and .scope-list, which keeps the page one system rather than
   introducing a second surface treatment. */
.quotes-head{max-width:20ch;}
.quotes{
  display:grid; gap:var(--space-l); grid-template-columns:1fr;
  margin-top:var(--space-l);
}
@media (min-width:900px){
  .quotes{grid-template-columns:1.15fr 1fr; gap:var(--space-xl); align-items:start;}
  /* One review, so there is no second column to balance against. */
  .quotes--solo{grid-template-columns:minmax(0,68ch);}
}
.quote{margin:0; border-top:3px solid var(--ink); padding-top:var(--space-m);}
.quote blockquote{margin:0;}
.quote p{color:var(--ink-soft); text-wrap:pretty;}
.quote--lead p{
  font-size:var(--step-1); line-height:1.5; color:var(--ink);
  max-width:34ch;
}
.quote-stars{display:flex; gap:2px; margin-bottom:var(--space-s);}
.quote-stars .star{width:15px; height:15px; color:var(--accent); flex:none;}
.quote figcaption{
  margin-top:var(--space-s); font-size:.9rem; font-weight:600;
  letter-spacing:.01em; color:var(--ink);
}
/* The source sits under the name rather than beside it, so a long display
   name never collides with the label on a narrow screen. */
.quote-src{
  display:block; margin-top:.15rem; font-weight:400; color:var(--ink-muted);
}
.quotes-rest{display:grid; gap:var(--space-l);}
/* The lighter rule is 2px thinner than the lead's, so the padding makes that
   back up. Without it the two columns start 2px apart and the star rows read
   as misaligned against each other. */
.quotes-rest .quote{
  border-top-width:1px; border-top-color:var(--steel-300);
  padding-top:calc(var(--space-m) + 2px);
}
/* Four or more reviews run as an even wall. CSS columns rather than grid,
   because the quotes vary from two lines to a full paragraph and columns
   pack that unevenness far better than equal grid rows would. */
.quotes-wall{margin-top:var(--space-l);}
@media (min-width:700px){ .quotes-wall{columns:2; column-gap:var(--space-l);} }
@media (min-width:1100px){ .quotes-wall{columns:3; column-gap:var(--space-l);} }
.quotes-wall .quote{
  break-inside:avoid; margin-bottom:var(--space-l);
  border-top-width:1px; border-top-color:var(--steel-300);
}
/* A column break can otherwise leave a rule stranded at the foot of a column. */
.quotes-wall .quote:last-child{margin-bottom:0;}

.quotes-note{
  margin-top:var(--space-l); font-size:.95rem; color:var(--ink-muted);
  max-width:62ch;
}

/* ---------- Related ---------- */
.related-grid{display:grid; gap:var(--space-m); grid-template-columns:1fr; margin-top:var(--space-l);}
@media (min-width:760px){ .related-grid{grid-template-columns:repeat(3,1fr);} }
.related-card{
  display:flex; flex-direction:column; text-decoration:none; color:inherit;
  border:2px solid var(--ink);
  background:var(--paper-raised); overflow:hidden;
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
             transform var(--dur) var(--ease);
}
.related-card:hover{border-color:var(--accent); transform:translateY(-3px);}
.related-card img{width:100%; aspect-ratio:16/10; object-fit:cover;}
.related-body{padding:var(--space-m); display:flex; flex-direction:column; gap:.4rem; flex:1;}
.related-body h3{font-size:var(--step-0); font-weight:700;}
.related-body p{font-size:.92rem; color:var(--ink-muted);}
.related-go{
  margin-top:auto; padding-top:.6rem; font-family:var(--font-mono);
  font-size:.7rem; letter-spacing:.12em; text-transform:uppercase; color:var(--accent-ink);
}
.related-card:hover .related-go{color:var(--accent-hover);}

/* ---------- Services hub grid ---------- */
.hub-grid{display:grid; gap:var(--space-m); grid-template-columns:1fr; margin-top:var(--space-l);}
@media (min-width:700px){ .hub-grid{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1100px){ .hub-grid{grid-template-columns:repeat(3,1fr);} }
.hub-card{
  display:flex; flex-direction:column; text-decoration:none; color:inherit;
  border:2px solid var(--ink);
  background:var(--paper-raised); overflow:hidden;
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
             transform var(--dur) var(--ease);
}
.hub-card:hover{border-color:var(--accent); transform:translateY(-3px);}
.hub-card img{width:100%; aspect-ratio:16/10; object-fit:cover;}
/* Cards with no photo yet keep the same shape with an ink panel.
   Used by both the hub grid and the related grid, so it is not scoped
   to either one. */
.hub-blank{
  aspect-ratio:16/10; background:var(--ink); display:grid; place-items:center;
}
.hub-blank span{
  font-family:var(--font-mono); font-size:.72rem; letter-spacing:.2em;
  text-transform:uppercase; color:var(--accent);
}
.hub-body{padding:var(--space-m); display:flex; flex-direction:column; gap:.45rem; flex:1;}
.hub-body h2{font-size:var(--step-1); font-stretch:100%; letter-spacing:-.015em;}
.hub-body p{font-size:.94rem; color:var(--ink-muted);}
.hub-go{
  margin-top:auto; padding-top:.7rem; font-family:var(--font-mono);
  font-size:.7rem; letter-spacing:.12em; text-transform:uppercase; color:var(--accent-ink);
}

/* Seven services into a three column grid leaves the last card alone on
   its own row. It runs full width instead, laid out sideways. That suits
   the catch-all trades card, which is the one that lands there. */
@media (min-width:1100px){
  .hub-grid > .hub-card:last-child{grid-column:1 / -1; flex-direction:row;}
  .hub-grid > .hub-card:last-child > :first-child{flex:0 0 32%;}
  .hub-grid > .hub-card:last-child img,
  .hub-grid > .hub-card:last-child .hub-blank{
    height:100%; min-height:210px; aspect-ratio:auto; object-fit:cover;
  }
  .hub-grid > .hub-card:last-child .hub-body{justify-content:center; padding:var(--space-l);}
  .hub-grid > .hub-card:last-child .hub-body p{max-width:60ch;}
  .hub-grid > .hub-card:last-child .hub-go{margin-top:.9rem;}
}

/* ============================================================
   Home page
   Louder than the rest of the site on purpose. Thick rules, hard
   edges, poster scale type. The hairlines and soft shadows used
   elsewhere read as timid at this size.
   ============================================================ */

/* ---------- Job site hero ---------- */
.jobsite{position:relative; background:var(--ink); overflow:hidden;}
/* Not a 50/50 split. The structure plate takes the larger share because the
   headline sits over it, which leaves the finish plate clean enough to
   actually sell the finished room. */
.jobsite-plates{position:absolute; inset:0; display:grid; grid-template-columns:1.18fr .82fr;}
/* One photograph across the whole hero. The split was a framing shot beside a
   finished one; the client wanted the finished house on its own, so the grid
   collapses to a single column and the plate keeps its own colour treatment
   rather than the darkened structure one. */
.jobsite-plates:has(.plate--full){grid-template-columns:1fr;}
.plate--full img{filter:saturate(1.04) brightness(.9);}
.plate{position:relative; margin:0; overflow:hidden;}
.plate img{width:100%; height:100%; object-fit:cover;}
/* Structure plate is desaturated, finish plate is not. The eye reads the
   left as work in progress and the right as the result without being told. */
.plate--structure img{filter:grayscale(1) contrast(1.1) brightness(.5);}
.plate--finish img{filter:saturate(1.05) brightness(.92);}
.plate figcaption{
  position:absolute; top:1.4rem; z-index:3;
  font-family:var(--font-mono); font-size:.68rem; font-weight:600;
  letter-spacing:.24em; text-transform:uppercase; color:#fff;
  padding:.35rem .6rem; border:1px solid rgba(255,255,255,.35);
}
.plate--structure figcaption{left:1.4rem;}
.plate--finish figcaption{right:1.4rem;}
/* No seam rule. The two photographs meet directly: one is greyed and one is
   in colour, which already reads as two plates without drawing a line down
   the middle of the page. */
/* Scrim. Weighted to the left, where the type lives, so the finish plate on
   the right keeps its colour instead of going muddy under a flat overlay. */
.jobsite::before{
  content:""; position:absolute; inset:0; z-index:2;
  background:
    linear-gradient(96deg, rgba(13,15,18,.93) 0%, rgba(13,15,18,.88) 42%,
                          rgba(13,15,18,.55) 64%, rgba(13,15,18,.22) 100%),
    linear-gradient(180deg, rgba(13,15,18,.30) 0%, rgba(13,15,18,0) 34%,
                           rgba(13,15,18,.42) 100%);
}
.jobsite-copy{
  position:relative; z-index:3;
  padding-block:clamp(5rem,16vh,9rem) clamp(3rem,8vh,5rem);
  min-height:min(86vh,780px); display:flex; flex-direction:column; justify-content:flex-end;
}
.stamp{
  display:inline-flex; align-items:center; gap:.5rem; align-self:flex-start;
  font-family:var(--font-mono); font-size:.7rem; font-weight:600;
  letter-spacing:.18em; text-transform:uppercase; color:#fff;
  border:2px solid var(--accent); padding:.45rem .85rem; margin-bottom:var(--space-m);
}
.stamp .star{width:13px; height:13px; color:var(--accent); flex:none;}
/* Held to the left of the seam so the split stays readable as two
   photographs rather than one dark background behind a headline. */
.jobsite h1{
  color:#fff; font-size:clamp(2.1rem,4.6vw,4.1rem); font-weight:800;
  font-stretch:118%; line-height:.94; letter-spacing:-.022em;
  text-transform:uppercase; max-width:16ch;
}
/* The promise carries the colour. It is the line people repeat, and it sits
   below the h1 so it can be plain English without costing anything in search. */
.jobsite-promise{
  color:var(--accent); font-size:clamp(1.05rem,1.9vw,1.65rem); font-weight:700;
  font-stretch:112%; text-transform:uppercase; letter-spacing:-.01em;
  line-height:1.12; max-width:24ch; margin-top:var(--space-s);
}
.jobsite-lede{
  color:rgba(255,255,255,.86); font-size:var(--step-1); line-height:1.5;
  max-width:56ch; margin-top:var(--space-m);
}
.jobsite-actions{display:flex; flex-wrap:wrap; gap:.75rem; margin-top:var(--space-l);}
.btn--onphoto{border-color:rgba(255,255,255,.5); color:#fff; background:rgba(13,15,18,.35);}
.btn--onphoto:hover{border-color:#fff; background:rgba(255,255,255,.12);}

@media (max-width:760px){
  /* Stacked, structure on top of finish, so both still read on a phone.
     The scrim has to go vertical here: the copy spans the full width, so a
     left weighted gradient would leave the lede sitting on a bright kitchen. */
  .jobsite::before{
    background:linear-gradient(180deg, rgba(13,15,18,.52) 0%, rgba(13,15,18,.72) 42%,
                                       rgba(13,15,18,.93) 100%);
  }
  .jobsite-plates{grid-template-columns:1fr; grid-template-rows:1fr 1fr;}
  .plate--finish figcaption{right:auto; left:1.4rem; top:auto; bottom:1.4rem;}
  .jobsite-copy{min-height:74vh;}
}

/* ---------- Title block ---------- */
.titleblock-wrap{background:var(--ink); padding-bottom:clamp(2rem, 4vw, 3rem);}
.titleblock{
  display:grid; grid-template-columns:1fr; gap:0;
  border:2px solid var(--accent); background:var(--ink);
}
@media (min-width:620px){ .titleblock{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1000px){ .titleblock{grid-template-columns:repeat(4,1fr);} }
.titleblock > div{padding:1.15rem 1.35rem; border-bottom:1px solid rgba(41,149,212,.4);}
@media (min-width:620px){
  .titleblock > div{border-right:1px solid rgba(41,149,212,.4);}
  .titleblock > div:nth-child(2n){border-right:0;}
}
@media (min-width:1000px){
  .titleblock > div{border-bottom:0; border-right:1px solid rgba(41,149,212,.4);}
  .titleblock > div:last-child{border-right:0;}
}
.titleblock span{
  display:block; font-family:var(--font-mono); font-size:.62rem; font-weight:600;
  letter-spacing:.2em; text-transform:uppercase; color:var(--accent); margin-bottom:.4rem;
}
.titleblock b{color:#fff; font-size:1rem; font-weight:600; font-stretch:105%;}

/* ---------- Services index ---------- */
.index-head{font-size:clamp(2rem,5vw,3.6rem); font-stretch:118%; text-transform:uppercase;
  line-height:.95; margin:.6rem 0 var(--space-l);}
.svc-index{border-top:3px solid var(--ink);}
.idx-row{
  position:relative; display:grid; align-items:center; gap:.2rem 1.5rem;
  grid-template-columns:1fr auto; padding:1.5rem .25rem;
  border-bottom:1px solid var(--steel-300); text-decoration:none; color:var(--ink);
  transition:padding-left var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.idx-name{
  grid-column:1; font-size:clamp(1.4rem,3.4vw,2.5rem); font-weight:700; font-stretch:112%;
  letter-spacing:-.02em; line-height:1.05; text-transform:uppercase;
}
.idx-teaser{grid-column:1; font-size:.95rem; color:var(--ink-muted); max-width:52ch;}
.idx-arrow{grid-column:2; grid-row:1 / span 2; font-size:1.6rem; color:var(--steel-400);
  transition:color var(--dur) var(--ease), transform var(--dur) var(--ease);}
.idx-row:hover{padding-left:1.1rem; border-color:var(--accent);}
.idx-row:hover .idx-arrow{color:var(--accent); transform:translateX(6px);}
.idx-row:focus-visible{outline:3px solid var(--accent); outline-offset:3px;}

/* The photograph panel. Hidden until hover, and only on pointer devices with
   room for it: on touch the row is just a link. */
/* The column beside the list is a sticky call to action. It replaced a
   photograph that only slid down the page as you scrolled: that space is
   better spent keeping the estimate button in view while somebody reads
   through the list. Below 1080px it simply stacks under the rows. */
.idx-cta{
  border:2px solid var(--accent); background:var(--ink); color:var(--steel-300);
  padding:var(--space-m); margin-top:var(--space-l);
}
.idx-cta-label{
  font-family:var(--font-mono); font-size:.68rem; font-weight:600;
  letter-spacing:.2em; text-transform:uppercase; color:var(--accent);
  margin-bottom:.7rem;
}
.idx-cta h3{color:#fff; font-size:var(--step-1); font-stretch:106%; margin-bottom:.6rem;}
.idx-cta p{font-size:.94rem; color:var(--steel-300); max-width:none;}
.idx-cta .cta-actions{flex-direction:column; gap:.5rem; margin-top:var(--space-m);}
.idx-cta .btn{width:100%;}
.idx-cta-note{
  margin-top:var(--space-m); padding-top:var(--space-s);
  border-top:1px solid rgba(255,255,255,.14);
  font-size:.82rem; color:var(--steel-400);
}

@media (min-width:1080px){
  .svc-index{
    display:grid; grid-template-columns:minmax(0,1fr) 24rem;
    column-gap:clamp(2.5rem,5vw,4rem);
  }
  .svc-index > .idx-row{grid-column:1;}
  /* span 99, not 1 / -1. The rows here are implicit, and -1 resolves to the
     last line of the explicit grid, which is line 1 when no grid-template-rows
     is set. That would drop the panel inside row one and stretch it. The
     extra implicit rows this creates are empty and collapse to zero height. */
  .idx-cta{
    grid-column:2; grid-row:1 / span 99; margin-top:0;
    position:sticky; top:calc(76px + var(--space-l)); align-self:start;
  }
}

/* ---------- Document layout ----------
   Long form pages used to be a single 65ch column inside a 1400px shell,
   which left the right hand half of the page empty. The prose keeps its
   measure and an aside fills the rest with something useful. */
.doc{display:grid; gap:var(--space-xl); grid-template-columns:1fr; align-items:start;}
@media (min-width:1000px){
  .doc{grid-template-columns:minmax(0,1fr) 22rem; gap:clamp(3rem,6vw,5.5rem);}
  .doc-aside{position:sticky; top:calc(76px + var(--space-m));}
}
.doc-main > h2:first-child{margin-top:0;}

.doc-aside{
  border:2px solid var(--ink); background:var(--paper-raised); padding:var(--space-m);
}
.doc-aside h3{
  font-family:var(--font-mono); font-size:.7rem; font-weight:600; letter-spacing:.18em;
  text-transform:uppercase; color:var(--accent-ink); margin-bottom:.9rem;
}
.doc-aside ul{list-style:none; padding:0; margin:0 0 var(--space-m); display:grid; gap:.05rem;}
.doc-aside li{
  position:relative; padding:.6rem 0 .6rem 1.5rem; font-size:.93rem;
  color:var(--ink-soft); border-bottom:1px solid var(--steel-200);
}
.doc-aside li:last-child{border-bottom:0;}
.doc-aside li::before{
  content:""; position:absolute; left:0; top:1.1em; width:9px; height:1px; background:var(--accent);
}
.doc-aside .btn{width:100%;}
.doc-aside .cta-actions{margin-top:0; flex-direction:column; gap:.5rem;}

/* Legal pages have no aside. A single column reads better centred than
   pinned to the left of an empty half page. */
.doc-solo{max-width:72ch; margin-inline:auto;}

/* ============================================================
   Mobile
   Phones are most of this client's traffic, so the small label
   sizes and tap targets that pass on a desktop get corrected here
   rather than left to chance.
   ============================================================ */
@media (max-width:760px){
  /* Mono labels sit at 11px or below on desktop, which is too small to read
     comfortably on a phone. Nudged over 12px without changing the desktop. */
  .eyebrow,.stamp,.plate figcaption,.doc-aside h3,
  .hub-go,.related-go,.idx-cta-label,.titleblock span,.hub-blank span,
  .idx-blank,.logo-text span,.process-num,.site-footer h3{font-size:.78rem;}
  /* The process numbers are a display element, not a label, so they keep
     their size rather than being swept up by the rule above. */
  .process-num,.step::before{font-size:1.7rem;}

  /* The logo is the most tapped thing in the header. 36px tall was under the
     44px comfortable target, so it gets padding rather than a bigger image. */
  .logo{padding-block:.4rem;}

  /* Long uppercase service names need room to break */
  .idx-name{font-size:clamp(1.3rem,6.4vw,1.9rem);}

  /* The home hero runs close to a full screen. Trimmed so the first service
     row is reachable without a long scroll. */
  .jobsite-copy{min-height:68vh;}
}

/* ---------- Services dropdown ----------
   The client asked for the full service list in the nav. Built as a
   disclosure rather than a hover menu: hover-only menus are unusable on
   touch and awkward with a keyboard. */
.nav-item{display:inline-flex; align-items:center; gap:.25rem; position:relative;}
.nav-sub-toggle{
  display:inline-grid; place-items:center; width:28px; height:28px;
  border:0; background:transparent; color:rgba(255,255,255,.78);
  cursor:pointer; transition:color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.nav-sub-toggle:hover{color:var(--accent);}
.nav-sub-toggle[aria-expanded="true"]{color:var(--accent); transform:rotate(180deg);}
.nav-sub{
  display:none; list-style:none; margin:0; padding:0;
}
.nav-sub[data-open="true"]{display:block;}

@media (min-width:1000px){
  .nav-sub{
    position:absolute; top:calc(100% + 18px); left:-1rem; z-index:60;
    min-width:19rem; background:var(--ink);
    border:2px solid var(--accent); padding:.35rem;
    box-shadow:var(--shadow-lg);
  }
  .nav-sub li a{
    display:block; padding:.7rem .85rem; font-size:.92rem;
    color:rgba(255,255,255,.82); text-decoration:none; white-space:nowrap;
  }
  .nav-sub li a:hover,.nav-sub li a[aria-current="page"]{
    background:rgba(41,149,212,.16); color:#fff;
  }
  /* Bridges the gap between the nav item and the panel so the pointer does
     not fall through it on the way down. */
  .nav-item--has-sub::after{
    content:""; position:absolute; top:100%; left:0; right:0; height:20px;
  }
}

@media (max-width:999px){
  /* Inside the stacked mobile panel the submenu is just an indented list. */
  .nav-item{display:flex; justify-content:space-between; width:100%;
    border-bottom:1px solid rgba(255,255,255,.10); flex-wrap:wrap;}
  .nav-item > a{flex:1;}
  .nav-sub-toggle{width:44px; height:44px; color:#fff;}
  .nav-sub{width:100%; padding-bottom:.4rem;}
  .nav-sub li a{
    display:block; padding:.7rem 0 .7rem 1rem; font-size:.95rem;
    color:rgba(255,255,255,.72); text-decoration:none;
    border-left:2px solid var(--accent); margin-left:.25rem;
  }
  .nav-sub li a[aria-current="page"]{color:#fff;}
}
