@charset "UTF-8";
/* ==========================================================================
   RUSH WEBWORKS  |  site.css  |  reusable design system, v2

   Static CSS only. No build step, no preprocessor, no framework, no CDN.
   Fonts load via <link> in the head partial, never with @import here.

   HOW TO USE THIS FILE ON A NEW CLIENT
     1. Edit section 00 (BRAND). That is the whole reskin.
     2. Swap the logo SVG in the header and footer partials.
     3. Do not touch anything below section 00 to change how the site LOOKS.
        Sections 01 to 23 are the bones. They read section 00 and nothing else.

   TABLE OF CONTENTS
     00  BRAND            <- the only block you edit per client
     01  System tokens    (scale, motion, containers, derived from 00)
     02  Surface contexts (how a block knows what is legible on it)
     03  Reset
     04  Base typography
     05  Utilities
     06  Layout: wrap / section / grid
     07  Devices: slash-rule / eyebrow / chip / stat / credential strip
     08  Buttons
     09  Skip link
     10  Header, brand, nav, mobile drawer
     11  Hero
     12  Cards, services, split
     13  Quote band, CTA band
     14  Work grid, portfolio filter
     15  Gallery, lightbox
     16  Pillars, benefits, positions
     17  Forms
     18  Contact, breadcrumb, prose, error page
     19  Sticky mobile call bar
     20  Footer
     21  Reveal animation
     22  prefers-reduced-motion
     23  Print

   CONTRAST RULE, ENFORCED STRUCTURALLY
     A bright accent on white paper can be as low as 1.4:1. It is NEVER used
     for text on a light surface. Components that want an accent text colour
     use --accent-text, which resolves to --accent-on-light (the ink) on light
     surfaces and --accent-on-dark (the accent) on dark ones. Do not hard-code
     var(--accent) as a text colour anywhere below section 00.
   ========================================================================== */


/* ==========================================================================
   ==========================================================================
   00  BRAND
   ==========================================================================

   ###  EDIT ONLY THIS BLOCK TO RESKIN A SITE.  ###

   Everything under here is plumbing. If you find yourself editing a
   component to change a colour, a corner, an angle or a divider, stop:
   the token you want is in this block. Add one if it genuinely is not.

   ==========================================================================
   ========================================================================== */

:root {

  /* ------------------------------------------------------------------
     PNW HOME & YARD CARE  |  the brand block
     Evergreen ink, rain-mist paper, the gold from the logo as the one
     accent. Zero skew, soft 12px corners, pill buttons, a calm solid
     in-heading rule; the site's own devices (treeline edge, contour
     texture) live in section 24. Different face from the yellow,
     slanted, Archivo Black tree-company build on purpose.
     ------------------------------------------------------------------ */

  --accent:         #F7CB45;   /* the logo's gold, warmed a touch */
  --accent-bright:  #FFDA5E;
  --accent-deep:    #C99A12;

  --ink:            #0F1E17;   /* deep evergreen, reads black */
  --ink-2:          #16291F;
  --ink-3:          #233A2E;

  --paper:          #FDFDFB;
  --paper-2:        #EFF2EC;   /* rain-mist band */
  --paper-3:        #DDE2D9;
  --paper-4:        #C5CCC2;

  --text-dark:      #0F1E17;
  --text-mid:       #4F5C55;   /* 6.6:1 on --paper-2 */
  --text-light:     #FFFFFF;
  --text-light-mid: #B5C2B9;   /* 9.4:1 on --ink */

  --on-accent:      var(--ink);
  --on-accent-mid:  #3C2E05;   /* 7.9:1 on the gold */

  --danger:         #B3261E;
  --danger-soft:    #FDECEA;

  --ink-rgb:        15 30 23;
  --paper-rgb:      253 253 251;
  --accent-rgb:     247 203 69;

  --accent-on-light: var(--ink);
  --accent-on-dark:  var(--accent);

  --font-display: "Bricolage Grotesque", "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  --font-body:    "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;

  --display-weight:   800;
  --display-case:     none;
  --display-tracking: -.02em;

  --label-case:     uppercase;
  --label-tracking: .14em;

  --skew:      0deg;
  --unskew:    calc(var(--skew) * -1);
  --band-tilt: calc(var(--skew) * .14);

  --radius: 12px;

  --btn-radius:   var(--r-pill);
  --btn-height:   50px;
  --btn-pad-x:    1.6rem;
  --btn-font:     var(--font-display);
  --btn-case:     none;
  --btn-tracking: 0;

  --chip-radius: var(--r-pill);

  --rule-style:       var(--rule-solid);
  --rule-style-short: var(--rule-solid-short);
  --rule-texture:     var(--rule-solid-texture);
  --rule-sheen:       var(--rule-solid-sheen);

  --rule-height: 9px;

  --shadow-depth: .9;
  --section-rhythm: 1.05;
  --border-weight: 2px;

  --wrap:        1200px;
  --wrap-narrow: 760px;

  --print-origin: "https://pnwhomeandyardcare.com";

  --select-caret: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%230F1E17' stroke-width='2' stroke-linecap='square'/%3E%3C/svg%3E");
}

/* ==========================================================================
   ###  END OF THE BRAND BLOCK. NOTHING BELOW HERE IS PER-CLIENT.  ###
   ========================================================================== */


/* ==========================================================================
   01  SYSTEM TOKENS
   The scale, the motion, the containers, and everything derived from the
   personality tokens above. These are the bones. Changing them changes the
   system for every client, not one site.
   ========================================================================== */

:root {
  /* ---- Type scale ---- */
  --fs-body:   clamp(1rem, 0.955rem + 0.22vw, 1.0625rem);
  --fs-small:  0.875rem;
  --fs-micro:  0.78rem;
  --fs-lede:   clamp(1.05rem, 0.98rem + 0.5vw, 1.3rem);
  --fs-h1:     clamp(2rem, 1.35rem + 3.1vw, 3.5rem);
  --fs-hero:   clamp(2.1rem, 7.2vw, 5.1rem);
  --fs-h2:     clamp(1.7rem, 1.25rem + 2.1vw, 2.8rem);
  --fs-h3:     clamp(1.25rem, 1.1rem + 0.7vw, 1.6rem);
  --fs-h4:     clamp(1.05rem, 1rem + 0.3vw, 1.25rem);
  --fs-h5:     1rem;
  --fs-h6:     0.9rem;

  --lh-display: 1.02;
  --lh-head:    1.12;
  --lh-body:    1.62;

  /* ---- Spacing scale ---- */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 6rem;
  --sp-10: 8rem;

  /* Section padding, scaled by the rhythm personality token. */
  --section-y: calc(clamp(3rem, 7.5vw, 6rem) * var(--section-rhythm));

  /* ---- Radii, derived from --radius ----
     Capped with min() on purpose. A card, a form panel or a media box has
     real content in it: past about 22px the corner starts eating the top
     line of text, and at a pill value the card turns into a dome and clips
     its own title. So --radius drives the scale and the cap keeps any value,
     including a careless 999px, rendering as a finished site.
     Small controls that SHOULD be able to go fully round (buttons, chips)
     point at --r-pill directly through their own tokens in section 00. */
  --r-sm:   min(calc(var(--radius) * .5), 12px);
  --r-md:   min(var(--radius), 22px);
  --r-lg:   min(calc(var(--radius) * 2), 32px);
  --r-pill: 999px;

  /* ---- Accent bars, derived from --border-weight ----
     --accent-bar    card top rules, service card rules, underlines
     --accent-bar-lg form top rule, pillar left rule, footer top rule */
  --accent-bar:    calc(var(--border-weight) * 2);
  --accent-bar-lg: calc(var(--border-weight) * 3);

  /* ---- Shadows, derived from --shadow-depth ----
     At --shadow-depth: 0 the offset, the blur and the alpha all go to
     zero, so the shadows are genuinely gone rather than faintly present. */
  --sh-1: 0 calc(1px * var(--shadow-depth)) calc(2px * var(--shadow-depth)) rgb(var(--ink-rgb) / calc(.08 * var(--shadow-depth))),
          0 calc(2px * var(--shadow-depth)) calc(8px * var(--shadow-depth)) rgb(var(--ink-rgb) / calc(.05 * var(--shadow-depth)));
  --sh-2: 0 calc(6px * var(--shadow-depth)) calc(22px * var(--shadow-depth)) rgb(var(--ink-rgb) / calc(.13 * var(--shadow-depth)));
  --sh-3: 0 calc(16px * var(--shadow-depth)) calc(44px * var(--shadow-depth)) rgb(var(--ink-rgb) / calc(.20 * var(--shadow-depth)));
  --sh-dark: 0 calc(18px * var(--shadow-depth)) calc(48px * var(--shadow-depth)) rgb(0 0 0 / calc(.55 * var(--shadow-depth)));

  /* ---- Containers ----
     --wrap and --wrap-narrow are set in section 00, because the measure is a
     brand decision. Only the gutter is system. */
  --gutter: 20px;

  /* ---- Chrome heights ---- */
  --header-h: 64px;
  --call-bar-h: 58px;

  /* ---- Motion ---- */
  --t-fast: .16s ease;
  --t:      .24s ease;
  --t-slow: .42s cubic-bezier(.16, .84, .44, 1);
}

@media (min-width: 760px) {
  :root { --gutter: 24px; }
}

@media (min-width: 1000px) {
  :root { --header-h: 80px; }
}

@media (min-width: 1200px) {
  :root { --gutter: 32px; }
}


/* ==========================================================================
   02  SURFACE CONTEXTS
   Every block declares what is legible on it. Components read these, so a
   card, a stat or an eyebrow is automatically correct on paper, on ink and
   on an accent fill with no extra classes.

   --accent-text is the contrast guard in action. It is the ONLY way a
   component is allowed to ask for "the accent, as text".
   ========================================================================== */

:root,
.section,
.section-light,
.card,
.prose,
.form {
  --surface:        var(--paper);
  --raised:         var(--paper);
  --on-surface:     var(--text-dark);
  --on-surface-mid: var(--text-mid);
  --accent-text:    var(--accent-on-light);   /* legible accent on THIS surface */
  --hairline:       var(--paper-3);
  --ring:           var(--accent);
  --ring-halo:      var(--ink);
}

.section-light {
  --surface: var(--paper-2);
  --raised:  var(--paper);
}

.header,
.nav-drawer,
.hero,
.section-dark,
.quote-band,
.footer,
.lightbox {
  --surface:        var(--ink);
  --raised:         var(--ink-2);
  --on-surface:     var(--text-light);
  --on-surface-mid: var(--text-light-mid);
  --accent-text:    var(--accent-on-dark);
  --hairline:       var(--ink-3);
  --ring:           var(--accent);
  --ring-halo:      var(--ink);
}

.btn,
.nav-cta,
.cta-band,
.call-bar-primary,
.work-card-label,
.chip.is-solid,
.filter-btn[aria-pressed="true"] {
  --surface:        var(--accent);
  --raised:         var(--accent);
  --on-surface:     var(--on-accent);
  --on-surface-mid: var(--on-accent-mid);
  --accent-text:    var(--on-accent);
  --hairline:       var(--accent-deep);
  --ring:           var(--ink);        /* an accent ring is invisible on accent */
  --ring-halo:      var(--paper);
}


/* ==========================================================================
   03  RESET
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Safety net for the "zero horizontal scroll" promise. `clip` (not `hidden`)
     so it does not create a scroll container and break position:sticky.
     Nothing should actually need it: no component overflows at 320px. */
  overflow-x: clip;
}

/* Scroll lock. It has to sit on the root: html already owns the viewport's
   overflow here, so overflow:hidden on <body> alone would not hold it.
   site.js measures the scrollbar and sets --sbw so hiding it does not shift
   the layout sideways. (No scrollbar-gutter here on purpose: reserving a
   permanent gutter inflates documentElement.scrollWidth and would make an
   honest "zero horizontal overflow" audit read as a 15px overflow.) */
html.is-locked {
  overflow: hidden;
  padding-right: var(--sbw, 0px);
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ul, ol, fieldset, legend {
  margin: 0;
  padding: 0;
}

ul[class], ol[class] { list-style: none; }

img, svg, video, canvas, picture {
  display: block;
  max-width: 100%;
}

img, video { height: auto; }

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button { background: none; border: 0; }

a { color: inherit; }

table { border-collapse: collapse; }

fieldset { border: 0; min-width: 0; }

[hidden] { display: none !important; }

:target { scroll-margin-top: calc(var(--header-h) + 1.25rem); }

::selection {
  background: var(--accent);
  color: var(--on-accent);
}


/* ==========================================================================
   04  BASE TYPOGRAPHY
   ========================================================================== */

body {
  min-height: 100%;
  background: var(--paper);
  color: var(--text-dark);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Room for the sticky mobile call bar so it never covers the footer. */
  padding-bottom: calc(var(--call-bar-h) + env(safe-area-inset-bottom, 0px));
}

@media (min-width: 721px) {
  body { padding-bottom: 0; }
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  text-transform: var(--display-case);
  letter-spacing: var(--display-tracking);
  line-height: var(--lh-head);
  color: var(--on-surface);
  overflow-wrap: break-word;
  text-wrap: balance;
}

h1 { font-size: var(--fs-h1); line-height: var(--lh-display); }
h2 { font-size: var(--fs-h2); line-height: 1.06; }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); }
/* h5 and h6 open up a little past the display tracking, because at these
   sizes the display face gets cramped. Written as an offset from the token so
   they still follow a skin that tightens or loosens the tracking. */
