/* ============================================================================
   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:#CDBDA5;
  --surface-2:#F0E8DB;
  --band:#2B2119;
  --band-ink:#F1E9DC;
  --band-ink-2:#BEB09D;
  --accent-on-band:#E3A44F;
  --ink:#1C1610;
  --ink-2:#453A2C;
  --ink-3:#544737;
  --accent:#7C2708;
  --accent-2:#5E1C04;
  --accent-ink:#FDF4E8;
  --line:#A8967D;
  --maxw:1200px;
  --gutter:22px;
  --radius:3px;
  --font-display:'Zilla Slab',Georgia,'Times New Roman',serif;
  --font-body:'Karla',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:-.018em}
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(124,39,8,.26)}
.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:#7C2708;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:62px}
.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}}


/* ============================================================================
   PLATE — one source directly overhead, camera looking down at a table.

   LIGHT LOGIC. Everything on this page is a physical OBJECT lying on a warm
   mid-tone surface. There are no panels, no cards-as-UI and no bands: there is
   a table, and there are things on it. Four custom properties carry the whole
   idea and ONE rule composes them:

     --shade   the shadow's own colour, as a bare `r g b` triple. Warm, never
               grey — a shadow on a wooden table is brown.
     --lift    UNITLESS, per component. How far off the table that object sits.
     --tilt    that object's own angle. Nothing dropped on a table lands square.
     --cast    composed in `.lay` from the two above.

   Every term of every cast has an X OFFSET OF ZERO, because a source directly
   overhead has no direction to throw in. Grep this file for `box-shadow` and
   check it: there is not one non-zero x anywhere, and not one glow, rim, or
   sideways throw. Because the y-offset, blur and spread are all calc()'d from
   --lift, a thing that sits higher automatically casts softer, wider and
   weaker. The physics is in the arithmetic, not in a value tuned per component.

   The inverse is --press: a RECESS. Shade at the TOP inner edge, light caught
   on the bottom edge — what a slot cut into a surface does under a lamp
   directly above it. It is used for exactly two things and both of them are
   ABSENCES: a price nobody has sent, and a week nobody has published.

   THE DELETE TEST. Comment out the `.lay` block below and this page does not
   degrade, it COLLAPSES. The palette is deliberately narrow — 1.5:1 from the
   table to the top sheet — and there is no border, no rule and no colour change
   between an object and the surface it is lying on. Take the cast away and
   every object on the page loses its edge at once.

   THE ORIENTATION RULE. Below the hero there is no aspect-ratio, no
   object-fit and no fixed height on any photographic frame: THE FLOOR is a
   column flow and each print is exactly as tall as the picture in it. The HERO
   is exempt by name — it is art-directed, it is ours, and a client's own
   photographs never land in it.

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

:root{
  --grade:saturate(.84) contrast(1.06) brightness(1.02) sepia(.12);
  --nav-h:62px;
  --nav-gap:28px;

  /* the shadow's own colour — a triple, not a colour, so alpha varies per term */
  --shade:38 28 18;

  /* THE TONAL LADDER. Three surfaces, 1.5:1 from bottom to top, and the two
     that are not palette tokens are DERIVED so they survive any repaint. A
     color-mix in sRGB lands between its endpoints in luminance, so any ink that
     clears 4.5:1 against both endpoints clears it against the mix — which is
     why every ink used on --sheet is declared in contrast_pairs against BOTH
     --surface and --surface-2, and every ink used on --brick against --band. */
  --sheet:color-mix(in srgb, var(--surface-2) 62%, var(--surface));
  --brick:color-mix(in srgb, var(--band-ink) 9%, var(--band));

  /* a recess cut into a surface: shade at the top inner edge, light on the
     bottom edge. The exact inverse of a cast, from the same source. */
  --press:inset 0 2px 3px rgb(var(--shade)/.30), inset 0 -1px 0 rgba(255,251,244,.55);
  /* the 1px highlight an object's own top face takes from the lamp */
  --catch:inset 0 1px 0 rgba(255,252,246,.42);
  --hair:1px solid var(--line);
}

