/* ============================================================================
   BASE — identical on every Pittsburgh IT build. The visitor never sees any of it.
   Token NAMES are fixed; only the VALUES change per client. Everything below the
   token block is structural: the accessibility floor, the form skeleton, tap
   targets, the motion contract. Roughly 20 lines get rewritten per client and
   several hundred lines of quality are inherited.
   MOBILE FIRST — every rule here is the small-screen rule. Breakpoints add.
   ========================================================================== */
:root{
  --surface:#EDF0F1;
  --surface-2:#DFE5E7;
  --band:#18262C;
  --band-ink:#E7EDEF;
  --band-ink-2:#A9BAC1;
  --accent-on-band:#79C7C2;
  --ink:#101619;
  --ink-2:#434F55;
  --ink-3:#55636A;
  --accent:#0B5B63;
  --accent-2:#083F45;
  --accent-ink:#F2F7F8;
  --line:#C3CDD1;
  --maxw:1300px;
  --gutter:22px;
  --radius:0px;
  --font-display:'Bricolage Grotesque','Helvetica Neue',Helvetica,Arial,sans-serif;
  --font-body:'Chivo',system-ui,-apple-system,'Segoe UI',sans-serif;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{margin:0;background:var(--surface);color:var(--ink);
  font-family:var(--font-body);font-size:17px;line-height:1.62;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden}
img,svg,video{max-width:100%;height:auto;display:block}
h1,h2,h3,h4{font-family:var(--font-display);margin:0;line-height:1.08;
  font-weight:700;letter-spacing:-.032em}
p{margin:0 0 1em}
a{color:inherit}
ul{margin:0;padding:0;list-style:none}

/* --- container ------------------------------------------------------------ */
.container{width:100%;max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
@media(min-width:760px){:root{--gutter:34px}}
@media(min-width:1180px){:root{--gutter:48px}}

/* --- accessibility floor -------------------------------------------------- */
.skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--accent);
  color:var(--accent-ink);padding:12px 18px;border-radius:0 0 var(--radius) 0;
  font-weight:700;text-decoration:none}
.skip:focus{left:0}
:focus-visible{outline:3px solid var(--accent);outline-offset:3px;border-radius:2px}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);
  clip-path:inset(50%);white-space:nowrap}
/* honeypot: OFF-SCREEN, never display:none — a hidden field some bots skip,
   and a screen reader is told to leave it alone. */
.hp{position:absolute!important;left:-9999px;top:-9999px;width:1px;height:1px;
  opacity:0;pointer-events:none}

/* --- tap targets ---------------------------------------------------------- */
a,button,input,select,textarea,summary{font-family:inherit}
.btn,button,input[type=submit]{min-height:48px}
nav a,footer a{display:inline-block;min-height:24px}

/* --- button skeleton (templates restyle the skin, not the mechanics) ------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.55em;
  padding:14px 26px;border:1px solid transparent;border-radius:var(--radius);
  font-weight:650;font-size:16px;line-height:1.1;text-decoration:none;cursor:pointer;
  transition:transform .18s ease,background .18s ease,color .18s ease,border-color .18s ease,box-shadow .18s ease}
.btn:active{transform:translateY(1px)}
.btn-primary{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line)}

/* --- form skeleton -------------------------------------------------------- */
.form{display:grid;gap:16px}
.field{display:grid;gap:7px}
.field label{font-size:12.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink-2)}
.field input,.field select,.field textarea{
  width:100%;min-height:50px;padding:13px 15px;border:1px solid var(--line);
  border-radius:var(--radius);background:var(--surface);color:var(--ink);
  font-size:16px;/* 16px stops iOS zooming the page on focus */
  font-family:inherit;transition:border-color .18s ease,box-shadow .18s ease}
.field textarea{min-height:140px;resize:vertical;line-height:1.55}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(11,91,99,.24)}
.field ::placeholder{color:var(--ink-3);opacity:1}
.frow{display:grid;gap:16px}
@media(min-width:680px){.frow{grid-template-columns:1fr 1fr}}
.thanks{display:none;border:1px solid var(--line);border-radius:var(--radius);
  padding:28px;background:var(--surface-2)}
