/* Dossier — the system for this site.
   Light ground only: the intake asks for a light background, so there is no
   second palette and no theme script anywhere on the site.
   Every text/background pair below was measured against WCAG AA before it was
   written. Copper is a non-text colour: it draws rules and marks, never words. */
:root{
  --ground:#F6F4F0; --paper:#FFFFFF; --band:#EDE9E2; --navy:#1C3A60;
  --ink:#16223A; --copper-text:#8A4E22; --grey-text:#565F6B;
  --copper-rule:#B8703E; --hair:#D8D2C8;
  --on-navy:#F6F4F0; --on-navy-copper:#E8B98C; --on-navy-grey:#AEB8C6;
  --serif:Georgia,"Iowan Old Style","Times New Roman",serif;
  --sans:system-ui,-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;
  --measure:64ch; --gap:1.5rem; --pad:clamp(1rem,4vw,2.5rem);
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--ground);color:var(--ink);
  font:400 1rem/1.6 var(--sans);
  /* BackgroundStyle: texture — drawn, not an image, so it costs nothing */
  background-image:repeating-linear-gradient(0deg,transparent 0 3px,rgba(28,58,96,.022) 3px 4px);}
h1,h2,h3,h4{text-wrap:balance;font-family:var(--serif);color:var(--navy);
  line-height:1.18;margin:0 0 .6em}
h1{font-size:clamp(1.9rem,4.4vw,3rem);letter-spacing:-.012em}
h2{font-size:clamp(1.4rem,2.6vw,2rem)}
h3{font-size:1.08rem;font-family:var(--sans);font-weight:700;letter-spacing:-.005em}
/* The emitter already binds the last two words of every string, so a word can
   never strand alone; pretty also discourages a short final line where the
   browser supports it. */
p,li,dd,figcaption,.cap{text-wrap:pretty}
p{margin:0 0 1em}
a{color:var(--copper-text)}
a:hover{color:var(--navy)}
:focus-visible{outline:3px solid var(--copper-rule);outline-offset:2px}
img{max-width:100%;display:block}
[hidden]{display:none}
.wrap{width:min(1180px,100% - 2*var(--pad));margin-inline:auto}
.skip{position:absolute;left:-9999px}
.skip:focus{left:1rem;top:1rem;z-index:60;background:var(--navy);
  color:var(--on-navy);padding:.6rem 1rem;border-radius:3px}

/* Small-caps section label — the editorial apparatus of this system */
.label{font:700 .75rem/1.3 var(--sans);letter-spacing:.14em;
  text-transform:uppercase;color:var(--grey-text);margin:0 0 .7rem}

/* Preview banner: self-contained colours, in flow, no JS, covers nothing */
.owpreview{background:#1C3A60;color:#FFFFFF;padding:.7rem var(--pad);
  display:flex;gap:1rem;align-items:center;justify-content:center;
  flex-wrap:wrap;text-align:center}
.owpreview p{margin:0;font-size:.94rem}
.owcta{background:#FFFFFF;color:#1C3A60;text-decoration:none;font-weight:700;
  padding:.5rem 1rem;border-radius:3px;font-size:.9rem;min-height:44px;
  display:inline-flex;align-items:center}