h5 { font-size: var(--fs-h5); letter-spacing: calc(var(--display-tracking) + .03em); }
h6 { font-size: var(--fs-h6); letter-spacing: calc(var(--display-tracking) + .07em); }

p, li, dd, dt, blockquote, figcaption, label, td, th {
  overflow-wrap: break-word;
}

p + p { margin-top: 1em; }

strong, b { font-weight: 700; }

a {
  text-decoration-thickness: 2px;
  text-underline-offset: .18em;
  transition: color var(--t-fast), background-color var(--t-fast), border-color var(--t-fast);
}

/* Focus. An accent ring plus a hard halo, so it is visible on paper AND on
   ink. Surfaces that are themselves accent-filled flip --ring to the ink
   in section 02, because an accent ring on an accent fill is invisible. */
:focus { outline: none; }

:is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--ring);
  outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--ring-halo);
  border-radius: var(--r-sm);
}

hr {
  border: 0;
  height: 1px;
  background: var(--hairline);
  margin-block: var(--sp-6);
}


/* ==========================================================================
   05  UTILITIES
   ========================================================================== */

/* The slant. Put .skew on a heading or lockup, .unskew on the inner text run
   so the glyphs stay upright inside a skewed shape. At --skew: 0deg both are
   identity transforms and cost nothing. */
.skew   { transform: skewX(var(--skew)); }
.unskew { display: inline-block; transform: skewX(var(--unskew)); }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.text-center { text-align: center; }

.lede {
  font-size: var(--fs-lede);
  line-height: 1.5;
  color: var(--on-surface-mid);
  max-width: 62ch;
}

.muted { color: var(--on-surface-mid); }

/* Aspect-ratio helpers for .card-media, .split-media and .gallery-item */
.ratio-16x9 { --media-ratio: 16 / 9; }
.ratio-3x2  { --media-ratio: 3 / 2; }
.ratio-4x3  { --media-ratio: 4 / 3; }
.ratio-1x1  { --media-ratio: 1 / 1; }
.ratio-3x4  { --media-ratio: 3 / 4; }


/* ==========================================================================
   06  LAYOUT
   ========================================================================== */

.wrap,
.wrap-narrow {
  width: 100%;
  margin-inline: auto;
  /* padding-inline, never margin, so the gutter can never collapse */
  padding-inline: var(--gutter);
}

.wrap        { max-width: var(--wrap); }
.wrap-narrow { max-width: var(--wrap-narrow); }

.section {
  position: relative;
  padding-block: var(--section-y);
  background: var(--surface);
  color: var(--on-surface);
}

.section-dark  { background: var(--ink); color: var(--text-light); }
.section-light { background: var(--paper-2); color: var(--text-dark); }

/* Body copy on a dark band is muted. Written through :where() ON PURPOSE, so
   the whole selector has ZERO specificity and any component that paints its
   own colour wins without needing a patch.
   The trap this avoids: ".section-dark p" is (0,1,1) and beats a bare
   component class like ".eyebrow" or ".pillar-quote" at (0,1,0). A
   <p class="pillar-quote"> inside a dark band would silently compute to the
   muted grey and lose its accent. Do not unwrap these. */
:where(.section-dark, .footer) :where(p, li) { color: var(--on-surface-mid); }

.section-head {
  max-width: 64ch;
  margin-bottom: clamp(1.75rem, 4.5vw, 2.75rem);
}

.section-head > * + * { margin-top: var(--sp-3); }

.section-head.text-center {
  margin-inline: auto;
}

.section-head.text-center .eyebrow,
.section-head.text-center .slash-rule { margin-inline: auto; }

.section-head.text-center .lede { margin-inline: auto; }

/* --- Bare intro columns ---------------------------------------------------
   The reset zeroes every heading and list margin, and the shared components
   (.section-head, .split-body, .prose) are what normally put the rhythm back.
   A short intro column of bare children sitting directly inside .wrap-narrow
   has no such component, so a subhead and its chip row collapse flat against
   the paragraph above (measured gap: 0px). Restore the rhythm for that
   adjacency only. Scoped to DIRECT children, so headings inside .prose or
   .split-body are untouched.
--------------------------------------------------------------------------- */
.wrap-narrow > p + h2 { margin-top: clamp(2.25rem, 5vw, 3rem); }
.wrap-narrow > p + h3 { margin-top: clamp(2rem, 4.5vw, 2.75rem); }
.wrap-narrow > h2 + .chip-row,
.wrap-narrow > h3 + .chip-row { margin-top: var(--sp-4); }

/* --- Grid utilities. One column on phones, widening at the breakpoints. --- */
.grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
}

.grid-tight { gap: var(--sp-3); }
.grid-wide  { gap: clamp(1.5rem, 4vw, 3rem); }

@media (min-width: 560px) {
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 760px) {
  .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}


/* ==========================================================================
   07  DEVICES
   ========================================================================== */

/* --- THE DIVIDER RECIPES ---------------------------------------------------
   Three hand-authored treatments for .slash-rule. Pure CSS, no images.
   DO NOT EDIT THESE. Choose one in section 00, group D, or with a
   data-rule attribute / a .rule-* modifier class (both below).

   Each recipe is four values:
     -long      the clip-path for a full-width rule
     -short     the clip-path for the 168px in-heading accent mark
     -texture   an extra background layer painted over the accent fill
     -sheen     the ::after overlay that keeps it from reading as a flat slab
--------------------------------------------------------------------------- */
:root {

  /* BRUSH. A dry-brush sweep. Tapered at both ends, ragged along both
     edges, and pinched almost shut twice near the trailing end where the
     brush ran out of paint. The striations run along the sweep. */
  --rule-brush: polygon(
     0% 44%,   2% 26%,   7% 11%,  13% 21%,  21%  6%,  31% 16%,  40%  4%,
    50% 14%,  57%  6%,  61% 18%,  63% 44%,  66% 17%,  72%  7%,  79% 19%,
    84%  9%,  87% 41%,  90% 19%,  95% 10%, 100% 40%,
   100% 60%,  95% 90%,  90% 81%,  87% 59%,  84% 91%,  79% 81%,  72% 93%,
    66% 83%,  63% 56%,  61% 82%,  57% 94%,  50% 86%,  40% 96%,  31% 84%,
    21% 94%,  13% 79%,   7% 89%,   2% 74%,   0% 56%
  );
  /* The two dry pinches read as breaks at 168px, so the short mark gets a
     simpler single-stroke sweep with no pinch. */
  --rule-brush-short: polygon(
     0% 40%,   4% 19%,  12%  7%,  22% 20%,  34%  5%,  46% 18%,  58%  4%,
    70% 19%,  82%  7%,  92% 18%, 100% 36%,
   100% 64%,  92% 89%,  82% 78%,  70% 93%,  58% 80%,  46% 95%,  34% 79%,
    22% 92%,  12% 77%,   4% 89%,   0% 60%
  );
  --rule-brush-texture: repeating-linear-gradient(
    2deg,
    rgb(var(--ink-rgb) / 0)   0,
    rgb(var(--ink-rgb) / 0)   4.3px,
    rgb(var(--ink-rgb) / .34) 4.3px,
    rgb(var(--ink-rgb) / .34) 5px,
    rgb(var(--ink-rgb) / 0)   5px,
    rgb(var(--ink-rgb) / 0)   9.6px
  );
  /* The white in the sheens below is a specular highlight on a coloured
     object, not a surface colour, so it stays neutral rather than following
     --paper. It is the one white in this file that is meant to be white. The
     shade at the bottom of the brush sheen DOES follow the ink. */
  --rule-brush-sheen: linear-gradient(
    to bottom,
    rgb(255 255 255 / .32) 0%,
    rgb(255 255 255 / 0)   46%,
    rgb(var(--ink-rgb) / .16) 100%
  );

  /* SOLID. A clean tapered bar. Full height through the middle, narrowing
     to a third of its height at both ends. No texture, one soft highlight.
     Reads engineered. */
  --rule-solid: polygon(
      0% 34%,   6% 0%,  94% 0%, 100% 34%,
    100% 66%,  94% 100%, 6% 100%,   0% 66%
  );
  --rule-solid-short: polygon(
      0% 30%,  10% 0%,  90% 0%, 100% 30%,
    100% 70%,  90% 100%, 10% 100%,  0% 70%
  );
  --rule-solid-texture: none;
  --rule-solid-sheen: linear-gradient(
    to bottom,
    rgb(255 255 255 / .24) 0%,
    rgb(255 255 255 / 0)   62%
  );

  /* NOTCH. A stepped, crenellated bar: square teeth along the top, offset
     square teeth along the bottom. Flat colour, no sheen, no texture.
     Reads architectural and modular. */
  --rule-notch: polygon(
      0%   0%,  14%   0%,  14%  34%,  28%  34%,  28%   0%,  42%   0%,
     42%  34%,  56%  34%,  56%   0%,  70%   0%,  70%  34%,  84%  34%,
     84%   0%, 100%   0%,
    100% 100%,  86% 100%,  86%  66%,  72%  66%,  72% 100%,  58% 100%,
     58%  66%,  44%  66%,  44% 100%,  30% 100%,  30%  66%,  16%  66%,
     16% 100%,   0% 100%
  );
  --rule-notch-short: polygon(
      0%   0%,  26%   0%,  26%  38%,  52%  38%,  52%   0%,  78%   0%,
     78%  38%, 100%  38%,
    100% 100%,  74% 100%,  74%  62%,  48%  62%,  48% 100%,  22% 100%,
     22%  62%,   0%  62%
  );
  --rule-notch-texture: none;
  --rule-notch-sheen: none;
}

/* Per-page override. One attribute on <html> reskins every divider on the
   page without touching a single element's markup. */
[data-rule="brush"] {
  --rule-style:       var(--rule-brush);
  --rule-style-short: var(--rule-brush-short);
  --rule-texture:     var(--rule-brush-texture);
  --rule-sheen:       var(--rule-brush-sheen);
}

[data-rule="solid"] {
  --rule-style:       var(--rule-solid);
  --rule-style-short: var(--rule-solid-short);
  --rule-texture:     var(--rule-solid-texture);
  --rule-sheen:       var(--rule-solid-sheen);
}

[data-rule="notch"] {
  --rule-style:       var(--rule-notch);
  --rule-style-short: var(--rule-notch-short);
  --rule-texture:     var(--rule-notch-texture);
  --rule-sheen:       var(--rule-notch-sheen);
}

/* Per-element override, for the one divider on a page that should differ. */
.slash-rule.rule-brush {
  --rule-style:       var(--rule-brush);
  --rule-style-short: var(--rule-brush-short);
  --rule-texture:     var(--rule-brush-texture);
  --rule-sheen:       var(--rule-brush-sheen);
}

.slash-rule.rule-solid {
  --rule-style:       var(--rule-solid);
  --rule-style-short: var(--rule-solid-short);
  --rule-texture:     var(--rule-solid-texture);
  --rule-sheen:       var(--rule-solid-sheen);
}

.slash-rule.rule-notch {
  --rule-style:       var(--rule-notch);
  --rule-style-short: var(--rule-notch-short);
  --rule-texture:     var(--rule-notch-texture);
  --rule-sheen:       var(--rule-notch-sheen);
}


/* --- .slash-rule -----------------------------------------------------------
   The section divider. An accent band, slanted so its ends cut on a diagonal,
   shaped by whichever recipe is live. Not an <hr> semantically, though it can
   be written on one.
     <span class="slash-rule" aria-hidden="true"></span>
   Inside a .section-head, .hero-inner, .split-body or .card-body it renders
   short automatically (a 168px accent mark). Force either length with
   .is-short or .is-long. At --skew: 0deg it is a level rule, which is the
   correct look for a squared-up skin.
--------------------------------------------------------------------------- */
.slash-rule {
  display: block;
  position: relative;
  width: 100%;
  height: var(--rule-height);
  border: 0;
  margin: 0;
  transform: skewX(var(--skew));
  background: var(--rule-texture), var(--accent);
  clip-path: var(--rule-style);
}

/* A little modelling so the band is not a flat slab of colour. Recipes that
   want a flat band set --rule-sheen to none and this paints nothing. */
.slash-rule::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--rule-sheen);
}

/* Short accent mark. */
.section-head .slash-rule,
.hero-inner .slash-rule,
.split-body .slash-rule,
.card-body .slash-rule,
.slash-rule.is-short {
  width: 168px;
  max-width: 62%;
  clip-path: var(--rule-style-short);
}

/* Force full width back on, inside a context that would shorten it. */
.slash-rule.is-long {
  width: 100%;
  max-width: none;
  clip-path: var(--rule-style);
}

.slash-rule + * { margin-top: var(--sp-4); }

/* Clearance under a heading.
   .slash-rule resets its own margin so it can be dropped anywhere, including
   onto an <hr>. That reset is (0,1,0) and sits later in the file than the
   ".section-head > * + *" rhythm, so it silently wins and the mark ends up
   butting against the line box above it. With an uppercase display face that
   reads as a tight underline and nobody notices. The moment a skin sets
   --display-case: none the headings grow descenders, the headings run a very
   tight line-height (1.02 to 1.12) so the tail falls at the bottom of the
   box, and the tail of a "p" or a "g" lands on the mark. Two of the six
   pairings in section 00 and three of the six recipes in BRAND.md ask for
   sentence case, so this is the common path, not the exotic one.
   The gap is in em of the HEADING, so it scales with the heading rather than
   with body copy: bigger under a hero h1, smaller under a card h3. */