.thanks.show{display:block}
.thanks h3{font-size:24px;margin-bottom:10px}
.formerror{color:#8A2417;font-size:15px;font-weight:600;margin-top:10px}

/* --- MOTION CONTRACT ------------------------------------------------------
   Nothing starts hidden unless JavaScript has already run. The `js` class is set
   by an inline <head> script, and ONLY when prefers-reduced-motion is not set.
   No JS, blocked JS, old browser, or reduced motion => the page is simply visible.
   This is the inverse of how most sites do it, and it is why a script failure
   here cannot produce a blank page on a lead-generating site. */
html.js .reveal{opacity:0;transform:translateY(18px);
  transition:opacity .7s cubic-bezier(.22,.61,.36,1),transform .7s cubic-bezier(.22,.61,.36,1)}
html.js .reveal.in{opacity:1;transform:none}
html.js .reveal.d1{transition-delay:.08s}
html.js .reveal.d2{transition-delay:.16s}
html.js .reveal.d3{transition-delay:.24s}
@media(prefers-reduced-motion:reduce){
  html.js .reveal,html.js .reveal.in{opacity:1!important;transform:none!important;transition:none!important}
  *{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important}
}

/* --- nav skeleton --------------------------------------------------------- */
#nav{position:fixed;top:0;left:0;right:0;z-index:100;
  transition:background .25s ease,box-shadow .25s ease,border-color .25s ease}
.nav-inner{display:flex;align-items:center;justify-content:space-between;
  gap:16px;min-height:68px}
.navtoggle{display:inline-flex;align-items:center;justify-content:center;
  width:48px;height:48px;margin-right:-10px;background:none;border:0;
  color:inherit;cursor:pointer}
@media(min-width:940px){.navtoggle{display:none}}
.nav-links{display:none}
.nav-links.open{display:flex}
.nav-links{gap:0}
/* Desktop nav reset. Deliberately scoped to #nav so its specificity (1,1,0) beats any
   later `.nav-links{position:absolute…}` a template writes for its mobile drawer —
   equal specificity later in the file wins over a media query, which silently left the
   drawer stacked at the left edge on six of seven templates before this was scoped.
   It sets ONLY the structural properties that must not leak from mobile to desktop;
   gap, colour and type stay the template's business. */
@media(min-width:940px){
  #nav .nav-links,#nav .nav-links.open{display:flex;position:static;inset:auto;
    flex-direction:row;align-items:center;padding:0;margin:0;border:0;background:none;
    width:auto;height:auto;min-height:0;max-height:none;box-shadow:none;transform:none;
    visibility:visible;opacity:1;overflow:visible;
    gap:var(--nav-gap,32px)}
}
html.menu-open,html.menu-open body{overflow:hidden}

/* --- footer skeleton ------------------------------------------------------ */
footer a{text-decoration:none}
.credit{font-size:13.5px}
.credit a{text-decoration:underline;text-underline-offset:3px}

/* --- button rows ----------------------------------------------------------
   On a phone two CTAs sitting side by side at different intrinsic widths look
   accidental, and neither is a comfortable thumb target. They go full width until
   there is room for a row. Scoped as `.btnrow > .btn` (0,2,0) so a template's own
   `.btn{}` rule later in the file cannot silently undo it — the same cascade trap
   that left the desktop nav stacked. */
.btnrow{display:flex;flex-wrap:wrap;gap:12px}
.btnrow > .btn{flex:1 1 100%}
@media(min-width:560px){.btnrow > .btn{flex:0 0 auto}}

/* --- long-string guard ----------------------------------------------------
   A client email address or a compound word set in a heavy display face at
   20px uppercase does not wrap, and pushes a 390px page sideways. Found on the
   Ironworks contact page: dispatch@vantagemechanical.com forced the document to
   462px. Plumbing, so every template inherits the fix. */
/* Headings are deliberately NOT in this guard. break-word on a display heading
   shatters a word mid-syllable the moment its container is narrower than the word —
   it turned "Everything we make," into "Everyth / ing we / make," on Marquee. A
   heading that does not fit is a LAYOUT bug; fix the column, do not hyphenate it. */
h1,h2,h3,h4{overflow-wrap:normal;word-break:normal}
a[href^="mailto:"],a[href^="tel:"]{overflow-wrap:anywhere}
.crow span,.crow b,.cinfo span,address{overflow-wrap:anywhere}

/* --- utility -------------------------------------------------------------- */
.sec{padding:64px 0}
@media(min-width:760px){.sec{padding:96px 0}}
@media(min-width:1180px){.sec{padding:124px 0}}
.eyebrow{font-size:12px;font-weight:750;letter-spacing:.16em;text-transform:uppercase;
  color:var(--accent);margin:0 0 14px}
.lead{font-size:19px;line-height:1.6;color:var(--ink-2)}
@media(min-width:760px){.lead{font-size:21px}}