.owcta:hover{color:#16223A}

/* Header. The bar carries six pages; the disclosure carries the rest, and
   below the width where the full bar fits it carries all ten. */
.sitehead{position:sticky;top:0;z-index:40;background:var(--ground);
  border-bottom:2px solid var(--copper-rule)}
.headrow{display:flex;align-items:center;gap:1rem;padding:.5rem 0;flex-wrap:wrap}
.brandlink{flex:0 0 auto;display:block}
/* The logo file carries three lines; the third is set too small to read at
   header scale, so the header frames the two wordmark lines and the footer
   shows the whole mark at a size where the third line reads. The file itself
   is untouched. */
/* Frame arithmetic, measured off the file rather than guessed: canvas
   1300x400; the three text bands sit at y 109-168 (CALDERWOOD), 205-237
   (PLUMBING & HEATING) and 289-308 (ESTABLISHED 1994 - OTTAWA), the last only
   20px tall. At any width that fits a header bar that third line renders under
   5px and reads as a grey smear, so the header and footer frame the two
   wordmark bands (x 260-941, y 109-237) and the whole mark is shown at 640px
   on the About page, where all three lines are legible. The file is untouched.
   Scale 0.31: img width 1300*0.31=403, left -260*0.31=-81, top -109*0.31=-34,
   frame (941-260)*0.31=211 by (237-109)*0.31=40. */
.logoframe{display:block;width:211px;height:40px;overflow:hidden}
/* max-width:none, or the global image cap would shrink the mark to the frame
   and every offset below would land somewhere else */
.logoframe img{width:403px;max-width:none;height:auto;margin:-34px 0 0 -81px}
/* Footer, same crop at scale 0.388 */
.logoframe.foot{width:264px;height:50px;margin-bottom:1rem}
.logoframe.foot img{width:504px;margin:-42px 0 0 -101px}
.nav{position:relative;flex:1 1 auto;display:flex;justify-content:flex-end;
  gap:.4rem;align-items:center}
.bar{display:flex;flex-wrap:wrap;gap:.15rem;list-style:none;margin:0;padding:0}
.bar a,.morepanel a,.more summary{white-space:nowrap;text-decoration:none;
  font:600 .86rem/1 var(--sans);color:var(--navy);padding:.72rem .6rem;
  display:flex;align-items:center;min-height:44px;border-radius:3px}
.bar a:hover,.morepanel a:hover{background:var(--band);color:var(--navy)}
.bar a[aria-current],.morepanel a[aria-current]{color:var(--copper-text);
  box-shadow:inset 0 -2px 0 var(--copper-rule)}
.more{position:static}
.more summary{cursor:pointer;list-style:none;border:1px solid var(--hair)}
.more summary::-webkit-details-marker{display:none}
.morepanel{list-style:none;margin:0;padding:.4rem;display:flex;
  flex-direction:column;gap:.1rem}
/* Restate the closed state in the component's own CSS — a UA default is one
   declaration from not existing. */
.more:not([open]) .morepanel{display:none}
.more[open] .morepanel{position:absolute;right:0;top:calc(100% + .4rem);
  background:var(--paper);border:1px solid var(--hair);border-radius:4px;
  box-shadow:0 12px 28px rgba(22,34,58,.13);min-width:15rem;z-index:50}
.w-menu{display:none}
.dup{display:none}
.headcta{flex:0 0 auto}
.cta{background:var(--copper-text);color:#FFFFFF;text-decoration:none;
  font:700 .88rem/1 var(--sans);padding:.8rem 1.1rem;border-radius:3px;
  display:inline-flex;align-items:center;min-height:44px}
.cta:hover{background:var(--navy);color:#FFFFFF}
.ghost{text-decoration:none;font:700 .95rem/1 var(--sans);color:var(--navy);
  padding:.8rem 0;display:inline-flex;align-items:center;min-height:44px;
  box-shadow:inset 0 -2px 0 var(--copper-rule)}

/* A sticky header means every anchor target must reserve room for it. */
[id]{scroll-margin-top:6.5rem}

main{display:block}
.mod,.pagehead,.spread,.toc,.svclist,.infobox,.pagesplit,.grid.wide,
.faqwall.wide,.g-gallery{width:min(1180px,100% - 2*var(--pad));margin-inline:auto}
.mod{padding:clamp(2.2rem,5vw,3.6rem) 0;border-top:1px solid var(--hair)}
.mod.band{width:100%;background:var(--band);border-top:1px solid var(--hair);
  padding-inline:var(--pad)}
.mod.band > *{width:min(1180px,100%);margin-inline:auto}
.pagehead{padding:clamp(2rem,5vw,3.4rem) 0 1.5rem}
.more-link{margin:1.4rem 0 0}
.more-link a{font:700 .86rem/1 var(--sans);text-decoration:none;
  box-shadow:inset 0 -2px 0 var(--copper-rule);padding-bottom:2px}

/* Hero: photograph and words are one composition, so the pair is centred. */
.hero{padding:clamp(2rem,5vw,3.4rem) var(--pad)}
.heroinner{width:min(1180px,100%);margin-inline:auto;display:flex;
  justify-content:center;align-items:center;gap:clamp(1.5rem,4vw,3rem);
  flex-wrap:wrap}
.herowords{flex:1 1 21rem;max-width:34rem}
.heroshot{flex:1 1 21rem;max-width:34rem;margin:0}
.lede{font-size:1.06rem;color:var(--grey-text);max-width:var(--measure)}
.actions{display:flex;gap:.8rem;flex-wrap:wrap;align-items:center;margin-top:1.4rem}

/* One framing sitewide. Any img given a ratio also gets height:auto, or the
   width/height attributes the standards require would cancel the ratio. */
.shot{margin:0}
.shot img,.heroshot img,.tile img,.tile a img{width:100%;height:auto;
  aspect-ratio:4/3;object-fit:cover;border-radius:3px}
.shot.wide img{aspect-ratio:3/2;height:auto}
figcaption,.cap{font:400 .82rem/1.5 var(--sans);color:var(--grey-text);
  margin:.6rem 0 0;max-width:46ch}
.spread{padding:clamp(2rem,5vw,3.2rem) 0;border-top:1px solid var(--hair)}
/* The whole mark, uncropped, at the one size where its third line is legible */
.bigmark{width:min(640px,100%);height:auto}

.grid{list-style:none;margin:0;padding:0;display:grid;gap:var(--gap)}
/* .grid resets margin, so the grids that are their own page-width container
   have to restate the centring after it */
.g-gallery,.grid.wide{margin-inline:auto}
/* Fixed sets declare their columns, and the count divides the item count. */
.g-services{grid-template-columns:1fr}
.g-creds{grid-template-columns:1fr}
.g-team{grid-template-columns:1fr}
.g-quotes{grid-template-columns:1fr}
.g-strip{grid-template-columns:1fr}
.g-gallery{grid-template-columns:1fr}

.card{background:var(--paper);border:1px solid var(--hair);border-left:3px solid
  var(--copper-rule);border-radius:3px;padding:1.1rem 1.2rem}
.card h3,.card h2{margin:0 0 .35rem}
.card h3 a,.card h2 a{text-decoration:none;color:var(--navy)}
.card h3 a:hover{color:var(--copper-text)}
.card p{margin:0;font-size:.93rem;color:var(--grey-text)}

.ctile{background:var(--paper);border:1px solid var(--hair);border-radius:3px;
  padding:1.1rem 1.2rem;display:flex;flex-direction:column;gap:.25rem}
.cnum{font:700 1.35rem/1.15 var(--serif);color:var(--navy)}
.clab{font:400 .84rem/1.4 var(--sans);color:var(--grey-text)}

.split{display:flex;gap:clamp(1.5rem,4vw,2.6rem);flex-wrap:wrap;align-items:flex-start}
.half{flex:1 1 20rem;min-width:0}
.pagesplit{padding-bottom:clamp(2rem,5vw,3.4rem)}
.prose p,.half p,.svc p,.faqbody p{max-width:var(--measure)}

/* Tables, grids and the footer take their container's width; the prose measure
   belongs to prose only. */
.rates{width:100%;border-collapse:collapse;font-size:.94rem;
  font-variant-numeric:tabular-nums}
.rates th,.rates td{text-align:left;padding:.72rem .6rem;
  border-bottom:1px solid var(--hair);vertical-align:top}
.rates th{font-weight:600;color:var(--ink);width:60%}
.rates td{color:var(--navy);font-weight:700;white-space:normal}

.dossier{margin:0;padding-left:1.4rem;max-width:var(--measure)}
.dossier li{margin:0 0 .7rem;padding-left:.3rem}
.dossier li::marker{color:var(--copper-rule);font-weight:700}

.toc{padding:1.2rem 0;border-top:1px solid var(--hair);
  border-bottom:1px solid var(--hair)}
.toc ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.3rem}
.toc a{font:600 .84rem/1 var(--sans);text-decoration:none;color:var(--navy);
  background:var(--paper);border:1px solid var(--hair);border-radius:999px;
  padding:.62rem .9rem;display:inline-flex;align-items:center;min-height:44px}
.toc a:hover{border-color:var(--copper-rule);color:var(--copper-text)}

.svclist{padding:1rem 0 2.4rem}
.svc{padding:1.8rem 0;border-bottom:1px solid var(--hair)}
.svc h2{margin-bottom:.5rem}
.svc .shot{margin-top:1.1rem;max-width:34rem}

.credlist{margin:0}
.cred,.term,.fact{padding:.95rem 0;border-bottom:1px solid var(--hair)}
.cred dt,.term dt,.fact dt{font:700 .8rem/1.3 var(--sans);letter-spacing:.1em;
  text-transform:uppercase;color:var(--grey-text);margin-bottom:.35rem}
.cred dd,.term dd,.fact dd{margin:0;max-width:var(--measure)}
.fact dd{color:var(--navy);font-weight:600}

.qcard{background:var(--paper);border:1px solid var(--hair);border-radius:3px;
  padding:1.3rem 1.4rem;display:flex;flex-direction:column;gap:.8rem}
.qcard blockquote{margin:0;font:400 1.02rem/1.55 var(--serif);color:var(--ink)}
.qcard blockquote p{margin:0}
.qcard blockquote::before{content:"";display:block;width:2rem;height:2px;
  background:var(--copper-rule);margin-bottom:.9rem}
.attrib{margin:0;font:600 .84rem/1.4 var(--sans);color:var(--grey-text)}

.faqwall{display:flex;flex-direction:column;gap:.5rem;padding-bottom:2.4rem}
.faq{background:var(--paper);border:1px solid var(--hair);border-radius:3px}
.faq summary{cursor:pointer;list-style:none;padding:1rem 1.2rem;
  font:700 1rem/1.4 var(--sans);color:var(--navy);min-height:44px;
  display:flex;align-items:center}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--copper-text)}