/* A 28-inch display is where this gets looked at. The measure opens once and the
   mat and the mosaic do the rest at that size. */
@media(min-width:1700px){:root{--maxw:1340px;--gutter:64px}}

/* ============================================================================
   THE LAY — the signature, and the whole design, in one rule.
   FIFTEEN components read it (counted, 2026-08-14). Nothing else in this file
   declares a cast: the only other box-shadows are the scrolled masthead, the
   focus ring, and --press / --catch, which are inset and are the inverse.
   ========================================================================== */
.herosay,.heroplate,.h1b,.slip,.hook,.print,.note,.mat,.brick,.qslip,
.ask,.card,.panel,.mark,.mrows{
  --lift:10;
  transform:rotate(var(--tilt,0deg));
  box-shadow:
    0 calc(var(--lift) *  .16px) calc(var(--lift) *  .34px) calc(var(--lift) * -.06px) rgb(var(--shade)/.34),
    0 calc(var(--lift) *  .55px) calc(var(--lift) * 1.20px) calc(var(--lift) * -.30px) rgb(var(--shade)/.24),
    0 calc(var(--lift) * 1.10px) calc(var(--lift) * 2.60px) calc(var(--lift) * -.70px) rgb(var(--shade)/.13);
}

/* ---------------------------------------------------------------- type ----- */
body{background:var(--surface)}
h1{font-size:clamp(43px,9.6vw,60px);line-height:1.0;letter-spacing:-.028em;margin:0}
@media(min-width:760px){h1{line-height:1.04}}
.h-lg{font-size:clamp(28px,3.5vw,40px);line-height:1.08;letter-spacing:-.022em}
.h-md{font-size:clamp(24px,2.6vw,30px);line-height:1.14;letter-spacing:-.018em}
h3{font-size:18px;line-height:1.26;letter-spacing:-.01em;font-weight:600}
.measure{max-width:60ch}
.lead{color:var(--ink-2)}
.eyebrow{font-size:11px;font-weight:700;letter-spacing:.19em;color:var(--accent);margin:0 0 13px}
.eyebrow.onband{color:var(--accent-on-band)}
.lead.onband{color:var(--band-ink-2)}

/* -------------------------------------------------------------- imagery ----
   ONE grade, one rule, every photograph on the page. There is no second filter
   in this file and there must never be one. */
.heroplate img,.print img{filter:var(--grade)}

/* ------------------------------------------------------------ preview bar --
   Pinned above the nav; the nav takes its height as padding so the wordmark can
   never print on top of the bar's own words. */
.tplbar{position:fixed;top:0;left:0;right:0;z-index:130;background:var(--band);
  color:var(--band-ink-2);font-size:12px;line-height:1.35;letter-spacing:.02em;
  padding:9px 16px;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)}

/* -------------------------------------------------------------------- nav --
   The masthead is a strip lying ON the page, not a bar floating over it. At
   rest it is flat against the table; scrolling LIFTS it and the cast appears
   underneath. That is the only state change in the nav and it is the only cue
   that the page has moved. No `top` and no `position` is declared on #nav
   anywhere in this file — the shared floor owns those. */
#nav{background:var(--surface);transition:box-shadow .26s ease}
#nav.scrolled{box-shadow:
  0 2px 4px -1px rgb(var(--shade)/.26),
  0 8px 18px -8px rgb(var(--shade)/.30),
  0 18px 40px -22px rgb(var(--shade)/.20)}
.nav-inner{gap:12px;flex-wrap:wrap}
.brand{display:inline-flex;align-items:center;gap:12px;text-decoration:none;
  min-height:44px;color:var(--ink)}
.mark{--lift:9;--tilt:-3deg;display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;flex:0 0 auto;background:var(--surface-2);color:var(--ink);
  font-family:var(--font-display);font-size:14px;font-weight:700;letter-spacing:.01em;
  border-radius:2px}
.brandtype{font-family:var(--font-display);font-size:19px;font-weight:700;
  letter-spacing:-.02em;line-height:1}