/* ============================================================================
   FRONTAGE — the shop's street elevation, seen from the pavement.

   THE APERTURE. --ap is one number and it is the height of every window on this
   page: the hero, the four bays, the solid bay on the slate band, the two bays on
   the 404. A photograph appears through that rectangle or it does not appear. The
   height never changes; how many are across, what stands beside them and how dense
   the block above and below is — those are the only things that vary.

   LIGHT LOGIC: OVERCAST DAYLIGHT, FRONT ON. An overcast sky is a source the size
   of the sky. Nothing has a lit side and nothing casts. So grep this file for
   `box-shadow` and every hit is `inset 0 1px 0` — no offset, no blur, no spread,
   no vignette, no glow, no gradient used as a surface. One hairline catch on the
   TOP edge of six different component types, because on a grey afternoon the only
   thing that catches light is an upward-facing edge. 01-nightwork has one raking
   lamp; 02-open decided to have no light at all; this has the whole sky.

   And the sky is ON THE GLASS. From the street the inside of a shop is always
   darker than the pavement and the sky is lying across the window, so the grade
   strips the colour and flattens it (--grade) and a flat veil of sky (--haze) is
   screened over every aperture. That is why the pictures are dark on pale paper —
   it is what a shopfront looks like, not a contradiction.

   MOBILE FIRST. Every rule here is the phone rule; breakpoints only add.
   ========================================================================== */

:root{
  /* THE APERTURE. 200px on the phone; 20.8vw from 760 up, which is 1/4.81 — so a
     full-bleed aperture is 4.80:1 at 1440, at 1920 and at 2560 and the hero plate
     never drifts from its asset. Clamped at both ends so it can neither collapse
     to a letter-slot on a small tablet nor eat a 4K first screen. */
  --ap:200px;
  --grade:saturate(.32) contrast(.82) brightness(1.26);
  --haze:rgba(178,205,216,.19);       /* the sky lying on the glass          */
  --sky:rgba(255,255,255,.80);        /* the catch on a paper top edge       */
  --sky-band:rgba(231,237,239,.26);   /* the same catch on slate             */
  --hair:1px solid var(--line);
  --hair-band:1px solid rgba(231,237,239,.22);
  --nav-h:68px;
  --nav-gap:30px;
}
@media(min-width:760px){:root{--ap:clamp(260px,20.8vw,540px)}}
/* Jon works on a 28-inch display. One 1300px column centred in 2560px of paper
   reads as a phone layout that stopped growing, so the measure opens once and the
   full-bleed elevation does the rest. */
@media(min-width:1700px){:root{--maxw:1440px;--gutter:60px}}

/* ---------------------------------------------------------------- type ----- */
body{background:var(--surface)}
/* 44px floor, not 38: DESIGN-FLOOR C2 wants the largest type at 2.5x body and
   body is 17px, so anything under 42.5 fails at 390 while passing at 1440. */
h1{font-size:clamp(44px,5.4vw,92px);line-height:1.0;letter-spacing:-.035em;margin:0}
.h-lg{font-size:clamp(29px,3.5vw,48px);line-height:1.04;letter-spacing:-.03em}
.h-md{font-size:clamp(23px,2.5vw,32px);line-height:1.12;letter-spacing:-.024em}
h3{font-size:18px;line-height:1.28;letter-spacing:-.014em;font-weight:700}
.measure{max-width:60ch}
.lead{color:var(--ink-2)}
/* the lettering face: everything that behaves like painted lettering on a shop —
   fascia labels, ticket chips, captions, the register numbers, form labels — is
   the body face at small size, uppercase, wide tracking. Nothing else is. */
.fl,.fr,.chip,.bay figcaption span,.kerb span,.kerb a,.fh,.drawlab,.mgh,.towns span,
.field label,.solidbay figcaption,.fplain.lab,.fnav a,.mnote{
  text-transform:uppercase;letter-spacing:.15em;font-weight:600;font-size:10.5px}

/* -------------------------------------------------------------- imagery ----
   ONE grade, ONE rule, every photograph on the page — and the cool cast is NOT in
   it. --grade desaturates, flattens and lifts; --haze puts the sky back on top in
   screen blend, so the cool arrives in the shadows the way an overcast sky puts it
   there rather than as an even wash, which is what reads as a filter. There is no
   second filter declaration in this file and there must never be one. */
.apf img{filter:var(--grade)}

/* THE APERTURE ITSELF. Fixed height, no radius, no frame line — the only edge it
   has is the 1px of sky along its top, the same catch every other component on the
   page carries. isolation:isolate keeps the screen blend inside the window. */
.ap{display:block;position:relative}
.apf{display:block;position:relative;height:var(--ap);overflow:hidden;isolation:isolate;
  background:var(--surface-2);box-shadow:inset 0 1px 0 var(--sky)}
.apf img{width:100%;height:100%;object-fit:cover;object-position:50% 50%}
.apf::after{content:"";position:absolute;inset:0;background:var(--haze);
  mix-blend-mode:screen;pointer-events:none}