:is(h1, h2, h3, h4):has(+ .slash-rule) { padding-bottom: .2em; }

/* A heavier sweep used to cap a section. */
.slash-rule.is-band { height: calc(var(--rule-height) * 1.45); }


/* --- .eyebrow --------------------------------------------------------------
   Small label above a heading with an accent sweep mark. On dark surfaces the
   text itself is the accent. On light surfaces the text is ink and only the
   mark is accent, because a bright accent on paper is unreadable.
--------------------------------------------------------------------------- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  margin: 0 0 var(--sp-3);
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--label-tracking);
  line-height: 1.3;
  text-transform: var(--label-case);
  color: var(--accent-text);
}

.eyebrow::before {
  content: "";
  flex: none;
  width: 1.75rem;
  height: var(--accent-bar);
  background: var(--accent);
  transform: skewX(var(--skew));
}

/* An .eyebrow is usually a <p>. It keeps its accent inside a dark band only
   because the dark-band body rule in section 06 is written through :where()
   and therefore has zero specificity. If you ever unwrap that rule, this
   label goes muted grey on every dark section. */


/* --- .chip : a license or credential pill --------------------------------- */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-height: 34px;
  padding: .3rem .85rem;
  border: var(--border-weight) solid var(--hairline);
  border-radius: var(--chip-radius);
  background: transparent;
  color: var(--on-surface);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .55);
  text-transform: var(--label-case);
  white-space: nowrap;
  transform: skewX(var(--skew));
}

.chip > * { display: inline-block; transform: skewX(var(--unskew)); }

.section-dark .chip,
.hero .chip,
.footer .chip { border-color: var(--accent); }

.chip.is-solid {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

/* A .chip used as a LINK (a "services shown in this project" row) needs a real
   44px tap target and must not read as an underlined body-copy link. The pill
   keeps its type size, the control grows to clear the tap-target rule. Plain
   <span class="chip"> credential pills are untouched. The accent is a FILL
   here, never a text colour on a light surface. */
a.chip {
  min-height: 44px;
  color: var(--on-surface);
  text-decoration: none;
  transition: background-color var(--t-fast), border-color var(--t-fast),
              color var(--t-fast);
}

a.chip:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

a.chip:active {
  background: var(--accent-deep);
  border-color: var(--accent-deep);
  color: var(--paper);
}

.section-dark a.chip:hover,
.hero a.chip:hover,
.footer a.chip:hover { border-color: var(--accent); }


/* --- .stat : big accent number over a small caption ----------------------- */
.stat-row {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
}

@media (min-width: 560px) {
  .stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .stat-row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.stat {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  min-width: 0;
  padding-left: var(--sp-4);
  border-left: var(--accent-bar) solid var(--accent);
}

.stat-num {
  min-width: 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.55rem, 1.1rem + 2.2vw, 3rem);
  line-height: 1.02;
  letter-spacing: var(--display-tracking);
  text-transform: var(--display-case);
  color: var(--accent-text);
  transform: skewX(var(--skew));
  transform-origin: left bottom;
  /* A licence number is a long unbreakable token. Let it break rather than
     blow the grid track out and put horizontal scroll on the whole page. */
  overflow-wrap: anywhere;
}

.stat-label {
  min-width: 0;
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: calc(var(--label-tracking) * .35);
  text-transform: var(--label-case);
  color: var(--on-surface-mid);
  overflow-wrap: break-word;
}


/* --- .credential-strip -----------------------------------------------------
   The thin band of trust chips that sits directly under the hero. It is a
   band, not a full .section, so the only thing it needs is a vertical rhythm
   of its own. Carry .section-dark on it for the surface context (which is
   what turns the chip borders accent).
     <div class="credential-strip section-dark"><div class="wrap">...
--------------------------------------------------------------------------- */
.credential-strip {
  padding-block: var(--sp-4);
  border-top: var(--accent-bar) solid var(--accent);
  border-bottom: 1px solid var(--hairline);
}

.credential-strip .chip-row { gap: var(--sp-2) var(--sp-4); }


/* --- .error-code : the oversized numeral on a 404 or 500 page --------------
   Reads the surface tokens, so the numeral is accent on ink and ink on paper,
   and would flip automatically on any other surface. inline-block so the skew
   only shifts the glyph box, never the full column width, which keeps the
   320px overflow audit clean.
--------------------------------------------------------------------------- */
.error-code {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(4.25rem, 20vw, 10rem);
  line-height: .92;
  letter-spacing: var(--display-tracking);
  color: var(--accent-text);
  transform: skewX(var(--skew));
}

.error-help { margin-top: var(--sp-5); }

.error-help a {
  color: var(--accent-text);
  font-weight: 600;
}


/* ==========================================================================
   08  BUTTONS
   The label sits in an inner <span> which is automatically un-skewed, so the
   type stays upright inside a slanted shape. At --skew: 0deg both transforms
   are the identity and the button is a plain rectangle.
   Markup: <a class="btn" href="/contact.html"><span>Request a Bid</span></a>
   ========================================================================== */

.btn,
.nav-cta,
.filter-btn,
.call-bar-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  max-width: 100%;
  min-height: var(--btn-height);
  padding: .7rem var(--btn-pad-x);
  border: var(--border-weight) solid var(--accent);
  border-radius: var(--btn-radius);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--btn-font);
  font-size: clamp(.86rem, .82rem + .16vw, .98rem);
  font-weight: var(--display-weight);
  letter-spacing: var(--btn-tracking);
  line-height: 1.1;
  text-transform: var(--btn-case);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transform: skewX(var(--skew));
  transition: background-color var(--t-fast), border-color var(--t-fast),
              color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}

/* Auto-unskew the label so authors never have to remember .unskew here. */
.btn > *,
.nav-cta > *,
.filter-btn > *,
.call-bar-link > * {
  display: inline-block;
  transform: skewX(var(--unskew));
}

.btn:hover,
.nav-cta:hover {
  background: var(--accent-bright);
  border-color: var(--accent-bright);
  color: var(--on-accent);
}

.btn:active,
.nav-cta:active,
.filter-btn:active,
.call-bar-link:active {
  transform: skewX(var(--skew)) translateY(2px);
  background: var(--accent-deep);
  border-color: var(--accent-deep);
  color: var(--paper);
  box-shadow: none;
}

/* Outlined variant. Inherits the surface it sits on. */
.btn-ghost {
  background: transparent;
  border-color: var(--on-surface);
  color: var(--on-surface);
  --ring: var(--accent);
  --ring-halo: var(--ink);
}

.section-dark .btn-ghost,
.hero .btn-ghost,
.footer .btn-ghost {
  border-color: var(--accent);
  color: var(--text-light);
}

.btn-ghost:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.btn-ghost:active {
  background: var(--accent-deep);
  border-color: var(--accent-deep);
  color: var(--paper);
}

/* Inside an accent band an accent button is invisible. Flip to ink. */
.cta-band .btn,
.call-bar-primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--accent-on-dark);
}

.cta-band .btn:hover {
  background: var(--ink-2);
  border-color: var(--ink-2);
  color: var(--accent-bright);
}

/* The outlined button inside the accent band. It paints from --on-accent, NOT
   from --ink. --on-accent is the one colour the palette guarantees is legible
   on an accent fill, so this stays readable whether the client's accent is a
   bright amber (--on-accent is the ink, which is what the default renders) or
   a dark navy, forest or burgundy (--on-accent flips to the paper). Hard
   coding var(--ink) here measured 3.1:1 on a mid-blue accent.
   The hover pair is the exact inverse of the normal pair, so it carries the
   identical contrast ratio by construction. */
.cta-band .btn-ghost {
  background: transparent;
  border-color: var(--on-accent);
  color: var(--on-accent);
}

.cta-band .btn-ghost:hover {
  background: var(--on-accent);
  border-color: var(--on-accent);
  color: var(--accent);
}

.btn-lg {
  min-height: calc(var(--btn-height) + 8px);
  padding: .9rem calc(var(--btn-pad-x) + .5rem);
  font-size: clamp(.95rem, .9rem + .25vw, 1.1rem);
}

.btn-block {
  display: flex;
  width: 100%;
}

/* Wrapper for two or more buttons. The extra gap keeps slanted edges apart. */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
  margin-top: var(--sp-5);
}

.btn-row.text-center { justify-content: center; }


/* ==========================================================================
   09  SKIP LINK
   ========================================================================== */

.skip-link {
  position: absolute;
  top: 0;
  left: var(--gutter);
  z-index: 300;
  transform: translateY(-140%);
  display: inline-flex;
  align-items: center;
  min-height: var(--btn-height);
  padding: .7rem 1.25rem;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .35);
  text-transform: var(--label-case);
  text-decoration: none;
  box-shadow: var(--sh-3);
  --ring: var(--ink);
  --ring-halo: var(--paper);
}

.skip-link:focus-visible {
  transform: translateY(0);
}


/* ==========================================================================
   10  HEADER / BRAND / NAV / DRAWER
   ========================================================================== */

.header {
  position: sticky;
  top: 0;
  z-index: 70;
  color: var(--text-light);
  border-bottom: 1px solid var(--ink-3);
  transition: box-shadow var(--t), border-color var(--t);
}

/* The translucent panel lives on a pseudo-element, NOT on .header itself.
   backdrop-filter makes an element the containing block for its
   position:fixed descendants, which would collapse .nav-drawer into the
   height of the header instead of the viewport. */
.header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgb(var(--ink-rgb) / .88);
  transition: background-color var(--t);
}

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .header::before {
    -webkit-backdrop-filter: blur(10px) saturate(130%);
    backdrop-filter: blur(10px) saturate(130%);
  }
}

.header.is-scrolled {
  border-bottom-color: var(--accent);
  box-shadow: var(--sh-dark);
}

.header.is-scrolled::before { background: var(--ink); }

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--header-h);
}

/* --- Brand lockup: logo mark + optional two-line wordmark ---
   Swap the inline SVG in the header and footer partials per client. The SVG
   should paint from --badge-ink and --badge-accent rather than hard-coded
   fills, so it follows the palette. --- */
/* flex: 0 1 auto plus min-width: 0 lets flexbox squeeze the brand's BOX when
   the nav is wide, but .wordmark is white-space: nowrap, so without the
   overflow below the text simply spills out of the squeezed box and paints on
   top of the first nav link. Measured on a 1280px laptop with a two word name
   and a three word kicker: 67px of spill, 51px of it sitting on the nav, and
   the page-level overflow audit stays clean the whole time because html has
   overflow-x: clip, so nothing warns you. Clip it here instead. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: .625rem;
  min-height: 48px;
  padding-block: .25rem;
  text-decoration: none;
  color: var(--text-light);
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
}

.badge-mark {
  flex: none;
  width: 40px;
  height: 40px;
  /* The inline SVG reads these. Override per surface if ever needed. */
  --badge-ink:    var(--ink);
  --badge-accent: var(--accent);
}

@media (min-width: 1000px) {
  .badge-mark { width: 46px; height: 46px; }
}

.wordmark {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(.92rem, .82rem + .5vw, 1.15rem);
  line-height: 1;
  text-transform: var(--display-case);
  color: var(--text-light);
  transform: skewX(var(--skew));
  transform-origin: left center;
  white-space: nowrap;
}

/* The header has a real capacity limit: a brand lockup, five nav links, a
   phone number and a CTA button on one row. If the lockup runs out of room it
   now truncates rather than overlapping the nav.
   AN ELLIPSIS IN THE HEADER MEANS THE HEADER IS OVER CAPACITY. Fix the cause,
   do not style around it: shorten the name in the lockup, shorten or delete
   the kicker line, drop a nav item, or shorten the CTA label. The tightest
   combinations are an uppercase display face with a large --label-tracking
   and a four word CTA. */
.wordmark-line {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The small kicker line above the name (a region, a trade, a tagline).
   Tracked wider than the name, but off --label-tracking rather than a fixed
   value: a skin that runs tight micro-labels must not leave this one line
   wearing the previous skin's spacing. */
.wordmark-line:first-child {
  font-size: .7em;
  letter-spacing: calc(var(--label-tracking) * 1.1);
  color: var(--text-light-mid);
}

.wordmark-line:last-child {
  font-size: 1em;
  letter-spacing: var(--display-tracking);
}

/* Any single glyph inside the wordmark that should carry the accent. */
.wordmark-accent { color: var(--accent-on-dark); }

/* --- Nav. The same <nav> element is the inline bar on desktop and the
       slide-in drawer on phones, so there is only one copy of the markup. --- */
.nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 1.6vw, 1.5rem);
}

.nav-list {
  display: flex;
  align-items: center;
  gap: clamp(.9rem, 1.4vw, 1.6rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  min-width: 44px;          /* short labels still clear the 44px target */
  padding: .25rem 0;
  border-bottom: 3px solid transparent;
  color: var(--text-light);
  font-size: clamp(.78rem, .74rem + .16vw, .86rem);
  font-weight: 600;
  letter-spacing: calc(var(--label-tracking) * .55);
  text-transform: var(--label-case);
  text-decoration: none;
  white-space: nowrap;
}

.nav-link:hover { color: var(--accent-on-dark); border-bottom-color: var(--accent-deep); }

.nav-link[aria-current="page"] {
  color: var(--accent-on-dark);
  border-bottom-color: var(--accent);
}

.nav-phone {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-height: 48px;
  padding: .25rem .25rem;
  color: var(--text-light);
  font-size: clamp(.85rem, .8rem + .2vw, .95rem);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .22);
  text-decoration: none;
  white-space: nowrap;
}