.navtel{display:none}
.navtoggle .bars{display:block;width:22px}
.navtoggle .bars i{display:block;height:2px;margin:5px 0;background:var(--ink);border-radius:1px}
.navtoggle .bars i:nth-child(2){width:14px}
.nav-links{flex:1 0 100%;flex-direction:column;align-items:stretch;gap:0;
  padding:6px 0 16px;border-top:var(--hair)}
.nav-links a{color:var(--ink-2);text-decoration:none;font-size:16.5px;font-weight:500;
  width:100%;padding:13px 0;border-bottom:var(--hair);min-height:48px}
.nav-links a:hover{color:var(--accent)}
.drawlab{margin:14px 0 2px;font-size:11px;font-weight:700;letter-spacing:.19em;
  text-transform:uppercase;color:var(--ink-3)}
.drawhours{margin:0 0 8px;font-size:15px;color:var(--ink-2)}
.navcta{background:var(--accent);color:var(--accent-ink)!important;
  border-bottom:0!important;text-align:center;margin-top:14px;border-radius:2px;
  font-weight:700!important;padding:14px 18px!important}
html.menu-open #nav{box-shadow:0 8px 18px -8px rgb(var(--shade)/.30)}
@media(min-width:940px){
  .nav-inner{flex-wrap:nowrap;gap:24px}
  .navtel{display:inline-flex;align-items:center;min-height:44px;margin-left:auto;
    font-size:15px;font-weight:600;color:var(--ink-2);text-decoration:none}
  .navtel:hover{color:var(--accent)}
  .nav-links{flex:0 0 auto;width:auto;padding:0;margin:0;border:0}
  .nav-links a{width:auto;padding:0;border-bottom:0;font-size:14.5px;min-height:44px;
    display:inline-flex;align-items:center}
  /* two classes, not one: `.nav-links a` is (0,1,1) and would beat a bare
     `.drawtel` (0,1,0), which is how a drawer's phone number ends up printed in
     a desktop menu. */
  .nav-links .drawlab,.nav-links .drawhours,.nav-links .drawtel{display:none}
  .navcta{margin-top:0;padding:0 18px!important;height:40px;font-size:13px!important}
}

/* ============================================================================
   HERO — THE MOSAIC
   Three plates dropped at three angles and three heights, and one sheet of
   paper with the statement on it laid over them. The type is legible because
   it is on paper, not because the picture was darkened: there is no scrim,
   no gradient and no overlay in this composition.
   THE HERO IS EXEMPT from the orientation rule and carries no .reveal.
   ========================================================================== */
.hero{padding:calc(var(--nav-h) + var(--tpl-h,0px) + 6px) 0 58px}
.herolay{position:relative}

/* full-bleed on the phone so the plates run past the card on both sides.
   The phone band is 100/61 and not 100/57 or 100/64 for one measured reason: at
   100/64 the h1 computed to 301.6px at 390 in the demo state, 1.6px over
   DESIGN-FLOOR A3. The aspect here is a FOLD control on the phone, not a crop —
   the plates inside it are absolutely positioned and keep their own shapes. */
.heromos{position:relative;z-index:1;aspect-ratio:100/61;
  margin:0 calc(var(--gutter) * -1)}
@media(min-width:560px){.heromos{aspect-ratio:100/50}}
@media(min-width:760px){.heromos{aspect-ratio:100/42}}

.heroplate{position:absolute;margin:0;padding:7px;background:var(--surface-2);
  border-radius:var(--radius)}
.heroplate img{display:block;width:100%;height:100%;object-fit:cover;border-radius:1px}
/* no two objects at the same angle, and the lift ladder is the drop order:
   A went down first and lies flattest, C went down last and sits highest. */
.heroplate.hpa{left:0;top:0;width:42%;aspect-ratio:3/4;--tilt:-3.4deg;--lift:14;z-index:1}
.heroplate.hpc{left:34%;top:8%;width:34%;aspect-ratio:4/5;--tilt:2.2deg;--lift:30;z-index:3}
.heroplate.hpb{right:0;bottom:0;width:62%;aspect-ratio:3/2;--tilt:-1.9deg;--lift:22;z-index:2}