/* ------------------------------------------------------------ preview bar --
   Demo-only chrome, and it has to get out of the masthead's way: in normal flow
   the fixed nav simply covers it and the wordmark prints on top of the bar's own
   words (the defect 05-plate shipped). Pinned above the nav, and the nav is given
   a matching padding-top published as --tpl-h. No `top` and no `position` is
   declared on #nav — the shared floor owns those and houserules.py enforces it. */
.tplbar{position:fixed;top:0;left:0;right:0;z-index:130;background:var(--band);
  color:var(--band-ink-2);font-size:11.5px;line-height:1.4;letter-spacing:.02em;
  padding:8px var(--gutter);text-align:center}
.tplbar b{color:var(--band-ink)}
:root:has(.tplbar){--tpl-h:54px}
@media(min-width:760px){:root:has(.tplbar){--tpl-h:32px}}
#nav{padding-top:var(--tpl-h,0px)}

/* -------------------------------------------------- THE MASTHEAD = FASCIA --
   Lettering across the top of a shopfront. Paper, one hairline underneath, the
   name at the left, the number at the right. Nothing translucent, blurred or
   shadowed; scrolling darkens the hairline and nothing else moves. */
#nav{background:var(--surface);border-bottom:1px solid transparent}
#nav.scrolled{border-bottom-color:var(--line)}
.nav-inner{gap:12px;flex-wrap:wrap}
.brand{display:inline-flex;align-items:center;gap:12px;text-decoration:none;
  color:var(--ink);min-height:44px}
.mark{display:inline-flex;align-items:center;justify-content:center;width:30px;
  height:30px;font-size:11px;font-weight:700;letter-spacing:.04em;color:var(--accent);
  border:1px solid var(--accent);box-shadow:inset 0 1px 0 var(--sky)}
.brandtype{font-family:var(--font-display);font-size:20px;font-weight:700;
  letter-spacing:-.032em;white-space:nowrap}
.navtel{display:none}
.navtoggle .bars{display:block;width:22px}
.navtoggle .bars i{display:block;height:1px;margin:6px 0;background:var(--ink)}
.navtoggle .bars i:nth-child(2){width:14px}
.nav-links{flex:1 0 100%;flex-direction:column;align-items:stretch;gap:0;width:100%;
  padding:4px 0 14px;margin-top:6px;border-top:var(--hair)}
.nav-links a{color:var(--ink-2);text-decoration:none;font-size:16px;font-weight:500;
  padding:11px 0;min-height:44px;display:flex;align-items:center;
  border-bottom:var(--hair)}
.nav-links a:hover{color:var(--accent)}
.drawlab{color:var(--accent);margin:10px 0 2px}
.drawhours{font-size:14px;color:var(--ink-2);margin:0 0 8px}
.drawtel{font-family:var(--font-display)!important;font-size:22px!important;
  font-weight:700!important;letter-spacing:-.02em!important;color:var(--ink)!important}
.navcta{background:var(--accent);color:var(--accent-ink)!important;
  justify-content:center!important;border-bottom:0!important;margin-top:12px;
  font-family:var(--font-display)!important;font-size:15px!important;font-weight:700;
  letter-spacing:0;box-shadow:inset 0 1px 0 var(--sky-band)}
html.menu-open #nav{border-bottom-color:var(--line)}

@media(min-width:940px){
  .nav-inner{flex-wrap:nowrap;gap:26px}
  .navtel{display:inline-flex;align-items:center;min-height:44px;margin-left:auto;
    padding-right:24px;border-right:var(--hair);font-family:var(--font-display);
    font-size:16px;font-weight:600;letter-spacing:-.02em;color:var(--ink);
    text-decoration:none}
  .navtel:hover{color:var(--accent)}
  .nav-links{flex:0 0 auto;width:auto;padding:0;margin:0;border:0}
  /* two classes, not one: `.nav-links a` is (0,1,1) and beats a bare `.drawtel`
     (0,1,0), which is how a drawer's 22px telephone number ends up printed in a
     desktop masthead. 02-open found that on the render, not in the file. */
  .nav-links a{width:auto;padding:0;border-bottom:0;font-size:11px;font-weight:600;
    letter-spacing:.15em;text-transform:uppercase;color:var(--ink-2)}
  .nav-links .drawlab,.nav-links .drawhours,.nav-links .drawtel{display:none}
  .navcta{height:40px;margin-top:0;padding:0 18px!important;
    font-size:13px!important;letter-spacing:0}
}

/* ------------------------------------------------------------- THE HERO ----
   One full-bleed aperture, and THE BOARD hanging off it. The board's top is a
   CONSTANT 104px (phone) / 140px (desktop) below the top of the aperture at every
   width: --ap grows with the viewport and the negative margin grows with it, so
   the headline does not move and a letterbox hero and the 300px fold rule stop
   fighting. The h1's box is inside the picture's box (A1) and the picture frames
   it above and to the right. No scrim, no gradient, no shadow — the type is
   legible because it is painted on a sign. */