.nav-phone:hover { color: var(--accent-on-dark); }

.nav-phone svg { width: 16px; height: 16px; flex: none; fill: var(--accent); }

.nav-cta { padding: .6rem 1.15rem; min-height: 46px; }

/* --- Hamburger --- */
.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex: none;
  width: 48px;
  height: 48px;
  padding: 0;
  border: var(--border-weight) solid var(--ink-3);
  border-radius: var(--r-sm);
  background: var(--ink-2);
  color: var(--text-light);
  cursor: pointer;
}

.nav-toggle:hover { border-color: var(--accent); }

.nav-toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: currentColor;
  transition: transform var(--t), opacity var(--t-fast);
}

.nav-toggle[aria-expanded="true"] { border-color: var(--accent); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* --- Mobile drawer (below 1000px) ---
   The closed drawer is display:none, not a panel parked off the right edge.
   A parked panel is position:fixed and still counts toward
   documentElement.scrollWidth, which would put a phantom 340px of horizontal
   overflow on every page. It opens with a keyframe instead of a transition
   because you cannot transition out of display:none.                       */
@media (max-width: 999.98px) {
  .nav-drawer {
    display: none;
    position: fixed;
    top: var(--header-h);
    right: 0;
    bottom: 0;
    left: auto;
    z-index: 60;
    width: min(88vw, 340px);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--sp-5) var(--sp-5)
             calc(var(--sp-8) + var(--call-bar-h) + env(safe-area-inset-bottom, 0px));
    background: var(--ink-2);
    border-left: 1px solid var(--ink-3);
    box-shadow: var(--sh-dark);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .nav-drawer.is-open {
    display: flex;
    animation: rw-drawer-in .3s cubic-bezier(.16, .84, .44, 1) both;
  }

  @keyframes rw-drawer-in {
    from { transform: translateX(100%); opacity: .4; }
    to   { transform: none;             opacity: 1; }
  }

  .nav-drawer .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin-bottom: var(--sp-5);
  }

  .nav-drawer .nav-link {
    min-height: 54px;
    padding: .5rem 0;
    border-bottom: 1px solid var(--ink-3);
    font-size: .95rem;
  }

  .nav-drawer .nav-link[aria-current="page"] {
    border-bottom-color: var(--accent);
    padding-left: .6rem;
    box-shadow: inset var(--accent-bar) 0 0 var(--accent);
  }

  .nav-drawer .nav-phone {
    min-height: 54px;
    font-size: 1.15rem;
    margin-bottom: var(--sp-3);
  }

  .nav-drawer .nav-cta { width: 100%; }

  /* Backdrop. Deliberately neutral black rather than tinted ink, so it dims
     the page rather than colouring it. */
  body.is-nav-open::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 58;
    background: rgb(0 0 0 / .58);
  }
}

@media (min-width: 1000px) {
  .nav-toggle { display: none; }
  .nav-drawer { display: flex; animation: none; }
}


/* ==========================================================================
   11  HERO
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: flex-end;
  /* Pull up under the sticky header, then pad the content back down. */
  margin-top: calc(var(--header-h) * -1);
  padding-top: calc(var(--header-h) + var(--sp-7));
  padding-bottom: clamp(2.5rem, 7vw, 5rem);
  min-height: min(88vh, 780px);
  min-height: min(88svh, 780px);
  background: var(--ink);
  color: var(--text-light);
  overflow: hidden;
}

.hero-slides {
  position: absolute;
  inset: 0;
  z-index: -2;
  background: var(--ink);
}

.hero-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.6s ease;
  will-change: opacity;
}

.hero-slide.is-active { opacity: 1; }

.hero-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 42%;
  transform-origin: 54% 46%;
}

/* Ken Burns belongs to the CROSS-FADING slideshow only, where each slide is
   swapped out at the end of its 7.6s run. Scoped to [data-hero] so it can
   never apply to a single static interior hero, which would animate once and
   then sit permanently at scale(1.12), cropping 12% off the photo forever. */
[data-hero] .hero-slide.is-active img {
  animation: rw-kenburns 7600ms ease-out both;
}

@keyframes rw-kenburns {
  from { transform: scale(1)    translate3d(0, 0, 0); }
  to   { transform: scale(1.12) translate3d(-1.1%, -0.9%, 0); }
}

/* Interior pages have one still hero. Give it a short settle-in that ENDS at
   natural scale, so the photo rests uncropped.
   NOTE: data-hero sits on .hero-slides, not on the .hero section, so this is
   scoped to the same element. Writing it as .hero:not([data-hero]) would also
   match the homepage (whose section carries no attribute) and, being more
   specific, would silently steal the slideshow's Ken Burns. */
.hero-slides:not([data-hero]) .hero-slide.is-active img {
  animation: rw-hero-settle 1100ms cubic-bezier(.16, .84, .44, 1) both;
}

@keyframes rw-hero-settle {
  from { transform: scale(1.055); }
  to   { transform: scale(1); }
}

/* Two-part scrim: a corner-to-corner wash plus a hard bottom fade, so the
   headline stays readable over every photo including the brightest one.
   Neutral black on purpose: a tinted scrim would recolour the photography. */
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgb(0 0 0 / 0) 38%, rgb(0 0 0 / .85) 100%),
    linear-gradient(35deg, rgb(0 0 0 / .72) 0%, rgb(0 0 0 / .52) 46%, rgb(0 0 0 / .25) 100%);
}

.hero-inner {
  position: relative;
  width: 100%;
  max-width: 900px;
}

.hero-inner h1 {
  font-size: var(--fs-hero);
  line-height: .96;
  letter-spacing: var(--display-tracking);
  color: var(--text-light);
  overflow-wrap: break-word;
  text-wrap: balance;
  transform: skewX(var(--skew));
  transform-origin: left bottom;
  text-shadow: 0 3px 22px rgb(0 0 0 / .55);
  margin-bottom: var(--sp-4);
}

/* Slightly softened from pure white so it sits under the headline rather than
   competing with it, but much brighter than --text-light-mid, which is too
   grey to hold up over photography. */
.hero-inner .lede {
  color: rgb(var(--paper-rgb) / .92);
  max-width: 54ch;
  text-shadow: 0 2px 14px rgb(0 0 0 / .6);
}

.hero-inner .chip-row { margin-top: var(--sp-5); }

/* --- Compact interior hero -------------------------------------------------
   The same .hero component, with one still photo instead of a slideshow, so
   it does not need the full 88svh of the homepage. Scoped by the ABSENCE of
   the [data-hero] slideshow container rather than by a new class name, so it
   applies to any interior page that drops a single still into .hero and never
   touches the homepage. A browser without :has() simply keeps the tall hero,
   which still renders correctly.
--------------------------------------------------------------------------- */
.hero:not(:has([data-hero])) {
  min-height: 0;
  padding-bottom: clamp(2rem, 5.5vw, 3.25rem);
}

.hero:not(:has([data-hero])) .hero-inner h1 {
  font-size: var(--fs-h1);
}

.hero-dots {
  position: absolute;
  right: var(--gutter);
  bottom: calc(var(--gutter) * .75);
  z-index: 3;
  display: flex;
  gap: .35rem;
}

/* 44x44 hit area. The visible mark is the smaller ::before bar. */
.hero-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

/* The inactive marks are the paper colour at low alpha, not a fixed white, so
   an ivory or warm paper carries through here too. They sit over photography,
   which is why they are pale rather than a surface token. */
.hero-dot::before {
  content: "";
  width: 26px;
  height: 5px;
  background: rgb(var(--paper-rgb) / .42);
  transform: skewX(var(--skew));
  transition: background-color var(--t-fast), width var(--t-fast);
}

.hero-dot:hover::before { background: rgb(var(--paper-rgb) / .75); }

.hero-dot[aria-current="true"]::before,
.hero-dot.is-active::before {
  background: var(--accent);
  width: 34px;
}

@media (max-width: 559.98px) {
  .hero-dots { bottom: .25rem; right: .25rem; gap: 0; }
  /* Hit area stays 44x44. Only the visible bar shrinks. */
  .hero-dot::before { width: 17px; }
  .hero-dot[aria-current="true"]::before,
  .hero-dot.is-active::before { width: 24px; }
}


/* ==========================================================================
   12  CARDS / SERVICES / SPLIT
   ========================================================================== */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--raised);
  color: var(--on-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}

.section-dark .card,
.footer .card { background: var(--ink-2); border-color: var(--ink-3); }

.card-media {
  position: relative;
  display: block;
  aspect-ratio: var(--media-ratio, 4 / 3);
  background: var(--hairline);
  overflow: hidden;
}

.card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--t-slow);
}

.card-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  flex: 1 1 auto;
  padding: clamp(1.1rem, 3vw, 1.75rem);
}

/* Styles itself, so it works on a real <h3> inside a card AND on a <span>
   inside a whole-card <a> where a heading would be awkward. */
.card-title {
  display: block;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: var(--display-weight);
  line-height: var(--lh-head);
  letter-spacing: var(--display-tracking);
  text-transform: var(--display-case);
  color: var(--on-surface);
  overflow-wrap: break-word;
}

.card-text {
  color: var(--on-surface-mid);
  margin: 0;
}

.card-link {
  margin-top: auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 44px;
  min-width: 44px;
  padding-top: .35rem;
  color: var(--accent-text);
  font-weight: 700;
  font-size: var(--fs-small);
  letter-spacing: calc(var(--label-tracking) * .55);
  text-transform: var(--label-case);
  text-decoration: none;
  border-bottom: 3px solid var(--accent);
}

.card-link::after { content: "\2192"; transition: transform var(--t-fast); }
.card-link:hover::after { transform: translateX(4px); }

/* --- Service card: a card with an accent top rule --- */
.service-card { border-top: var(--accent-bar) solid var(--accent); }

.service-card:hover,
.work-card:hover,
a.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--sh-2);
  border-color: var(--accent-deep);
}

.service-card:hover .card-media img,
.work-card:hover .card-media img { transform: scale(1.05); }

/* --- Service list: ticked list of what is included --- */
.service-list {
  display: grid;
  gap: .65rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.service-list > li {
  position: relative;
  padding-left: 1.85rem;
  color: var(--on-surface-mid);
}

.service-list > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: 13px;
  height: 13px;
  border-radius: var(--r-sm);
  background: var(--accent);
  transform: skewX(var(--skew));
}

.service-list.is-two-col { grid-template-columns: 1fr; }

@media (min-width: 760px) {
  .service-list.is-two-col { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Split: image beside text, stacks on phones --- */
.split {
  display: grid;
  gap: clamp(1.5rem, 4.5vw, 3.25rem);
  grid-template-columns: 1fr;
  align-items: center;
}

@media (min-width: 900px) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split.reverse .split-media { order: 2; }
  .split.reverse .split-body  { order: 1; }
}

.split-media {
  position: relative;
  aspect-ratio: var(--media-ratio, 4 / 3);
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--hairline);
}

.split-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Accent corner flag on split imagery. The negative offset is clipped by the
   parent's overflow, so it reads as a flush tab at --skew: 0deg. Only the
   inner end takes the radius, for the same reason as .work-card-label. */
.split-media::after {
  content: "";
  position: absolute;
  left: -14px;
  bottom: 18px;
  width: 92px;
  height: 12px;
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--accent);
  transform: skewX(var(--skew));
}

.split-body { min-width: 0; }
.split-body > * + * { margin-top: var(--sp-4); }


/* ==========================================================================
   13  QUOTE BAND / CTA BAND
   ========================================================================== */

.quote-band {
  position: relative;
  padding-block: calc(clamp(3rem, 8vw, 5.5rem) * var(--section-rhythm));
  background: var(--ink);
  color: var(--text-light);
  overflow: hidden;
}

/* The accent cap. --band-tilt is derived from --skew, so at 0deg this is a
   level rule sitting 4px proud of the top edge, which is deliberate. */
.quote-band::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 10px;
  background: var(--accent);
  transform: skewY(var(--band-tilt)) translateY(-6px);
}

.quote-text {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.45rem, 1rem + 2.4vw, 2.6rem);
  line-height: 1.12;
  letter-spacing: var(--display-tracking);
  text-transform: var(--display-case);
  color: var(--text-light);
  transform: skewX(var(--skew));
  transform-origin: left center;
  margin: 0;
}

.quote-text em {
  font-style: normal;
  color: var(--accent-text);
}

.quote-cite {
  display: block;
  margin-top: var(--sp-4);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-style: normal;
  font-weight: 600;
  letter-spacing: calc(var(--label-tracking) * .65);
  text-transform: var(--label-case);
  color: var(--text-light-mid);
}

/* --- CTA band: the reusable accent "Request a bid" strip --- */
.cta-band {
  position: relative;
  padding-block: calc(clamp(2.5rem, 6.5vw, 4.25rem) * var(--section-rhythm));
  background: var(--accent);
  color: var(--on-accent);
  overflow: hidden;
}

.cta-band::before,
.cta-band::after {
  content: "";
  position: absolute;
  left: -5%;
  width: 110%;
  height: 14px;
  background: var(--ink);
  opacity: .9;
}