/* the card is laid UP into the mosaic. The overlap is a percentage of the
   container's own width so it tracks the mosaic's height at every width instead
   of being a pixel number that only works at one. */
.herosay{position:relative;z-index:5;margin-top:-38%;background:var(--sheet);
  padding:20px 20px 24px;border-radius:var(--radius);--tilt:-1.1deg;--lift:34}
.herokick{margin:0 0 7px;font-size:11px;font-weight:700;letter-spacing:.19em;
  text-transform:uppercase;color:var(--accent)}
/* THE DRAWN MOMENT — THE LAY, applied to a word. h1b is its own small sheet of
   paper, one step lighter than the card, at its own angle and its own lift, so
   the emphasised phrase is physically raised off the headline and casts onto
   it. inline-block, so a long phrase wraps INSIDE one sheet and never becomes
   two objects. No stroke, no underline, no highlight, anywhere in this file. */
.h1b{--tilt:-1.7deg;--lift:15;display:inline-block;max-width:100%;
  background:var(--surface-2);font-style:normal;border-radius:2px;
  padding:.02em .22em .08em;margin:.06em 0}
.herosub{margin:14px 0 0;font-size:16.5px;line-height:1.55;color:var(--ink-2)}
@media(min-width:760px){.herosub{font-size:19px;line-height:1.58}}
.herosay .btnrow{margin-top:20px}
.herofoot{display:flex;flex-wrap:wrap;gap:4px 16px;margin:18px 0 0;padding-top:14px;
  border-top:var(--hair);font-size:13px;color:var(--ink-3)}
.herofoot b{color:var(--ink-2);font-weight:700}

@media(min-width:980px){
  .hero{padding:calc(var(--nav-h) + var(--tpl-h,0px) + 22px) 0 74px}
  .herolay{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:start}
  .heromos{grid-area:1/1/2/3;margin:0;aspect-ratio:auto;height:clamp(430px,56vh,540px)}
  .herosay{grid-area:1/1/2/2;width:106%;margin:34px 0 0;padding:32px 32px 34px;--tilt:-.8deg;--lift:38}
  .heroplate.hpa{left:36%;top:0;width:26%;--tilt:-2.6deg;--lift:16}
  .heroplate.hpc{right:0;top:11%;left:auto;width:31%;--tilt:1.7deg;--lift:34}
  .heroplate.hpb{left:22%;right:auto;bottom:3%;width:44%;--tilt:-1.4deg;--lift:24}
}

/* ============================================================================
   THE BOARD — paper slips, two columns, no imagery.
   The angles alternate down AND across so no two neighbours are parallel.
   ========================================================================== */
.shead{max-width:62ch}
.slips{display:grid;gap:20px;margin:28px 0 0;padding:0}
@media(min-width:820px){.slips{grid-template-columns:1fr 1fr;gap:26px 30px;margin-top:38px}}
.slip{background:var(--sheet);border-radius:var(--radius);padding:19px 19px 21px;
  display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 16px;align-items:start}
.slip:nth-child(4n+1){--tilt:-2.4deg;--lift:9}
.slip:nth-child(4n+2){--tilt:1.9deg;--lift:16}
.slip:nth-child(4n+3){--tilt:-1.3deg;--lift:22}
.slip:nth-child(4n+4){--tilt:2.8deg;--lift:12}
.sname{grid-column:1;grid-row:1;margin:0;font-size:19px}
.sprice{grid-column:2;grid-row:1/3;align-self:start;font-family:var(--font-display);
  font-weight:700;font-size:29px;line-height:1;letter-spacing:-.02em;color:var(--accent);
  font-variant-numeric:tabular-nums}
.sblurb{grid-column:1;grid-row:2;margin:5px 0 0;font-size:15.5px;line-height:1.5;color:var(--ink-2)}
/* the second axis: a chip STAMPED into the slip rather than laid on it */
.stag{grid-column:1/-1;grid-row:3;justify-self:start;margin-top:13px;
  background:var(--surface);border-radius:2px;box-shadow:var(--press);
  padding:5px 10px 6px;font-size:10.5px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}