.hero{background:var(--surface);padding:calc(var(--nav-h) + var(--tpl-h,0px)) 0 0}
.board{position:relative;background:var(--band);color:var(--band-ink);
  margin:calc(112px - var(--ap)) calc(var(--gutter) * -1) 0;
  padding:20px var(--gutter) 26px;box-shadow:inset 0 1px 0 var(--sky-band)}
.kick{margin:0 0 12px;font-size:10.5px;font-weight:600;letter-spacing:.18em;
  text-transform:uppercase;color:var(--accent-on-band)}
h1 .h1a{display:block;color:var(--band-ink)}
/* THE DRAWN MOMENT — the painted sign. Same face, same size, printed the other way
   round: ink on a paper rectangle inside the slate board. box-decoration-break so a
   wrap gives two painted panels rather than one broken one. */
h1 .h1b{font-style:normal;color:var(--ink);background:var(--surface);
  padding:.03em .14em;-webkit-box-decoration-break:clone;box-decoration-break:clone}
.board .lead{margin:16px 0 0;font-size:16.5px;line-height:1.55;color:var(--band-ink-2);
  max-width:44ch}
.board .btnrow{margin-top:20px}
/* the street line under the sign: what somebody standing outside actually wants. */
.kerb{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 22px;margin:22px 0 0;
  padding-top:11px;border-top:var(--hair)}
.kerb span,.kerb a{color:var(--ink-3)}
.kerb .kerb-h{color:var(--accent)}
.kerb a{text-decoration:none;min-height:24px;display:inline-block}
@media(min-width:560px){.kerb a{margin-left:auto}}
.kerb a:hover{color:var(--accent)}
.kerb span,.kerb a{overflow-wrap:anywhere}

@media(min-width:560px){.board .lead{font-size:17.5px}}
@media(min-width:820px){
  .board{margin:calc(140px - var(--ap)) 0 0;width:min(700px,58%);
    padding:28px 34px 32px}
  .kick{margin-bottom:16px}
  .board .lead{margin-top:20px;font-size:19px;line-height:1.52}
  .board .btnrow{margin-top:26px}
  .kerb{margin-top:30px}
}
@media(min-width:1700px){
  .board{width:min(880px,60%);padding:34px 44px 40px}
}

/* --------------------------------------------------- THE FASCIA + SECTIONS --
   Every section opens on a full-bleed hairline with its name hanging under it at
   the left and a real piece of the shop's data printed at the right — hours, area,
   address, telephone. Delete a fascia and information is lost, which is the test
   it has to pass to be allowed on the page at all. */
.sec{padding:0 0 44px;background:var(--surface)}
.secin{padding-top:34px}
@media(min-width:760px){.sec{padding-bottom:84px}.secin{padding-top:56px}}
@media(min-width:1180px){.sec{padding-bottom:104px}.secin{padding-top:66px}}
.fascia{border-top:var(--hair)}
.fascia .container{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 18px;
  padding-top:9px;padding-bottom:0}
.fl{color:var(--accent)}
.fr{color:var(--ink-3);overflow-wrap:anywhere}
@media(min-width:640px){.fr{margin-left:auto;text-align:right}}
.fascia.onband{border-top:var(--hair-band)}
.fascia.onband .fl{color:var(--accent-on-band)}
.fascia.onband .fr{color:var(--band-ink-2)}
.shead,.ahead,.chead{max-width:800px}
.shead .h-lg,.chead .h-lg{margin-bottom:14px}
.shead .lead,.chead .lead{margin:0}

/* ---------------------------------------------------- PRICES (paper, dense) --
   Rows on hairlines, no cards, no imagery. The second axis is the TICKET: the
   outlined chip carrying services[].tag sits on the row's top line, before the
   name, because on a shopfront the ticket in the window is what is read first. */
.rows{margin-top:26px;border-top:1px solid var(--ink)}
.prow{display:grid;grid-template-columns:1fr auto;column-gap:16px;row-gap:6px;
  padding:16px 0;border-bottom:var(--hair)}
.chip{grid-column:1;grid-row:1;justify-self:start;color:var(--ink-3);
  padding:5px 9px;border:var(--hair);box-shadow:inset 0 1px 0 var(--sky);
  line-height:1}
.pn{grid-column:1;grid-row:2;color:var(--ink);align-self:center}
.pp{grid-column:2;grid-row:1 / span 2;align-self:center;font-family:var(--font-display);
  font-size:clamp(26px,2.6vw,38px);font-weight:700;letter-spacing:-.035em;
  color:var(--ink);white-space:nowrap;font-variant-numeric:tabular-nums}