.cta-band::before { top: -7px;    transform: skewY(var(--band-tilt)); }
.cta-band::after  { bottom: -7px; transform: skewY(var(--band-tilt)); }

.cta-inner {
  display: grid;
  gap: var(--sp-5);
  align-items: center;
  grid-template-columns: 1fr;
}

@media (min-width: 900px) {
  .cta-inner { grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-7); }
}

.cta-title {
  font-size: clamp(1.6rem, 1.1rem + 2.4vw, 2.6rem);
  line-height: 1.04;
  color: var(--on-accent);
  transform: skewX(var(--skew));
  transform-origin: left bottom;
  margin: 0;
}

.cta-text {
  margin-top: var(--sp-3);
  color: var(--on-accent-mid);
  font-weight: 500;
  max-width: 56ch;
}

.cta-band .btn-row { margin-top: 0; }


/* ==========================================================================
   14  WORK GRID / FILTER
   ========================================================================== */

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem .7rem;
  margin-bottom: var(--sp-6);
}

.filter-btn {
  min-height: 46px;
  padding: .55rem 1.1rem;
  background: transparent;
  border-color: var(--hairline);
  color: var(--on-surface);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .45);
}

.filter-btn:hover {
  border-color: var(--accent-deep);
  background: transparent;
  color: var(--on-surface);
}

.filter-btn[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.filter-count {
  flex: 1 0 100%;
  margin: .25rem 0 0;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--on-surface-mid);
}

.work-grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
}

@media (min-width: 620px) {
  .work-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .work-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.work-card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--raised);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
  text-decoration: none;
  color: var(--on-surface);
  transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}

.work-card .card-media { --media-ratio: 3 / 2; }

/* The corner tag. Its left bleed is clipped by the card's overflow, so at
   --skew: 0deg it reads as a flush-left tab rather than a broken offset.
   Only the two INNER corners take the radius: the outer pair is cut off by
   the card anyway, and rounding one end is what makes it read as a tag. */
.work-card-label {
  position: absolute;
  left: -6px;
  top: 14px;
  z-index: 2;
  padding: .3rem 1rem .3rem 1.2rem;
  border-radius: 0 var(--chip-radius) var(--chip-radius) 0;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .55);
  text-transform: var(--label-case);
  transform: skewX(var(--skew));
}

.work-card-label > * { display: inline-block; transform: skewX(var(--unskew)); }


/* ==========================================================================
   15  GALLERY / LIGHTBOX
   ========================================================================== */

.gallery {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 560px) {
  .gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.gallery-item {
  margin: 0;
  min-width: 0;
}

.gallery-btn {
  display: block;
  width: 100%;
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--hairline);
  cursor: zoom-in;
  overflow: hidden;
  position: relative;
  aspect-ratio: var(--media-ratio, 4 / 3);
}

.gallery-btn img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--t-slow), opacity var(--t-fast);
}

.gallery-btn:hover img { transform: scale(1.05); opacity: .92; }

.gallery-btn::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  width: 44px;
  height: 10px;
  border-radius: var(--r-sm) 0 0 var(--r-sm);
  background: var(--accent);
  transform: skewX(var(--skew)) translateX(6px);
  opacity: 0;
  transition: opacity var(--t-fast);
}

.gallery-btn:hover::after,
.gallery-btn:focus-visible::after { opacity: 1; }

/* --- Lightbox. Built and appended to <body> by site.js on first use. --- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  background: rgb(0 0 0 / .95);
  color: var(--text-light);
}

.lightbox.is-open { display: block; }

.lightbox-inner {
  position: absolute;
  inset: 0;
  display: grid;
  /* minmax(0, 1fr), not 1fr: a bare 1fr row has an auto minimum, so a tall
     portrait photo grew the row past the viewport and max-height: 100% then
     resolved against that oversized row. Found 2026-09-28 on a gallery of
     phone portraits (1200x2597); landscape galleries never showed it. */
  grid-template-rows: minmax(0, 1fr) auto;
  align-items: center;
  justify-items: center;
  gap: var(--sp-3);
  padding: clamp(3.5rem, 8vw, 4.5rem) clamp(.75rem, 4vw, 3.5rem) clamp(4rem, 9vw, 3.5rem);
}

.lightbox-img {
  max-width: 100%;
  max-height: 100%;
  min-height: 0;
  width: auto;
  height: auto;
  object-fit: contain;
  border: 3px solid rgb(var(--accent-rgb) / .35);
  background: var(--ink);
}

.lightbox-caption {
  max-width: 68ch;
  margin: 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-light-mid);
  text-align: center;
}

/* The hairline on these three is neutral white at low alpha on purpose. It
   separates the control from a 95% black backdrop, which is the one surface in
   the system that is not built out of the palette (see .lightbox above), so a
   palette colour would be the wrong tool. */
.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: absolute;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  padding: 0;
  border: var(--border-weight) solid rgb(255 255 255 / .28);
  border-radius: var(--r-sm);
  background: rgb(var(--ink-rgb) / .85);
  color: var(--text-light);
  font-family: var(--font-body);
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}

.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.lightbox-close { top: clamp(.5rem, 2vw, 1.25rem); right: clamp(.5rem, 2vw, 1.25rem); }
.lightbox-prev  { left: clamp(.5rem, 2vw, 1.25rem);  top: 50%; transform: translateY(-50%); }
.lightbox-next  { right: clamp(.5rem, 2vw, 1.25rem); top: 50%; transform: translateY(-50%); }

.lightbox-count {
  position: absolute;
  left: 50%;
  bottom: clamp(.6rem, 2.5vw, 1.25rem);
  transform: translateX(-50%);
  padding: .35rem .85rem;
  background: rgb(var(--ink-rgb) / .85);
  border: 1px solid rgb(255 255 255 / .2);
  border-radius: var(--r-sm);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .55);
  white-space: nowrap;
}

@media (max-width: 559.98px) {
  .lightbox-prev,
  .lightbox-next {
    top: auto;
    bottom: .6rem;
    transform: none;
    width: 48px;
    height: 48px;
  }
  .lightbox-prev { left: .6rem; }
  .lightbox-next { right: .6rem; }
  .lightbox-count { bottom: 1.1rem; }
}

/* The scroll lock itself lives on <html> (see the reset). This is here only
   so the class on <body> is meaningful to page authors reading the markup. */
body.is-locked { overscroll-behavior: contain; }


/* ==========================================================================
   16  PILLARS / BENEFITS / POSITIONS
   ========================================================================== */

.pillar-grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
}

@media (min-width: 760px) {
  .pillar-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1100px) {
  .pillar-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.pillar {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-width: 0;
  padding: clamp(1.25rem, 3.5vw, 2rem);
  background: var(--raised);
  border: 1px solid var(--hairline);
  border-left: var(--accent-bar-lg) solid var(--accent);
  border-radius: var(--r-sm);
}

.section-dark .pillar {
  background: var(--ink-2);
  border-color: var(--ink-3);
  border-left-color: var(--accent);
}

.pillar-title {
  font-size: var(--fs-h4);
  color: var(--on-surface);
}

.pillar-quote {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.05rem, .95rem + .6vw, 1.35rem);
  line-height: 1.16;
  text-transform: var(--display-case);
  letter-spacing: var(--display-tracking);
  color: var(--accent-text);
  transform: skewX(var(--skew));
  transform-origin: left center;
  margin: 0;
}

/* Zero specificity for the same reason as the dark-band body rule in section
   06: a <p class="pillar-quote"> must keep its accent, not be repainted muted
   by its own container. */
:where(.pillar) :where(p) { color: var(--on-surface-mid); margin: 0; }

/* --- Benefits --- */
.benefit-grid {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 560px) { .benefit-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .benefit-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.benefit {
  display: flex;
  align-items: flex-start;
  gap: .8rem;
  min-height: 56px;
  padding: .85rem 1rem;
  background: var(--raised);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  font-weight: 600;
  color: var(--on-surface);
}

.section-dark .benefit { background: var(--ink-2); border-color: var(--ink-3); }

.benefit::before {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  margin-top: .45em;
  border-radius: var(--r-sm);
  background: var(--accent);
  transform: skewX(var(--skew));
}

/* --- Open positions --- */
.position-list {
  display: grid;
  gap: 0;
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--hairline);
}

@media (min-width: 720px) {
  .position-list { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-6); }
}

.position {
  display: flex;
  align-items: center;
  gap: .9rem;
  min-height: 60px;
  padding: .9rem 0;
  border-bottom: 1px solid var(--hairline);
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(.95rem, .9rem + .3vw, 1.1rem);
  text-transform: var(--display-case);
  letter-spacing: var(--display-tracking);
  color: var(--on-surface);
}

.position::before {
  content: "";
  flex: none;
  width: 16px;
  height: 7px;
  border-radius: var(--r-sm);
  background: var(--accent);
  transform: skewX(var(--skew));
}


/* ==========================================================================
   17  FORMS
   ========================================================================== */

.form {
  background: var(--raised);
  border: 1px solid var(--hairline);
  border-top: var(--accent-bar-lg) solid var(--accent);
  border-radius: var(--r-md);
  padding: clamp(1.25rem, 4vw, 2.25rem);
}

.field { display: block; margin-bottom: var(--sp-5); }
.field:last-child { margin-bottom: 0; }

.field-row {
  display: grid;
  gap: 0 var(--sp-5);
  grid-template-columns: 1fr;
}

@media (min-width: 720px) {
  .field-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.label {
  display: block;
  margin-bottom: .4rem;
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .35);
  text-transform: var(--label-case);
  color: var(--on-surface);
}

.label .required { color: var(--danger); }

.input,
.select,
.textarea {
  display: block;
  width: 100%;
  min-height: 50px;
  padding: .7rem .9rem;
  background: var(--paper);
  color: var(--text-dark);
  border: var(--border-weight) solid var(--paper-3);
  border-radius: var(--r-sm);
  font-size: 1rem;
  line-height: 1.4;
  transition: border-color var(--t-fast), background-color var(--t-fast);
}

.input:hover,
.select:hover,
.textarea:hover { border-color: var(--paper-4); }

.input:focus,
.select:focus,
.textarea:focus { border-color: var(--accent-deep); }

.textarea {
  min-height: 150px;
  resize: vertical;
}

.select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 2.75rem;
  background-image: var(--select-caret);
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 12px 8px;
}

.input[aria-invalid="true"],
.select[aria-invalid="true"],
.textarea[aria-invalid="true"] {
  border-color: var(--danger);
  background: var(--danger-soft);
}

.form-error {
  margin-top: .4rem;
  font-size: var(--fs-small);
  font-weight: 700;
  line-height: 1.4;
  color: var(--danger);
}

.form-error::before { content: "\26A0\FE0E  "; }

.form-note {
  margin-top: var(--sp-4);
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--on-surface-mid);
}

.form-note a { color: var(--text-dark); font-weight: 700; }

/* --- Checkbox group --- */
.checkgroup {
  display: grid;
  gap: .5rem;
  grid-template-columns: 1fr;
  border: 0;
  padding: 0;
  margin: 0;
}

@media (min-width: 560px) { .checkgroup { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.check {
  display: flex;
  align-items: flex-start;
  gap: .65rem;
  min-height: 48px;
  padding: .6rem .75rem;
  background: var(--paper);
  border: 1px solid var(--paper-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-small);
  line-height: 1.35;
  cursor: pointer;
  transition: border-color var(--t-fast), background-color var(--t-fast);
}

.check:hover { border-color: var(--accent-deep); }

/* accent-color stays the ink on purpose: a bright accent behind a white
   checkmark is unreadable at 20px. */
.check input[type="checkbox"],
.check input[type="radio"] {
  flex: none;
  width: 20px;
  height: 20px;
  margin: .1rem 0 0;
  accent-color: var(--ink);
  cursor: pointer;
}

.check:has(input:checked) {
  border-color: var(--accent-deep);
  box-shadow: inset 0 0 0 1px var(--accent-deep);
}


/* ==========================================================================
   18  CONTACT / BREADCRUMB / PROSE
   ========================================================================== */

.contact-grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 1000px) {
  .contact-grid { grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); }
}

.contact-detail {
  display: block;
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--hairline);
}

.contact-detail:first-child { padding-top: 0; }

.contact-detail dt,
.contact-detail .label {
  margin-bottom: .3rem;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: calc(var(--label-tracking) * .78);
  text-transform: var(--label-case);
  color: var(--on-surface-mid);
}

.contact-detail dd { margin: 0; }

.contact-detail a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.05rem, .95rem + .55vw, 1.4rem);
  letter-spacing: var(--display-tracking);
  text-transform: var(--display-case);
  color: var(--on-surface);
  text-decoration: none;
  border-bottom: 3px solid var(--accent);
  word-break: break-word;
}

.contact-detail a:hover { color: var(--accent-text); border-bottom-color: var(--accent-deep); }

.contact-detail p { margin: 0; color: var(--on-surface-mid); }

/* --- Breadcrumb --- */
.breadcrumb {
  margin-bottom: var(--sp-4);
  font-size: var(--fs-small);
  color: var(--on-surface-mid);
}

.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3rem .55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.breadcrumb li { display: inline-flex; align-items: center; gap: .55rem; }

.breadcrumb li + li::before {
  content: "/";
  color: var(--accent-deep);
  font-weight: 700;
}