/* THE EMPTY STATE — a slot CUT INTO the paper where the figure goes. The same
   recess the missing week uses, and the only thing on the page that is cut into
   a surface rather than laid on one. Nothing is greyed out or apologised for. */
.sslot{display:block;width:82px;height:33px;border-radius:2px;
  background:var(--surface);box-shadow:var(--press)}
.hook{grid-column:1/-1;--tilt:1.2deg;--lift:20;background:var(--surface-2);
  border-radius:var(--radius);padding:20px 20px 22px}
.hook ~ .hook{display:none}
.hooklab{margin:0 0 8px;font-size:11px;font-weight:700;letter-spacing:.19em;
  text-transform:uppercase;color:var(--accent)}
.hooktxt{margin:0;font-size:15.5px;line-height:1.55;color:var(--ink-2);max-width:56ch}
.mgroup{margin-top:30px}
.mgh{margin:0 0 12px;font-size:12px;font-weight:700;letter-spacing:.19em;
  text-transform:uppercase;color:var(--ink-3)}
.mrows{--tilt:-.7deg;--lift:14;background:var(--sheet);border-radius:var(--radius);
  padding:6px 18px 8px}
.mrow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 16px;
  padding:12px 0;border-bottom:var(--hair)}
.mrow:last-child{border-bottom:0}
.mn{font-weight:600}
.mnote{grid-column:1;font-size:14px;color:var(--ink-3)}
.mp{grid-column:2;grid-row:1/3;font-family:var(--font-display);font-weight:700;
  color:var(--accent);font-variant-numeric:tabular-nums}
.bfoot{margin:26px 0 0;font-size:14.5px;color:var(--ink-3);max-width:60ch}

/* ============================================================================
   THE FLOOR — darkroom prints, a COLUMN FLOW, never a grid.
   No aspect-ratio, no object-fit and no height on any frame here: the print is
   exactly as tall as the picture in it, and because there are no rows there is
   no row to break when the client's photographs change shape.
   ========================================================================== */
.prints{margin:30px 0 0}
@media(min-width:720px){.prints{columns:2;column-gap:30px}}
@media(min-width:1120px){.prints{columns:3;column-gap:34px}}
.print{break-inside:avoid;-webkit-column-break-inside:avoid;margin:0 0 34px;
  background:var(--sheet);border-radius:var(--radius);padding:9px 9px 0}
.print:nth-child(4n+1){--tilt:-2.2deg;--lift:12}
.print:nth-child(4n+2){--tilt:1.6deg;--lift:20}
.print:nth-child(4n+3){--tilt:-1.2deg;--lift:26}
.print:nth-child(4n+4){--tilt:2.6deg;--lift:15}
.print img{width:100%;border-radius:1px}
.print figcaption{display:flex;flex-wrap:wrap;justify-content:space-between;
  gap:2px 14px;padding:11px 3px 13px;font-size:12px;letter-spacing:.05em}
.print figcaption b{font-weight:700;color:var(--ink)}
.print figcaption span{color:var(--ink-3);font-variant-numeric:tabular-nums}
.notes{display:grid;gap:16px;margin:6px 0 0}
@media(min-width:820px){.notes{grid-template-columns:repeat(3,1fr);gap:22px;margin-top:14px}}
.note{background:var(--sheet);border-radius:var(--radius);padding:20px 19px 22px}
.note:nth-child(3n+1){--tilt:1.7deg;--lift:11}
.note:nth-child(3n+2){--tilt:-2.3deg;--lift:18}
.note:nth-child(3n+3){--tilt:1.1deg;--lift:25}
.nnum{display:block;font-family:var(--font-display);font-size:13px;font-weight:700;
  color:var(--accent);margin-bottom:8px;font-variant-numeric:tabular-nums}
.note h3{margin:0 0 6px}
.note p{margin:0;font-size:15px;line-height:1.5;color:var(--ink-2)}

/* ============================================================================
   THE MAT — one large slate object laid on the table, inset from both edges so
   its own cast is visible the whole way round. A big heavy thing lies flatter
   than a receipt, which is why the tilt ladder scales the other way from lift.
   The three bricks are a fraction lighter than the mat and separated from it by
   NOTHING except their own shadows. This is where the delete test bites.
   ========================================================================== */