.pb{grid-column:1;grid-row:3;margin:0;font-size:14.5px;line-height:1.55;
  color:var(--ink-2);max-width:58ch}
.bfoot{margin:24px 0 0;font-size:14px;color:var(--ink-3);max-width:60ch}
.mgroup{margin-top:32px}
.mgh{color:var(--accent);padding-bottom:9px;border-bottom:1px solid var(--ink)}
.mrow{display:grid;grid-template-columns:1fr auto;column-gap:16px;padding:11px 0;
  border-bottom:var(--hair)}
.mn{color:var(--ink);font-weight:600;font-size:15px}
.mnote{grid-column:1;color:var(--ink-3)}
.mp{grid-column:2;grid-row:1 / span 2;align-self:center;font-family:var(--font-display);
  font-size:19px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
@media(min-width:760px){
  .prow{grid-template-columns:118px 1fr auto;column-gap:28px;row-gap:4px;padding:18px 0}
  .chip{grid-column:1;grid-row:1 / span 2;align-self:start;margin-top:5px}
  .pn{grid-column:2;grid-row:1;font-size:21px;align-self:start}
  .pb{grid-column:2;grid-row:2;font-size:15px}
  .pp{grid-column:3;grid-row:1 / span 2}
}

/* --------------------------------------------- THE FRONT (the elevation) ----
   Four bays at exactly --ap, one across on the phone and two from 760, edge to
   edge of the viewport and BUTTED: 1px of paper between them and nothing else. Not
   a gallery of cards — a run of windows. The caption under each is the stallriser:
   what it is at the left, what it costs or where it is at the right. */
.bays{display:grid;grid-template-columns:1fr;gap:1px;background:var(--line);
  margin-top:30px;border-top:var(--hair);border-bottom:var(--hair)}
.bay{margin:0;background:var(--surface)}
.bay figcaption{display:flex;justify-content:space-between;align-items:baseline;
  gap:12px;padding:9px 14px 11px}
.bay figcaption b{font-size:13.5px;font-weight:700;color:var(--ink);
  letter-spacing:-.012em}
.bay figcaption span{color:var(--ink-3);white-space:nowrap}
.facts{margin-top:34px;border-top:1px solid var(--ink)}
.fact{padding:16px 0;border-bottom:var(--hair)}
.fact h3{color:var(--ink)}
.fact p{margin:5px 0 0;font-size:14.5px;color:var(--ink-2);max-width:58ch}
@media(min-width:760px){
  .bays{grid-template-columns:1fr 1fr;margin-top:44px}
  .facts{display:grid;grid-template-columns:repeat(3,1fr);column-gap:34px;margin-top:52px}
  .fact{border-bottom:0;border-right:var(--hair);padding:18px 26px 4px 0}
  .fact:last-child{border-right:0}
}

/* ------------------------------------------------- REGULARS (the slate) -----
   The one dark surface and the only change of paper. A ruled register rather than
   three cards, and beside it THE SOLID BAY — a bay exactly --ap tall with no glass
   in it, carrying the review. That is what makes the aperture a module instead of
   a picture frame: the same rectangle works with a photograph behind it or a
   sentence inside it. */
.slate{background:var(--band);color:var(--band-ink)}
.slate h2,.slate h3{color:var(--band-ink)}
.slate .lead{color:var(--band-ink-2)}
.regwrap{display:grid;gap:30px;margin-top:0}
.regleft .shead{margin-bottom:26px;max-width:none}
.reg{border-top:var(--hair-band)}
.regrow{padding:17px 0;border-bottom:var(--hair-band)}
.regrow p{margin:6px 0 0;font-size:15px;line-height:1.6;color:var(--band-ink-2);
  max-width:64ch}
.regrow:last-child{border-bottom:0}
.solidbay{margin:0;min-height:var(--ap);display:flex;flex-direction:column;
  justify-content:flex-start;gap:20px;padding:20px;border:var(--hair-band);
  box-shadow:inset 0 1px 0 var(--sky-band)}
.solidbay blockquote{margin:0;font-family:var(--font-display);font-weight:600;
  font-size:clamp(17px,1.9vw,27px);line-height:1.38;letter-spacing:-.024em;
  color:var(--band-ink)}
.solidbay figcaption{color:var(--accent-on-band)}
@media(min-width:900px){
  .regwrap{grid-template-columns:1.12fr .88fr;column-gap:52px;align-items:start;
    margin-top:0}
  .regleft .shead{margin-bottom:38px}
  .regrow{display:grid;grid-template-columns:264px 1fr;column-gap:30px;
    align-items:baseline;padding:20px 0}
  .regrow h3{font-size:19px}
  .regrow p{margin:0}
  .solidbay{padding:26px}
}

/* ----------------------------------------------------------- QUESTIONS ------ */
.asklist{margin-top:20px;border-top:1px solid var(--ink)}
.ask{border-bottom:var(--hair)}
.ask summary{display:flex;align-items:center;justify-content:space-between;gap:18px;
  padding:15px 0;min-height:54px;cursor:pointer;list-style:none;font-weight:600;
  font-size:15.5px;color:var(--ink)}
.ask summary::-webkit-details-marker{display:none}
.ask summary:hover{color:var(--accent)}
.ask summary i{flex:0 0 auto;width:11px;height:11px;position:relative}
.ask summary i::before,.ask summary i::after{content:"";position:absolute;
  background:var(--accent)}
.ask summary i::before{left:0;top:5px;width:11px;height:1px}
.ask summary i::after{left:5px;top:0;width:1px;height:11px}
.ask[open] summary i::after{opacity:0}
.ask p{margin:0;padding:0 0 18px;font-size:14.5px;line-height:1.62;color:var(--ink-2);
  max-width:64ch}
.askcall{margin:14px 0 0;font-size:14px;line-height:1.6;color:var(--ink-3);max-width:34ch}
.askcall a{display:inline-flex;align-items:center;min-height:44px;
  font-family:var(--font-display);font-size:21px;font-weight:700;letter-spacing:-.02em;
  color:var(--ink);text-decoration:none}
.askcall a:hover{color:var(--accent)}
/* a narrow column beside its own heading from 900. Four short rows run across a
   1320px measure is restraint that reads as unfinished — a D5 deduction, not
   minimalism. */
@media(min-width:900px){
  .asks .secin{display:grid;grid-template-columns:.78fr 1.22fr;column-gap:56px;
    align-items:start}
  .asklist{margin-top:0}
}

/* ------------------------------------------------------------- THE DOOR ----- */
.door{background:var(--surface-2)}
.week{margin-top:0;border-top:1px solid var(--ink)}
.wrow{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:11px 0;border-bottom:var(--hair)}
.wd{font-size:15px;font-weight:600;color:var(--ink)}
.wt{font-family:var(--font-display);font-size:15px;font-weight:600;color:var(--ink-2);
  white-space:nowrap;font-variant-numeric:tabular-nums}
.cgrid{display:grid;gap:32px;margin-top:32px}
.crow{display:flex;flex-direction:column;gap:2px;margin-top:24px}
.cbig{display:inline-flex;align-items:center;min-height:44px;align-self:flex-start;
  font-family:var(--font-display);font-size:clamp(19px,2.1vw,25px);font-weight:700;
  letter-spacing:-.03em;color:var(--ink);text-decoration:none;
  border-bottom:1px solid transparent}
.cbig:hover{color:var(--accent);border-bottom-color:var(--accent)}
.crow address{font-style:normal;font-size:14px;color:var(--ink-3);margin-top:6px}
.area{margin-top:24px;padding-top:18px;border-top:var(--hair)}
.area h3{color:var(--ink)}
.area p{margin:7px 0 0;font-size:14.5px;color:var(--ink-2)}
.towns{display:flex;flex-wrap:wrap;gap:6px}
.towns span{color:var(--ink-3);padding:5px 9px;border:var(--hair);
  box-shadow:inset 0 1px 0 var(--sky)}
.formpanel{background:var(--surface);border:var(--hair);padding:22px 20px;
  box-shadow:inset 0 1px 0 var(--sky)}
.field label{color:var(--ink-3)}
.field input,.field select,.field textarea{background:var(--surface);
  border-color:var(--line);color:var(--ink)}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--accent)}