.faq:not([open]) .faqbody{display:none}
.faqbody{padding:0 1.2rem 1.1rem}
.faqbody p{margin:0}

.hourslist,.plain{list-style:none;margin:0;padding:0}
.plain li{padding:.35rem 0;font-size:.94rem}
.hourslist li{border-bottom:1px solid var(--hair);padding:.6rem 0}
.addr{font:400 1.05rem/1.6 var(--serif);color:var(--navy);margin:0 0 1rem}

.mapwrap{position:relative;width:100%;aspect-ratio:4/3;border-radius:3px;
  overflow:hidden;border:1px solid var(--hair);background:var(--band)}
.mapwrap iframe{position:absolute;inset:0;width:100%;height:100%}

/* Gallery enlargement. A fixed inset does not clear the UA margin a figure
   carries, and the enlargement must not inherit the tile's crop. */
.tile{position:relative}
.tile > a{display:block}
.big{position:fixed;inset:0;margin:0;z-index:70;background:rgba(22,34,58,.94);
  padding:clamp(1rem,4vw,3rem);display:none;flex-direction:column;
  align-items:center;justify-content:center;gap:1rem}
.big:target{display:flex}
.big img{width:auto;height:auto;max-width:100%;max-height:72vh;aspect-ratio:auto;
  object-fit:contain;border-radius:3px}