.matsec{padding-top:12px}
@media(min-width:760px){.matsec{padding-top:28px}}
.mat{--tilt:-.5deg;--lift:36;background:var(--band);color:var(--band-ink);
  border-radius:5px;padding:34px 20px 38px}
@media(min-width:820px){.mat{padding:58px 50px 62px}}
.mat h2,.mat h3{color:var(--band-ink)}
.mhead{max-width:62ch}
.bricks{display:grid;gap:14px;margin:28px 0 0}
@media(min-width:820px){.bricks{grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin-top:38px}}
.brick{background:var(--brick);border-radius:3px;padding:21px 19px 23px;
  box-shadow:var(--catch)}
.brick:nth-child(3n+1){--tilt:-1.4deg;--lift:14}
.brick:nth-child(3n+2){--tilt:1.1deg;--lift:22}
.brick:nth-child(3n+3){--tilt:-.8deg;--lift:17}
.bnum{display:block;font-family:var(--font-display);font-size:13px;font-weight:700;
  color:var(--accent-on-band);margin-bottom:9px;font-variant-numeric:tabular-nums}
.brick h3{margin:0 0 6px}
.brick p{margin:0;font-size:15px;line-height:1.52;color:var(--band-ink-2)}
/* the one pale object on the only dark surface, and the highest lift on the page */
.qslip{--tilt:1.8deg;--lift:40;background:var(--surface-2);color:var(--ink);
  border-radius:3px;margin:26px 0 0;padding:24px 20px 22px}
@media(min-width:820px){.qslip{margin:34px 44px 0;padding:32px 34px 28px}}
.qslip blockquote{margin:0;font-family:var(--font-display);font-size:19px;
  line-height:1.4;letter-spacing:-.012em;color:var(--ink)}
@media(min-width:820px){.qslip blockquote{font-size:22px}}
.qslip figcaption{margin-top:14px;padding-top:12px;border-top:var(--hair);
  font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3)}

/* ============================================================================
   WHAT PEOPLE ASK — index cards, and the state is the height off the table.
   A shut card lies almost flat; an open one is PICKED UP, squares itself to
   zero and its cast softens and spreads, because that is what a shadow does
   when an object rises. The marker carries the state as well, so nothing here
   depends on the shadow alone.
   ========================================================================== */
.askgrid{display:grid;gap:24px}
@media(min-width:900px){.askgrid{grid-template-columns:minmax(0,.85fr) minmax(0,1.3fr);
  gap:46px;align-items:start}}
.askcall{margin:14px 0 0;font-size:15px;color:var(--ink-3)}
.askcall a{color:var(--accent);font-weight:600;text-decoration:none}
.askcall a:hover{color:var(--accent-2)}
.asklist{display:grid;gap:13px}
.ask{--tilt:-1.6deg;--lift:5;background:var(--sheet);border-radius:var(--radius);
  transition:box-shadow .3s cubic-bezier(.22,.61,.36,1),transform .3s cubic-bezier(.22,.61,.36,1)}
.ask:nth-child(even){--tilt:1.5deg}
.ask[open]{--lift:18;--tilt:0deg}
.ask summary{list-style:none;cursor:pointer;display:flex;align-items:flex-start;
  justify-content:space-between;gap:16px;padding:15px 17px;min-height:52px;
  font-weight:600;font-size:16.5px;line-height:1.35}
.ask summary::-webkit-details-marker{display:none}
.ask summary i{position:relative;flex:0 0 auto;width:22px;height:22px;margin-top:2px;
  border-radius:2px;background:var(--surface);box-shadow:var(--press)}
.ask summary i::before,.ask summary i::after{content:"";position:absolute;
  left:50%;top:50%;width:10px;height:2px;background:var(--accent);
  transform:translate(-50%,-50%)}
.ask summary i::after{transform:translate(-50%,-50%) rotate(90deg);
  transition:transform .26s cubic-bezier(.22,.61,.36,1)}