.fineprint{margin:14px 0 0;font-size:12.5px;line-height:1.55;color:var(--ink-3)}
.thanks{background:var(--surface);border:var(--hair);border-radius:0;
  box-shadow:inset 0 1px 0 var(--sky)}
.thanks h3{font-family:var(--font-display);font-size:24px;color:var(--ink)}
.thanks p{margin:0;color:var(--ink-2)}
@media(min-width:900px){
  .cgrid{grid-template-columns:.84fr 1.16fr;column-gap:54px;align-items:start}
  .formpanel{padding:30px 28px}
}
@media(min-width:1180px){.cgrid{grid-template-columns:.8fr 1.2fr;column-gap:70px}}

/* ----------------------------------------------------------------- BUTTONS -- */
.btn{border-radius:0;font-family:var(--font-display);font-size:15px;font-weight:700;
  letter-spacing:-.012em;padding:15px 24px}
.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);
  box-shadow:inset 0 1px 0 var(--sky-band)}
.btn-primary:hover{background:var(--accent-2);border-color:var(--accent-2)}
.btn-ghost{background:transparent;color:var(--band-ink);border-color:var(--band-ink-2)}
.btn-ghost:hover{color:var(--band-ink);border-color:var(--band-ink)}
/* the ghost button lives on the slate board in the hero and on the slate 404 board
   and NOWHERE else, so it is coloured for slate and the paper case is a separate
   two-class rule rather than a hopeful override. */