.section-dark .breadcrumb li + li::before,
.hero .breadcrumb li + li::before { color: var(--accent); }

.breadcrumb a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  color: inherit;
  text-decoration: underline;
}

.breadcrumb a:hover { color: var(--accent-text); }

.breadcrumb [aria-current="page"] { color: var(--on-surface); font-weight: 600; }

/* --- Prose: long-form pages (privacy, terms, notes, articles) --- */
.prose {
  max-width: 72ch;
  color: var(--on-surface);
}

.prose > * + * { margin-top: 1.1em; }

.prose h2 { margin-top: 2.2em; font-size: var(--fs-h3); }
.prose h3 { margin-top: 1.8em; font-size: var(--fs-h4); }
.prose h2:first-child,
.prose h3:first-child { margin-top: 0; }

.prose p,
.prose li { color: var(--on-surface-mid); }

.prose ul,
.prose ol { padding-left: 1.35rem; }

.prose li + li { margin-top: .45em; }

.prose ul { list-style: none; padding-left: 0; }

.prose ul > li {
  position: relative;
  padding-left: 1.6rem;
}

.prose ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 11px;
  height: 11px;
  border-radius: var(--r-sm);
  background: var(--accent);
  transform: skewX(var(--skew));
}

/* A .chip-row nested inside .prose must not inherit the prose list marker.
   .prose ul > li gets an accent square bullet and a 1.6rem indent, which is
   right for a sentence list and wrong for a row of pills. Reset the marker,
   the indent and the stacked li spacing so .chip-row keeps its own flex row
   and its own gap. Ordinary .prose lists are untouched. */
.prose .chip-row > li { padding-left: 0; }
.prose .chip-row > li::before { content: none; }
.prose .chip-row > li + li { margin-top: 0; }

.prose a {
  color: var(--text-dark);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--accent-deep);
}

.prose a:hover { text-decoration-color: var(--ink); }

.prose strong { color: var(--on-surface); }


/* ==========================================================================
   19  STICKY MOBILE CALL BAR  (phones only, <= 720px)
   ========================================================================== */

.call-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 80;
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 3px solid var(--accent);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  box-shadow: 0 -8px 24px rgb(0 0 0 / .35);
}

.call-bar-link {
  min-height: var(--call-bar-h);
  padding: .6rem .5rem;
  border: 0;
  border-radius: 0;
  transform: none;               /* no slant, these are full-bleed halves */
  background: var(--ink);
  color: var(--text-light);
  font-size: clamp(.82rem, .76rem + .5vw, .95rem);
  letter-spacing: calc(var(--label-tracking) * .28);
  --ring: var(--accent);
  --ring-halo: var(--ink);
}

.call-bar-link > * { transform: none; }

/* Pressed state. The same accent-deep + paper pair every other control in the
   system uses, so both halves of the bar press the same way. */
.call-bar-link:active {
  transform: none;
  background: var(--accent-deep);
  color: var(--paper);
}

.call-bar-primary {
  background: var(--accent);
  color: var(--on-accent);
}

.call-bar-primary:active { background: var(--accent-deep); color: var(--paper); }

@media (min-width: 721px) {
  .call-bar { display: none; }
}


/* ==========================================================================
   20  FOOTER
   Every footer carries the Rush Webworks credit. Do not remove .footer-credit.
   ========================================================================== */

.footer {
  position: relative;
  background: var(--ink);
  color: var(--text-light);
  padding-top: calc(clamp(2.5rem, 6vw, 4rem) * var(--section-rhythm));
  padding-bottom: calc(clamp(1.5rem, 4vw, 2.5rem) * var(--section-rhythm));
  border-top: calc(var(--border-weight) * 3) solid var(--accent);
}

.footer-grid {
  display: grid;
  gap: var(--sp-6) var(--sp-5);
  grid-template-columns: 1fr;
}

@media (min-width: 620px) {
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .footer-grid { grid-template-columns: 1.4fr 1fr 1fr 1.2fr; gap: var(--sp-6); }
}

.footer-col { min-width: 0; }

.footer-brand .brand { margin-bottom: var(--sp-4); }

.footer-brand p {
  color: var(--text-light-mid);
  font-size: var(--fs-small);
  max-width: 40ch;
}

.footer-head {
  margin-bottom: var(--sp-3);
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--label-tracking);
  text-transform: var(--label-case);
  color: var(--accent-text);
}

.footer-links {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  padding: .25rem 0;
  color: var(--text-light-mid);
  font-size: var(--fs-small);
  text-decoration: none;
}

.footer-links a:hover {
  color: var(--accent-on-dark);
  text-decoration: underline;
  text-decoration-color: var(--accent);
}

.footer-contact { display: grid; gap: .1rem; }

.footer-contact a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  color: var(--text-light);
  font-size: var(--fs-small);
  font-weight: 600;
  text-decoration: none;
  word-break: break-word;
}

.footer-contact a:hover { color: var(--accent-on-dark); }

.footer-contact .footer-tel {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.1rem, 1rem + .5vw, 1.35rem);
  letter-spacing: var(--display-tracking);
  color: var(--accent-text);
}

.footer-contact address {
  font-style: normal;
  color: var(--text-light-mid);
  font-size: var(--fs-small);
  padding-block: .5rem;
}

.footer .chip-row { margin-top: var(--sp-4); }

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem var(--sp-5);
  margin-top: clamp(2rem, 5vw, 3rem);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--ink-3);
  font-size: var(--fs-small);
  color: var(--text-light-mid);
}

.footer-bottom p { margin: 0; color: var(--text-light-mid); }

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer-legal a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  color: var(--text-light-mid);
  text-decoration: underline;
}

.footer-legal a:hover { color: var(--accent-on-dark); }

/* The studio credit. Markup contract:
     <p class="footer-credit">Site built by
       <a href="https://rushwebworks.com">Rush Webworks</a></p> */
.footer-credit { color: var(--text-light-mid); }

.footer-credit a {
  color: var(--accent-on-dark);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: rgb(var(--accent-rgb) / .45);
}

.footer-credit a:hover { text-decoration-color: var(--accent); }


/* ==========================================================================
   21  REVEAL ON SCROLL
   Content is visible by default. site.js adds .js-reveal to <html> only when
   IntersectionObserver exists AND the user allows motion, which is the only
   way .reveal ever becomes hidden. No-JS and reduced-motion users see
   everything immediately.
   ========================================================================== */

.reveal { opacity: 1; transform: none; }

.js-reveal .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity .65s ease,
    transform .65s cubic-bezier(.16, .84, .44, 1);
  transition-delay: calc(var(--i, 0) * 85ms);
  will-change: opacity, transform;
}

.js-reveal .reveal.in {
  opacity: 1;
  transform: none;
}


/* ==========================================================================
   22  REDUCED MOTION
   Kills every transition and animation in the stylesheet. This is not a
   courtesy, it is the accessibility floor. Do not weaken it.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: .001ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }

  html { scroll-behavior: auto; }

  .hero-slide.is-active img { animation: none; transform: none; }
  .hero-slide { transition: none; }
  .nav-drawer.is-open { animation: none; }
  .js-reveal .reveal { opacity: 1; transform: none; }
  .card-media img,
  .gallery-btn img { transition: none; }
}


/* ==========================================================================
   23  PRINT
   ========================================================================== */