.ask[open] summary i::after{transform:translate(-50%,-50%) rotate(0deg)}
.ask p{margin:0;padding:0 17px 17px;font-size:15.5px;line-height:1.58;color:var(--ink-2)}

/* ============================================================================
   THE COUNTER — the last objects on the table. The form sheet is the largest
   one, and every field on it is a RECESS cut into the paper: the same slot the
   empty price uses, at input size, so the form is part of the object rather
   than a control panel dropped onto it.
   ========================================================================== */
.cgrid{display:grid;gap:22px;margin-top:30px}
@media(min-width:940px){.cgrid{grid-template-columns:minmax(0,.84fr) minmax(0,1.16fr);
  gap:34px;align-items:start;margin-top:40px}}
.cleft{display:grid;gap:18px;align-content:start}
.card{background:var(--sheet);border-radius:var(--radius);padding:21px 19px 23px}
.cardlab{margin:0 0 12px;font-size:11px;font-weight:700;letter-spacing:.19em;
  text-transform:uppercase;color:var(--ink-3)}
.whencard{--tilt:-1.9deg;--lift:11}
.contactcard{--tilt:1.5deg;--lift:19}
.areacard{--tilt:-1.1deg;--lift:26}
.wrow{display:flex;justify-content:space-between;gap:14px;padding:9px 0;
  border-bottom:var(--hair);font-size:15px}
.wrow:last-child{border-bottom:0}
.wd{font-family:var(--font-display);font-weight:600;color:var(--ink)}
.wt{color:var(--ink-2);font-variant-numeric:tabular-nums;text-align:right}
/* hours[] ABSENT — the line they did publish, set large, and the shape of the
   week that is missing cut into the card underneath it. One absence graphic,
   used for the two things a Facebook page never carries. */
.whenbig{margin:0;font-family:var(--font-display);font-size:20px;line-height:1.3;
  letter-spacing:-.014em;color:var(--ink)}
.whenslot{display:block;height:74px;margin:15px 0 13px;border-radius:2px;
  background:var(--surface);box-shadow:var(--press)}
.whenask{margin:0;font-size:14px;line-height:1.52;color:var(--ink-3)}
.cbig{display:block;font-family:var(--font-display);font-size:19px;font-weight:600;
  letter-spacing:-.014em;color:var(--ink);text-decoration:none;padding:5px 0;
  overflow-wrap:anywhere}
.cbig:hover{color:var(--accent)}
.contactcard address{margin-top:9px;font-style:normal;font-size:15px;color:var(--ink-2)}
.areabody{margin:0 0 12px;font-size:15px;line-height:1.5;color:var(--ink-2)}
.towns{display:flex;flex-wrap:wrap;gap:7px;margin:0}
.towns span{background:var(--surface);border-radius:2px;box-shadow:var(--press);
  padding:5px 9px 6px;font-size:10.5px;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-3)}
/* THE PANEL LIES FLAT ON A PHONE, AND THAT IS PHYSICS, NOT A CLIMBDOWN.
   Rotating a box sweeps its corners: the swept width is w*cos0 + h*sin0. Every other
   object here is short, so its sweep is a few pixels. The form panel is the tallest
   object on the page (~1,100px at 390) and 0.7deg on it swept the document out to
   480px against a 390 viewport -- the page genuinely scrolled sideways by 105px on a
   phone. MEASURED, not reasoned: setting --tilt:0 on this one selector took
   scrollWidth 480 -> 378. base.css's body{overflow-x:hidden} did NOT save it.
   A heavy thing laid on a table sits square; a receipt does not. So the tilt returns
   at 760px, where the column is wide enough and the panel short enough to carry it. */
.panel{--tilt:0deg;--lift:34;background:var(--surface-2);border-radius:var(--radius);
  padding:24px 19px 26px}
@media(min-width:760px){.panel{padding:34px 32px 36px;--tilt:.7deg}}
.panel .field label{color:var(--ink-3);letter-spacing:.14em}
.panel .field input,.panel .field select,.panel .field textarea{
  background:var(--surface);border:0;border-radius:2px;box-shadow:var(--press);color:var(--ink)}