.big figcaption{color:var(--on-navy-grey);text-align:center;max-width:56ch}
.close{color:#FFFFFF;text-decoration:none;font:700 .88rem/1 var(--sans);
  border:1px solid var(--on-navy-grey);border-radius:3px;padding:.8rem 1.2rem;
  min-height:44px;display:inline-flex;align-items:center}
.close:hover{background:#FFFFFF;color:var(--navy)}

.infobox{margin-block:0 clamp(2rem,5vw,3.4rem);background:var(--paper);
  border:1px solid var(--hair);border-top:3px solid var(--copper-rule);
  border-radius:3px;padding:1.4rem clamp(1.2rem,3vw,2rem)}
.facts{margin:0;display:grid;gap:0;grid-template-columns:1fr}
.infobox .fact:last-child{border-bottom:0;padding-bottom:0}

.sitefoot{background:var(--navy);color:var(--on-navy);
  margin-top:clamp(2rem,5vw,3.5rem);padding:clamp(2rem,5vw,3.2rem) 0 1.5rem}
.footgrid{display:grid;gap:2rem;grid-template-columns:1fr}
.footcol .label{color:var(--on-navy-grey)}
.footcol .label ~ .label{margin-top:1.6rem}
/* The wordmark is navy and copper ink on transparent ground, so on the navy
   footer it needs the cream ground it was drawn for. A plaque, not an edit. */
.logoframe.foot{background:var(--ground);border-radius:3px;
  box-sizing:content-box;padding:.7rem .9rem}
.footaddr{font-family:var(--serif);margin-bottom:.6rem}
.sitefoot a{color:var(--on-navy-copper);text-decoration:none}
.sitefoot a:hover{color:#FFFFFF;text-decoration:underline}
.sitefoot p{color:var(--on-navy)}
.farm{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.1rem}
.farm a{display:block;padding:.42rem 0;font-size:.9rem}
.sitefoot .plain li{color:var(--on-navy-grey)}
.footrule{border-top:1px solid rgba(246,244,240,.22);margin-top:2rem;
  padding-top:1.2rem}
.footrule p{margin:0;font-size:.84rem;color:var(--on-navy-grey)}

/* Sweep: 390 · 640 · 860 · 1060 · 1440. Column steps go 1 to n, never
   1 to n-1 to n, and each breakpoint is computed gap-inclusive. */
/* Measured, not guessed: the full bar needs 211 (mark) + 753 (six items and
   the More control) + 150 (quote button) + 32 of gaps = 1146px of content
   width, and the wrap gives vw - 80 above 1000px, so the bar fits from
   1226px up. Below that it sheds to the disclosure rather than wrapping the
   quote button onto a second line and doubling the header. */
@media (max-width:1229px){
  .bar{display:none}
  .dup{display:block}
  .w-more{display:none}
  .w-menu{display:block}
}
@media (min-width:560px){
  .g-creds{grid-template-columns:repeat(2,1fr)}
  .g-team{grid-template-columns:repeat(2,1fr)}
  .g-quotes{grid-template-columns:repeat(2,1fr)}
  .g-strip{grid-template-columns:repeat(2,1fr)}
  .g-gallery{grid-template-columns:repeat(2,1fr)}
  .g-services{grid-template-columns:repeat(2,1fr)}
  .facts{grid-template-columns:repeat(2,1fr);column-gap:2rem}
  .footgrid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:559px){
  .g-creds{grid-template-columns:1fr}
}
@media (min-width:900px){
  .g-team{grid-template-columns:repeat(3,1fr)}
  .g-gallery{grid-template-columns:repeat(3,1fr)}
  .facts{grid-template-columns:repeat(3,1fr)}
  /* five columns, because the footer has five: a fourth-column rule left the
     fifth to wrap under the first and opened a dead gap beside it */
  .footgrid{grid-template-columns:1.35fr 1fr 1.25fr 1.1fr 1.15fr}
}
@media (min-width:1100px){
  .g-creds{grid-template-columns:repeat(4,1fr)}
  .g-quotes{grid-template-columns:repeat(4,1fr)}
  .g-strip{grid-template-columns:repeat(4,1fr)}
}
/* The service grid stops at two columns. Five columns leaves 179px of text even
   at 1440, and the longest name then breaks inside its own hyphen
   ("rough- / in") — a heading split at a word, not a wrap. Two divides ten, so
   the column rule still holds and no cell is left dead. Measured at 390, 640,
   860, 1060, 1230, 1360 and 1440. */

@media (prefers-reduced-motion:no-preference){
  .bar a,.morepanel a,.cta,.toc a,.card,.faq summary,.close,.ghost{
    transition:background-color .18s ease,color .18s ease,border-color .18s ease}
}