@media print {
  .header,
  .nav,
  .nav-drawer,
  .nav-toggle,
  .skip-link,
  .call-bar,
  .hero-slides,
  .hero-scrim,
  .hero-dots,
  .lightbox,
  .filter-bar,
  .cta-band,
  .btn,
  .btn-row,
  .nav-cta { display: none !important; }

  html { overflow-x: visible; }

  body {
    padding-bottom: 0;
    background: #fff !important;
    color: #000 !important;
    font-size: 11pt;
    line-height: 1.45;
  }

  *,
  *::before,
  *::after {
    background: transparent !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
    transform: none !important;
    filter: none !important;
  }

  .section,
  .section-dark,
  .section-light,
  .quote-band,
  .footer,
  .hero {
    background: #fff !important;
    color: #000 !important;
    padding-block: 12pt;
    min-height: 0 !important;
    margin-top: 0 !important;
  }

  .card,
  .pillar,
  .form,
  .benefit,
  .work-card {
    border: 1pt solid #999 !important;
    break-inside: avoid;
  }

  h1, h2, h3, h4 { break-after: avoid; color: #000 !important; }

  img { max-width: 100% !important; break-inside: avoid; }

  /* Accent marks print as solid black bars. The divider drops its clip-path
     so a torn brush edge does not turn into a row of black specks on paper. */
  .slash-rule,
  .eyebrow::before,
  .service-list > li::before,
  .prose ul > li::before,
  .benefit::before,
  .position::before,
  .split-media::after { background: #000 !important; }

  .slash-rule {
    clip-path: none !important;
    height: 3pt !important;
  }

  .slash-rule::after { display: none !important; }

  a { text-decoration: underline; }

  a[href^="http"]::after,
  a[href^="mailto:"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    word-break: break-all;
  }

  a[href^="tel:"]::after { content: ""; }

  /* --print-origin is set once in section 00. */
  a[href^="/"]::after {
    content: " (" var(--print-origin) attr(href) ")";
    font-size: 9pt;
    word-break: break-all;
  }

  .footer-bottom { border-top: 1pt solid #999; }

  @page { margin: 14mm; }
}


/* ==========================================================================
   24  PNW HOME & YARD CARE  |  the face on top of the bones
   Everything in this section is this site's own: the treeline edge, the
   contour texture, the split hero with the before/after slider, the season
   banner, the expanding work cards, the steps, the FAQ and the page heads.
   It reads the brand tokens from section 00 and the system tokens from 01,
   so a palette change up there carries through here untouched.
   ========================================================================== */

:root {
  /* The two site-specific devices. --treeline is a hand-tuned conifer
     silhouette (221 points) used as a clip-path. --contour is a tile of
     topographic rings, white strokes, painted at low alpha on dark bands. */
  --moss:     #6FA36C;
  --moss-rgb: 111 163 108;
  --treeline: polygon(0% 100%,0% 90.6%,0.4% 74.9%,0.7% 70.7%,1.1% 54.9%,1.4% 50.8%,2.1% 30.8%,2.8% 50.8%,3% 46.6%,3.4% 70.7%,3.7% 66.5%,4.1% 90.6%,4.1% 77.4%,4.5% 59.7%,4.8% 55%,5.2% 37.3%,5.5% 32.6%,6.2% 10.1%,6.9% 32.6%,7.2% 27.9%,7.6% 55%,7.9% 50.3%,8.3% 77.4%,8.3% 75.7%,8.7% 59.6%,9.1% 55.3%,9.5% 39.2%,9.9% 34.9%,10.6% 14.5%,11.4% 34.9%,11.8% 30.6%,12.2% 55.3%,12.6% 51%,13% 75.7%,13% 90%,13.6% 65.2%,13.8% 61.2%,14.6% 32.3%,15.3% 61.2%,15.5% 57.1%,16.1% 90%,16.1% 82.2%,16.9% 65%,17.3% 62.2%,18.4% 42.3%,19.6% 62.2%,19.9% 59.4%,20.7% 82.2%,20.7% 75.1%,21.6% 47.9%,21.9% 43.5%,23.1% 11.8%,24.3% 43.5%,24.6% 39%,25.4% 75.1%,25.4% 74.5%,25.8% 68.9%,26% 67.4%,26.3% 61.7%,26.5% 60.2%,27.1% 53.1%,27.6% 60.2%,27.8% 58.7%,28.1% 67.4%,28.4% 65.9%,28.7% 74.5%,28.7% 77.5%,29.4% 56.5%,29.6% 53.1%,30.5% 28.6%,31.5% 53.1%,31.7% 49.7%,32.4% 77.5%,32.4% 85.9%,32.9% 72.5%,33.2% 69%,33.7% 55.5%,34% 52%,34.8% 35%,35.6% 52%,35.9% 48.4%,36.4% 69%,36.7% 65.4%,37.2% 85.9%,37.2% 83.9%,38% 65.7%,38.4% 62.7%,39.6% 41.5%,40.8% 62.7%,41.1% 59.8%,42% 83.9%,42% 78.1%,42.5% 70.2%,42.8% 68.1%,43.3% 60.1%,43.7% 58%,44.5% 47.9%,45.3% 58%,45.7% 55.9%,46.2% 68.1%,46.5% 66%,47% 78.1%,47% 75.9%,47.5% 56.4%,47.7% 53.3%,48.4% 30.6%,49% 53.3%,49.2% 50.1%,49.7% 75.9%,49.7% 91.2%,50.7% 70.5%,51.1% 67.1%,52.4% 42.9%,53.8% 67.1%,54.2% 63.7%,55.2% 91.2%,55.2% 74.9%,55.5% 56.6%,55.7% 51.7%,56.1% 33.3%,56.3% 28.4%,56.8% 5.1%,57.4% 28.4%,57.6% 23.5%,58% 51.7%,58.2% 46.8%,58.5% 74.9%,58.5% 75.3%,59.6% 61.1%,60% 58.7%,61.5% 42.2%,63% 58.7%,63.4% 56.4%,64.4% 75.3%,64.4% 75.6%,65% 69.1%,65.3% 67.4%,65.8% 61%,66.2% 59.3%,67.1% 51.1%,67.9% 59.3%,68.3% 57.6%,68.8% 67.4%,69.2% 65.7%,69.7% 75.6%,69.7% 90.6%,70.2% 69.4%,70.4% 66%,71% 41.3%,71.7% 66%,71.9% 62.5%,72.3% 90.6%,72.3% 75.1%,72.7% 71.9%,72.9% 71%,73.2% 67.8%,73.5% 67%,74.1% 62.9%,74.6% 67%,74.9% 66.1%,75.2% 71%,75.4% 70.2%,75.8% 75.1%,75.8% 82.1%,76.4% 60%,76.6% 56.5%,77.4% 30.8%,78.2% 56.5%,78.4% 52.9%,79% 82.1%,79% 81.5%,79.6% 64.3%,80% 59.7%,80.6% 42.5%,81% 37.9%,82% 16.1%,83% 37.9%,83.4% 33.4%,83.9% 59.7%,84.4% 55.2%,84.9% 81.5%,84.9% 77.8%,85.2% 68%,85.4% 65.4%,85.7% 55.6%,85.9% 53%,86.4% 40.5%,86.9% 53%,87.1% 50.4%,87.4% 65.4%,87.6% 62.8%,87.9% 77.8%,87.9% 84.7%,88.9% 49%,89.3% 43.2%,90.7% 1.8%,92.1% 43.2%,92.5% 37.4%,93.5% 84.7%,93.5% 89.4%,94.1% 69.2%,94.3% 65.9%,95.1% 42.4%,96% 65.9%,96.2% 62.6%,96.8% 89.4%,96.8% 81.9%,97.3% 72.4%,97.5% 70.9%,98.2% 59.8%,98.8% 70.9%,99% 69.3%,99.5% 81.9%,99.5% 79.3%,100% 65.4%,100% 63.2%,100% 47%,100% 63.2%,100% 60.9%,100% 79.3%,100% 100%);

--contour: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='420' height='420' viewBox='0 0 420 420' fill='none' stroke='%23fff' stroke-width='1.1'%3E%3Cpath d='M172 150C170 152 167 153 165 155C164 156 162 157 162 159C161 161 161 162 161 165C161 167 160 169 159 172C158 174 156 176 153 177C151 178 147 179 145 179C142 179 138 179 136 178C133 178 130 177 127 176C125 175 122 175 119 173C117 172 114 171 112 169C110 167 109 165 109 163C108 161 108 158 109 156C109 154 111 152 111 150C112 148 112 147 112 145C112 143 112 141 112 138C112 136 111 133 112 131C113 129 115 126 118 125C120 123 124 123 127 123C130 123 133 125 136 126C139 127 141 128 143 129C146 129 147 129 150 129C153 129 156 128 160 128C163 128 168 127 171 129C174 130 178 132 179 134C180 136 180 140 179 142C178 145 175 148 173 150Z'/%3E%3Cpath d='M200 150C200 154 200 158 198 161C197 165 196 169 194 172C191 175 188 178 184 181C181 183 176 185 172 186C168 188 164 190 160 191C156 193 152 196 147 198C143 200 137 202 132 203C126 204 119 205 114 204C109 202 103 199 99 196C95 193 93 188 91 184C89 180 89 175 87 172C86 168 85 165 83 161C81 157 77 154 75 150C73 146 70 141 70 137C70 132 71 127 75 123C78 120 84 117 90 116C96 114 103 115 109 115C114 115 119 116 123 116C128 116 130 115 134 113C138 111 142 107 147 105C152 102 159 99 165 98C172 97 180 97 185 99C191 101 196 105 199 109C202 114 203 119 203 124C204 129 202 134 202 138C201 142 201 146 200 150Z'/%3E%3Cpath d='M222 150C220 155 217 160 216 165C215 170 215 175 214 180C213 186 213 193 210 199C207 204 203 210 197 214C191 218 182 220 175 221C167 222 159 221 151 221C143 220 137 218 130 217C122 216 116 216 108 215C101 215 92 214 85 212C77 211 68 208 62 204C56 200 51 194 47 188C44 182 44 175 44 168C44 162 46 156 48 150C49 144 51 139 53 133C55 128 56 122 59 117C62 112 65 106 70 102C75 97 81 93 88 91C94 88 102 88 109 87C116 86 123 87 130 87C137 86 143 86 150 85C157 84 165 81 174 81C182 80 193 79 201 81C210 82 220 86 226 91C232 96 236 103 237 110C238 117 236 125 233 132C231 139 226 145 223 150Z'/%3E%3Cpath d='M263 150C261 158 259 165 257 173C256 180 256 188 253 196C250 204 247 213 241 220C235 226 226 233 216 236C207 240 194 240 184 240C173 239 162 236 153 233C144 231 136 228 128 226C120 224 113 224 104 224C95 223 86 224 75 223C65 222 53 220 44 217C34 213 24 207 17 200C10 194 6 185 3 176C0 168 -1 159 0 150C0 141 2 132 5 124C8 116 12 107 19 100C25 93 33 87 42 82C51 78 62 75 72 74C83 72 94 73 103 74C112 75 120 77 129 77C137 77 143 76 152 75C160 73 169 69 180 68C191 66 204 64 215 65C227 66 240 70 248 75C257 81 264 89 268 98C271 106 270 116 270 125C269 134 265 142 263 150Z'/%3E%3Cpath d='M354 310C355 312 357 313 358 315C359 318 361 320 362 323C363 326 363 329 362 332C360 334 358 337 355 338C352 339 348 340 344 340C341 340 337 338 334 338C331 337 329 336 326 335C324 334 321 334 319 333C316 332 314 331 312 330C310 329 308 328 307 326C305 324 305 322 304 321C303 319 303 317 302 315C302 314 301 312 300 310C299 308 298 306 297 304C296 301 295 298 296 296C296 293 297 291 299 289C301 287 305 286 308 285C311 284 315 284 318 285C321 285 323 285 326 285C329 285 331 285 334 285C337 285 340 284 342 284C345 285 349 285 351 286C354 287 356 289 357 291C358 294 358 296 357 299C357 301 356 303 355 305C355 307 354 308 355 310Z'/%3E%3Cpath d='M388 310C387 314 386 317 386 321C386 325 387 329 387 333C387 338 388 344 385 348C383 353 379 358 374 360C369 362 362 363 355 362C349 362 342 359 337 356C332 354 328 350 324 348C320 347 317 345 313 345C309 344 304 345 299 345C294 345 287 345 282 343C276 342 271 339 267 336C264 332 262 327 261 323C260 319 261 314 262 310C262 306 264 302 265 297C266 293 267 289 268 285C270 281 273 276 276 273C280 270 285 267 291 265C296 264 303 264 308 265C314 266 319 268 324 269C328 270 332 272 336 272C340 272 344 271 349 270C354 270 361 268 367 268C373 269 380 270 385 272C389 275 393 279 395 283C396 288 395 293 394 298C393 302 390 306 389 310Z'/%3E%3Cpath d='M426 310C432 316 436 324 437 331C438 337 435 345 431 351C427 357 419 362 411 366C404 370 394 371 386 373C378 375 370 376 363 377C355 379 349 380 341 382C334 383 326 384 318 384C311 384 302 383 296 381C289 378 282 374 277 370C273 365 270 359 267 354C264 348 263 343 261 338C259 333 257 329 254 325C251 320 247 315 244 310C241 305 238 298 237 292C236 286 236 279 238 272C240 266 245 260 250 255C255 249 262 245 269 241C276 237 284 234 292 232C300 230 309 229 317 229C326 229 335 230 342 232C350 235 357 239 362 243C368 248 372 254 375 259C379 264 380 269 383 273C386 278 388 281 392 285C397 288 403 291 408 295C414 299 422 304 427 310Z'/%3E%3Cpath d='M438 310C445 317 455 326 459 335C464 344 467 356 465 365C462 374 455 384 445 390C436 395 421 398 409 399C397 401 383 398 372 397C361 396 352 394 343 393C334 393 326 394 317 395C308 396 297 398 287 398C277 397 266 396 257 393C248 390 239 383 233 377C227 371 224 362 221 355C218 347 218 339 216 332C215 324 214 317 213 310C212 303 211 295 211 287C212 280 214 271 218 264C222 257 228 250 235 244C242 239 251 234 259 230C268 226 277 223 286 220C295 216 304 213 314 210C325 207 336 204 347 203C357 203 370 204 380 207C390 211 399 218 405 226C411 233 413 243 415 252C416 260 414 268 415 275C416 282 416 287 420 293C424 298 432 303 438 310Z'/%3E%3C/svg%3E");
}

/* --- 24.1  Contour texture on dark surfaces ------------------------------- */
.has-contour { position: relative; isolation: isolate; }

.has-contour::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: var(--contour);
  background-size: 420px 420px;
  opacity: .085;
  -webkit-mask-image: radial-gradient(120% 95% at 85% 0%, #000 25%, transparent 78%);
          mask-image: radial-gradient(120% 95% at 85% 0%, #000 25%, transparent 78%);
}

/* --- 24.2  Treeline edge --------------------------------------------------
   A strip that sits BETWEEN a light section and the dark section under it.
   Its own background is the colour of the section above; the ink trees are
   painted on ::before and clipped, so they read as a silhouette against the
   light "sky". Never used dark-to-light: trees pointing down are icicles. */
.edge-trees {
  position: relative;
  z-index: 1;
  height: clamp(30px, 5.4vw, 64px);
  margin-bottom: -1px;
  background: var(--paper);
}

.section-light + .edge-trees { background: var(--paper-2); }

.edge-trees::before {
  content: "";
  position: absolute;
  inset: 0 -1% 0 -1%;
  background: var(--ink);
  clip-path: var(--treeline);
}

/* A tonal horizon inside the hero: the same silhouette in a moss tint. */
.hero-trees {
  position: absolute;
  left: -1%;
  right: -1%;
  bottom: -2px;
  z-index: 0;
  height: clamp(64px, 12vw, 160px);
  background: rgb(var(--moss-rgb) / .16);
  clip-path: var(--treeline);
  pointer-events: none;
}

/* --- 24.3  Split hero -----------------------------------------------------
   Headline on the left, the before/after proof on the right. The photos are
   phone portraits, so they get a tall frame instead of a full-bleed crop
   that would go soft on a desktop. */
.hero.hero-split {
  align-items: center;
  min-height: 0;
  padding-top: calc(var(--header-h) + clamp(2.5rem, 6vw, 4.5rem));
  padding-bottom: clamp(3.5rem, 9vw, 7rem);
  background: var(--ink);
}

.hero-split .hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
  grid-template-columns: 1fr;
}

@media (min-width: 960px) {
  .hero-split .hero-grid { grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr); }
}

.hero.hero-split .hero-inner { max-width: 640px; }

.hero.hero-split .hero-inner h1 {
  font-size: clamp(2.3rem, 1.3rem + 3.9vw, 4.1rem);
  line-height: 1;
  text-shadow: none;
}

.hero-split .hero-inner h1 em {
  font-style: normal;
  color: var(--accent);
}

.hero.hero-split .lede {
  text-shadow: none;
  color: rgb(var(--paper-rgb) / .84);
}

.hero-split .btn-row { margin-top: var(--sp-5); }

.hero-note {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1.1rem;
  margin: var(--sp-5) 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-small);
  color: var(--text-light-mid);
}

.hero-note li { display: inline-flex; align-items: center; gap: .45rem; }

.hero-note li::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.hero-proof { position: relative; }

.hero-proof .ba {
  aspect-ratio: 4 / 5;
  border-radius: var(--r-lg);
  box-shadow: var(--sh-3), 0 0 0 1px rgb(255 255 255 / .08);
}

@media (max-width: 959.98px) {
  .hero-proof .ba { aspect-ratio: 4 / 4.3; max-width: 560px; }
}

.hero-proof-cap {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin: .9rem 0 0;
  font-size: var(--fs-small);
  color: var(--text-light-mid);
}

.hero-proof-cap b { color: var(--text-light); font-weight: 600; }

/* --- 24.4  Before/after slider -------------------------------------------
   Two photos stacked; the "before" one is clipped to the left of --pos and a
   native range input sits invisibly over the whole box and drives --pos.
   Keyboard and touch come free with the input. */
.ba {
  --pos: 50%;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md);
  background: var(--ink-2);
  user-select: none;
  -webkit-user-select: none;
}

.ba img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ba-before { clip-path: inset(0 calc(100% - var(--pos)) 0 0); }

.ba-tag {
  position: absolute;
  top: .85rem;
  z-index: 2;
  padding: .36rem .75rem;
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  background: rgb(var(--ink-rgb) / .74);
  color: var(--text-light);
  pointer-events: none;
}

.ba-tag-before { left: .85rem; }

.ba-tag-after {
  right: .85rem;
  background: var(--accent);
  color: var(--on-accent);
}

.ba-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  z-index: 2;
  width: 3px;
  margin-left: -1.5px;
  background: var(--paper);
  box-shadow: 0 0 0 1px rgb(0 0 0 / .22);
  pointer-events: none;
}

.ba-handle {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 6px 18px rgb(0 0 0 / .4);
  transform: translate(-50%, -50%);
  transition: transform var(--t-fast);
}

.ba-handle svg { width: 24px; height: 24px; }

.ba:focus-within .ba-handle {
  outline: 3px solid var(--paper);
  outline-offset: 3px;
}

.ba-range {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  opacity: 0;
  cursor: ew-resize;
  -webkit-appearance: none;
          appearance: none;
  touch-action: pan-y;
}