.panel .field input:focus,.panel .field select:focus,.panel .field textarea:focus{
  box-shadow:var(--press),0 0 0 3px var(--accent-ring)}
.panel .btn-primary{width:100%;margin-top:4px}
.fineprint{margin:14px 0 0;font-size:13px;line-height:1.5;color:var(--ink-3)}
.thanks{background:var(--sheet);border:0;border-radius:var(--radius)}

/* -------------------------------------------------------------- buttons ---- */
.btn{border-radius:2px;letter-spacing:.01em}
.btn-primary:hover{background:var(--accent-2);border-color:var(--accent-2)}
.btn-ghost{border-color:var(--ink-3);color:var(--ink)}
.btn-ghost:hover{border-color:var(--ink);background:var(--surface-2)}

/* --------------------------------------------------------------- footer ---- */
footer{background:var(--surface);padding:52px 0 40px;border-top:var(--hair)}
.fgrid{display:grid;gap:26px}
@media(min-width:760px){.fgrid{grid-template-columns:1.3fr 1fr 1fr;gap:36px}}
.mark.big{--lift:14;--tilt:2.4deg;width:42px;height:42px;font-size:16px}
.fname{margin:14px 0 5px;font-family:var(--font-display);font-size:19px;font-weight:700;
  letter-spacing:-.02em}
.fabout{margin:0;font-size:14.5px;line-height:1.55;color:var(--ink-2);max-width:44ch}
.fcol{display:flex;flex-direction:column;gap:3px}
.fh{margin:0 0 8px;font-size:11px;font-weight:700;letter-spacing:.19em;
  text-transform:uppercase;color:var(--ink-3)}
.fcol a{color:var(--ink);font-size:15.5px;min-height:36px;display:inline-flex;align-items:center}
.fcol a:hover{color:var(--accent)}
.fcol address{font-style:normal;font-size:15px;color:var(--ink-2);line-height:1.5}
.fplain{font-size:15px;color:var(--ink-2);line-height:1.5}
.fnav{display:flex;flex-wrap:wrap;gap:4px 24px;margin-top:32px;padding-top:14px;
  border-top:var(--hair)}
.fnav a{display:inline-flex;align-items:center;min-height:44px;font-size:14.5px;
  color:var(--ink-2)}
.fnav a:hover{color:var(--accent)}
.fbase{display:flex;flex-wrap:wrap;justify-content:space-between;gap:6px 20px;
  margin-top:14px;padding-top:14px;border-top:var(--hair);font-size:13px;color:var(--ink-3)}
.credit a{color:var(--ink-2)}
.credit a:hover{color:var(--accent)}
@media(min-width:760px){.fcol a,.fnav a{min-height:30px}}

/* ------------------------------------------------------------------ 404 ---- */
.nf{padding-top:calc(var(--nav-h) + var(--tpl-h,0px) + 44px)}
@media(min-width:760px){.nf{padding-top:calc(var(--nav-h) + var(--tpl-h,0px) + 66px)}}
.nfgrid{display:grid;gap:30px}
@media(min-width:900px){.nfgrid{grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:44px;align-items:start}}
.nfcard{--tilt:-1deg;--lift:32;padding:28px 22px 30px}
@media(min-width:760px){.nfcard{padding:40px 38px 42px}}
.nfcard h1{font-size:clamp(31px,5.4vw,44px);line-height:1.06;margin:0 0 14px}
.nfcard .btnrow{margin-top:22px}
.nfline{display:flex;flex-wrap:wrap;gap:2px 18px;align-items:baseline;margin:20px 0 0;
  padding-top:16px;border-top:var(--hair);font-size:14px;color:var(--ink-3)}
.nfprint{--tilt:2.6deg;--lift:22;margin:0}

/* --------------------------------------------------------------- motion ----
   The lift transitions are state, not decoration, so they are switched off
   with everything else when a visitor asks for reduced motion. The ANGLES are
   not motion and stay: a card lying askew is the design, at any setting. */
@media(prefers-reduced-motion:reduce){
  .ask,#nav{transition:none}
  .ask summary i::after{transition:none}
}