.sec .btn-ghost,.formpanel .btn-ghost{color:var(--ink);border-color:var(--ink)}
.board .btn-ghost{color:var(--band-ink);border-color:var(--band-ink-2)}

/* ------------------------------------------------------------------ FOOTER -- */
footer{background:var(--surface-2);padding:0 0 26px}
.ffascia{border-top:1px solid var(--ink)}
.fgrid{display:grid;gap:28px;padding-top:34px}
.mark.big{width:40px;height:40px;font-size:14px}
.fname{font-family:var(--font-display);font-size:22px;font-weight:700;
  letter-spacing:-.032em;color:var(--ink);margin:14px 0 6px}
.fabout{margin:0;font-size:14px;color:var(--ink-2);max-width:44ch}
.fh{color:var(--accent);margin-bottom:10px;padding-bottom:8px;border-bottom:var(--hair)}
.fcol{display:flex;flex-direction:column;gap:4px}
.fcol a{color:var(--ink-2);font-size:14px;text-decoration:none;
  display:inline-flex;align-items:center;min-height:44px}
.fplain{color:var(--ink-2);font-size:14px;line-height:1.5;margin-top:2px}
.fplain.lab{color:var(--ink-3);line-height:1.9;margin-top:0}
.fcol a:hover{color:var(--accent)}
.fcol address{font-style:normal;font-size:14px;color:var(--ink-3)}
.fnav{display:flex;flex-wrap:wrap;gap:6px 24px;margin-top:30px;padding-top:16px;
  border-top:var(--hair)}
.fnav a{display:inline-flex;align-items:center;min-height:44px;color:var(--ink-3);
  text-decoration:none}
.fnav a:hover{color:var(--accent)}
.fbase{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 24px;
  margin-top:16px;font-size:12.5px;color:var(--ink-3)}
.credit a{color:var(--ink-2)}
@media(min-width:760px){
  .fgrid{grid-template-columns:1.6fr 1fr 1fr;gap:40px;padding-top:52px}
  .fcol a,.fnav a{min-height:26px}
  footer{padding-bottom:30px}
}

/* --------------------------------------------------------------------- 404 --
   The 404 IS the hero: same aperture, same board, same kerb line. It needs no
   rules of its own beyond a slightly shorter headline step, because the whole
   composition is already a component. The bays below it are the ordinary run. */
.nfrun{padding-bottom:0}
.nfrun .bays{margin-top:0;border-bottom:0}
.nf h1{font-size:clamp(44px,4.6vw,72px)}
/* 44px is a floor, not a taste call: body is 17px and DESIGN-FLOOR C2 wants the
   largest type at 2.5x it. A 40px minimum measured 2.35x and FAILED C2 at 390 on
   the deployed 404 while passing at 1440 and 2560. */

/* ------------------------------------------------------------------ MOTION --
   Two moments, and both say what the layout says.
   1. the house reveal — every section below the hero fades up, staggered;
   2. THE SHUTTER — a bay's photograph opens downward out of its own top edge when
      the run arrives, the way a shopfront shutter goes up. It is a clip on the
      IMAGE, inside an element that has already been revealed, so nothing that the
      observer needs to see is ever a zero-area box.
   Both are gated behind html.js, which the head script only sets when the visitor
   has not asked for reduced motion. The hero is exempt from both: its aperture and
   its headline are painted the instant the page arrives. */
@keyframes shutter{from{clip-path:inset(0 0 100% 0)}to{clip-path:inset(0 0 0 0)}}
html.js .reveal.in .apf img{animation:shutter .72s cubic-bezier(.22,.61,.36,1) both}
html.js .reveal.in .bay:nth-child(2) .apf img{animation-delay:.09s}
html.js .reveal.in .bay:nth-child(3) .apf img{animation-delay:.18s}
html.js .reveal.in .bay:nth-child(4) .apf img{animation-delay:.27s}
html.js .reveal.in .bay:nth-child(5) .apf img{animation-delay:.36s}
html.js .reveal.in .bay:nth-child(6) .apf img{animation-delay:.45s}
html.js .reveal.in .bay:nth-child(7) .apf img{animation-delay:.54s}
@media(prefers-reduced-motion:reduce){
  html.js .reveal.in .apf img{animation:none;clip-path:none}
}