/* The one-time demo wipe on first sight: both the clip and the line ease. */
.ba.is-demo .ba-before,
.ba.is-demo .ba-line {
  transition: clip-path 1.05s cubic-bezier(.4, 0, .2, 1), left 1.05s cubic-bezier(.4, 0, .2, 1);
}

.ba-grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  grid-template-columns: 1fr;
}

@media (min-width: 760px) {
  .ba-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.ba-fig { margin: 0; }

.ba-fig figcaption,
.work-cap {
  margin-top: .7rem;
  font-size: var(--fs-small);
  color: var(--on-surface-mid);
}

.ba-fig figcaption b,
.work-cap b { color: var(--on-surface); font-weight: 600; }

/* --- 24.5  Season banner --------------------------------------------------
   "This month in the yard". js/pnw.js unhides the current month's line; the
   build leaves the build month visible as the no-JS fallback. */
.section.is-tight-top { padding-top: clamp(2rem, 4.5vw, 3rem); }

.season {
  display: grid;
  grid-template-columns: 1fr;
  gap: .9rem 1.6rem;
  align-items: center;
  padding: clamp(1.1rem, 2.6vw, 1.6rem) clamp(1.2rem, 3vw, 2rem);
  border: 1px solid var(--paper-3);
  border-left: 6px solid var(--accent);
  border-radius: var(--r-lg);
  background: var(--paper);
  box-shadow: var(--sh-1);
}

@media (min-width: 760px) {
  .season { grid-template-columns: auto minmax(0, 1fr) auto; }
}

.season-month {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.3rem, 1.05rem + 1vw, 1.7rem);
  line-height: 1;
  letter-spacing: -.01em;
  color: var(--text-dark);
}

.season-month small {
  display: block;
  margin-bottom: .4rem;
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-mid);
}

.season-tip { margin: 0; }
.season-tip p { margin: 0; font-size: 1.05rem; color: var(--text-dark); }
.season-tip p[hidden] { display: none; }
.season .btn { justify-self: start; }

/* --- 24.6  Service cards with icon badges ---------------------------------- */
.svc-group + .svc-group { margin-top: clamp(2.5rem, 5.5vw, 4rem); }

.svc-group-head {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin-bottom: var(--sp-5);
}

.svc-group-head h3 {
  margin: 0;
  font-size: var(--fs-h3);
}

.svc-group-head::after {
  content: "";
  flex: 1;
  height: 2px;
  background: var(--hairline);
}

.svc-ico {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  margin-bottom: .15rem;
  border-radius: 16px;
  background: var(--accent);
  color: var(--on-accent);
}

.svc-ico svg {
  width: 27px;
  height: 27px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.svc-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
}

.svc-kind {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  text-align: right;
  color: var(--text-mid);
}

.service-card .card-body { gap: .6rem; }
.service-card .card-text { font-size: .97rem; }

/* The services page lists what each one includes. */
.svc-detail {
  display: grid;
  gap: clamp(1.25rem, 3vw, 2rem);
  grid-template-columns: 1fr;
  padding: clamp(1.4rem, 3.5vw, 2.25rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--raised);
  scroll-margin-top: calc(var(--header-h) + 1rem);
}

@media (min-width: 760px) {
  .svc-detail { grid-template-columns: 54px minmax(0, 1fr); }
}

.svc-detail h3 { margin: 0 0 .5rem; font-size: var(--fs-h3); }
.svc-detail p { margin: 0 0 .9rem; color: var(--on-surface-mid); }
.svc-detail .service-list { margin-top: .25rem; }
.svc-detail + .svc-detail { margin-top: var(--sp-4); }

.svc-badge {
  display: inline-block;
  margin-left: .5rem;
  padding: .2rem .6rem;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  vertical-align: middle;
}

/* --- 24.7  Expanding cards ------------------------------------------------
   A row of photo panels. The open one takes about three shares of the width
   and reveals its description; the rest slim down and keep their titles.
   Hover, focus and tap all open a panel (js/pnw.js moves .is-open around).
   Below 760px the row becomes a column and the open panel grows in height. */
.xcards {
  display: flex;
  gap: .75rem;
  height: clamp(420px, 46vw, 560px);
}

.xcard {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--ink-2);
  color: var(--text-light);
  box-shadow: 0 0 0 1px rgb(255 255 255 / .06);
  cursor: pointer;
  transition: flex-grow .8s cubic-bezier(.4, 0, .2, 1);
  will-change: flex-grow;
}

.xcard > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(.8) brightness(.86);
  transition: transform 1.2s cubic-bezier(.16, .84, .44, 1), filter .6s ease;
}

.xcard::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgb(var(--ink-rgb) / .94) 0%,
    rgb(var(--ink-rgb) / .58) 36%,
    rgb(var(--ink-rgb) / 0) 66%);
}

.xcard-inner {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: clamp(1rem, 2.4vw, 1.6rem);
}

.xcard-num {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 .5rem;
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--accent);
}

.xcard-num::before {
  content: "";
  width: 18px;
  height: 3px;
  border-radius: 2px;
  background: var(--accent);
}

.xcard-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.1rem, .95rem + .8vw, 1.5rem);
  line-height: 1.1;
  letter-spacing: -.01em;
  color: var(--text-light);
}

.xcard:not(.is-open):not(:focus-within) .xcard-title {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 1rem;
  line-height: 1.2;
}

.xcard-body {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transform: translateY(12px);
  transition:
    grid-template-rows .6s cubic-bezier(.4, 0, .2, 1),
    opacity .4s ease,
    transform .5s cubic-bezier(.16, .84, .44, 1);
}

.xcard-body > div { min-height: 0; overflow: hidden; }

.xcard-text {
  margin: .75rem 0 0;
  max-width: 46ch;
  font-size: .97rem;
  color: rgb(var(--paper-rgb) / .86);
}

.xcard-link {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 40px;
  margin-top: .6rem;
  border-bottom: 2px solid transparent;
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--accent);
  transition: border-color var(--t-fast);
}

.xcard-link::after { content: "\2192"; transition: transform var(--t-fast); }
.xcard-link:hover { border-bottom-color: var(--accent); }
.xcard-link:hover::after { transform: translateX(4px); }
.xcard-link:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }

.xcard.is-open,
.xcard:focus-within { flex-grow: 2.8; }

.xcard.is-open > img,
.xcard:focus-within > img {
  transform: scale(1.06);
  filter: none;
}

.xcard.is-open .xcard-body,
.xcard:focus-within .xcard-body {
  grid-template-rows: 1fr;
  opacity: 1;
  transform: none;
  transition-delay: .14s;
}

.xcards-hint {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 1rem 0 0;
  font-size: var(--fs-small);
  color: var(--text-light-mid);
}

.xcards-hint svg { width: 18px; height: 18px; flex: none; }

@media (max-width: 759.98px) {
  .xcards { flex-direction: column; height: auto; gap: .6rem; }
  .xcard {
    flex: 0 0 auto;
    height: 112px;
    transition: height .6s cubic-bezier(.4, 0, .2, 1);
  }
  .xcard.is-open,
  .xcard:focus-within { flex-grow: 0; height: 410px; }
  .xcard:not(.is-open):not(:focus-within) .xcard-title { -webkit-line-clamp: 1; }
}

/* --- 24.8  How it works ---------------------------------------------------- */
.steps {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
}

@media (min-width: 760px) {
  .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.step {
  position: relative;
  padding: clamp(1.3rem, 3vw, 1.8rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--raised);
}

.section-dark .step { background: var(--ink-2); border-color: var(--ink-3); }

.step-num {
  display: inline-grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin-bottom: 1rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: 1.45rem;
  line-height: 1;
}

.step h3 { margin: 0 0 .5rem; font-size: var(--fs-h4); }
.step p { margin: 0; color: var(--on-surface-mid); }

@media (min-width: 760px) {
  .step + .step::before {
    content: "";
    position: absolute;
    top: calc(clamp(1.3rem, 3vw, 1.8rem) + 28px);
    left: calc(-1 * var(--sp-5));
    width: var(--sp-5);
    border-top: 3px dashed var(--accent);
    opacity: .7;
  }
}

/* --- 24.9  FAQ ------------------------------------------------------------ */
.faq { display: grid; gap: .65rem; }

.faq details {
  overflow: hidden;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--raised);
  transition: border-color var(--t);
}

.faq details[open] { border-color: var(--accent-deep); }

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  list-style: none;
  cursor: pointer;
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--on-surface);
}

.faq summary::-webkit-details-marker { display: none; }

.faq summary::after {
  content: "+";
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--paper-2);
  font-size: 1.2rem;
  font-weight: 700;
  line-height: 1;
  transition: transform var(--t), background-color var(--t);
}

.faq details[open] summary::after {
  background: var(--accent);
  transform: rotate(45deg);
}

.faq summary:focus-visible { outline: 3px solid var(--ring); outline-offset: -3px; }

.faq-a { padding: 0 1.25rem 1.2rem; color: var(--on-surface-mid); }
.faq-a p { margin: 0; }
.faq-a p + p { margin-top: .6rem; }

/* --- 24.10  Interior page head -------------------------------------------- */
.page-head {
  /* Dark surface: the same tokens section 02 gives .hero and .section-dark,
     so headings, eyebrows and body copy pick the light colours. */
  --surface:        var(--ink);
  --raised:         var(--ink-2);
  --on-surface:     var(--text-light);
  --on-surface-mid: var(--text-light-mid);
  --accent-text:    var(--accent-on-dark);
  --hairline:       var(--ink-3);
  position: relative;
  isolation: isolate;
  overflow: hidden;
  margin-top: calc(var(--header-h) * -1);
  padding: calc(var(--header-h) + clamp(2.75rem, 6.5vw, 4.5rem)) 0 clamp(2.75rem, 6.5vw, 4.5rem);
  background: var(--ink);
  color: var(--text-light);
}

.page-head h1 {
  max-width: 22ch;
  margin: 0 0 .85rem;
  font-size: var(--fs-h1);
  line-height: 1.02;
}

.page-head .lede {
  max-width: 58ch;
  color: rgb(var(--paper-rgb) / .84);
}

.page-head .btn-row { margin-top: var(--sp-5); }
.page-head .error-code { margin-bottom: .5rem; }

/* --- 24.11  Contact layout ------------------------------------------------ */
.contact-grid {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 960px) {
  .contact-grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, .85fr); }
  .contact-aside { position: sticky; top: calc(var(--header-h) + 1rem); }
}

/* Grid items default to min-width:auto, which lets a wide intrinsic child
   (a text input's default size) push the form past the wrap on phones. */
.contact-grid > * { min-width: 0; }

.contact-aside { display: grid; gap: 1rem; }
.contact-aside > * { min-width: 0; }

.info-card {
  padding: 1.3rem 1.45rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--raised);
}

.info-card h2 { margin: 0 0 .5rem; font-size: var(--fs-h4); }
.info-card p { margin: 0; color: var(--text-mid); }
.info-card p + p { margin-top: .45rem; }

.info-card .big {
  display: block;
  margin: .2rem 0 .35rem;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(1.05rem, .7rem + 1.5vw, 1.4rem);
  overflow-wrap: anywhere;   /* the email address is one unbreakable word */
  letter-spacing: -.01em;
  color: var(--text-dark);
  text-decoration: none;
}

.info-card .big:hover { color: var(--accent-deep); }

.area-list {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: .6rem 0 0;
  padding: 0;
  list-style: none;
}

.area-list li {
  padding: .32rem .7rem;
  border-radius: var(--r-pill);
  background: var(--paper-2);
  font-size: var(--fs-small);
  color: var(--text-dark);
}

/* --- 24.12  Header and footer marks --------------------------------------- */
.brand .mark {
  display: block;
  flex: none;
  width: auto;
  height: 34px;
}

@media (min-width: 1000px) {
  .brand .mark { height: 40px; }
}

/* The inline nav never wraps a button onto three lines, and between 1000
   and 1200px (laptops) the kicker line goes so the name keeps its width. */
.nav-cta span,
.nav-phone span { white-space: nowrap; }

@media (min-width: 1000px) and (max-width: 1199.98px) {
  .header .wordmark-line:first-child { display: none; }
  .header .brand { flex: none; }          /* the name never ellipsizes */
  .header .brand .mark { height: 32px; }
  .header .nav { gap: .9rem; }
  .header .nav-list { gap: .9rem; }
  .header .nav-phone { margin-inline: 0; }
  .header .nav-cta { padding-inline: 1.05rem; }
}

/* Phones: the two-line lockup does not fit beside the hamburger, so the
   kicker goes and the name gets the width. Measured at 320 and 375. */
@media (max-width: 559.98px) {
  .header .brand { gap: .5rem; }
  .header .brand .mark { height: 30px; }
  .header .wordmark-line:first-child { display: none; }
  .header .wordmark-line:last-child { font-size: .95rem; }
}

.footer-brand .brand {
  flex-direction: column;
  align-items: flex-start;
  gap: .6rem;
  overflow: visible;
}

.footer-brand .brand .mark { height: 44px; }

/* --- 24.13  Reduced motion for the pieces above --------------------------- */
@media (prefers-reduced-motion: reduce) {
  .xcard,
  .xcard > img,
  .xcard-body,
  .ba.is-demo .ba-before,
  .ba.is-demo .ba-line { transition: none !important; }
}
