/* Content must never be invisible by default.
   ------------------------------------------------------------------
   The comp animates sections in on scroll: `.reveal { opacity: 0 }`, with
   JavaScript adding `.in` when the element enters the viewport. On a static
   mockup opened once in a designer's browser that is fine. On a production
   site it means every page is blank below the fold until a script succeeds.

   It did not succeed. Cloudflare Turnstile throws eight uncaught exceptions on
   this host (error 110200, its site key is not valid for .localsite), the
   reveal observer never runs, and all 24-28 `.reveal` elements on every page
   stay at opacity 0. The markup is present, the sections have real height, the
   page returns 200, and the visitor sees nothing.

   Any of these produce the same result in production: a blocked third-party
   script, an ad blocker, a JS error in an unrelated plugin, a slow connection
   that fires the observer late.

   So: visible by default. The entrance animation is given up deliberately.
   A fade-in is worth less than the page being readable. */
.reveal { opacity: 1 !important; transform: translateY(14px); transition: transform .7s cubic-bezier(.2,.7,.2,1); }
.reveal.in { transform: none; }
/* v2 2026-09-03: the entrance is a 14px transform-only rise, never opacity.
   If the observer never runs the section simply sits 14px lower; nothing is
   ever invisible. */
@media (prefers-reduced-motion: reduce) { .reveal { transform: none !important; } }

/* .intro is a two-column grid in the comp: copy on the left, a photo on the
   right. Rendered from meta there is no photo, so the copy sat in a half-width
   column beside an empty half. One column when it is the only child. */
.intro:has(> .intro__body:only-child){grid-template-columns:1fr;max-width:820px;margin:0;}

/* Moved out of main.css so that file stays exactly what merge_css.py
   produces from the comp. Anything hand-written that lived inside it
   would be silently destroyed by the next regeneration. */
/* Skip link. Not in the comp -- added for keyboard access. Sized 44x44 even
   while off-screen: a 1x1 offscreen link still measures as a sub-AA tap target. */
.skip-link{position:absolute;left:-9999px;top:0;min-width:44px;min-height:44px;
  display:inline-flex;align-items:center;padding:12px 18px;background:#fff;
  color:var(--navy);font-weight:700;z-index:9999;}
.skip-link:focus{left:8px;top:8px;outline:3px solid var(--red);}

/* Pagination. Not in the comp -- the comp's /blog/ lists nothing, so it never
   needed any. Sized for WCAG 2.5.8: the default page-number links measure
   9x23 and fail at both desktop and mobile. */
.pagination{margin-top:38px;}
.pagination ul{list-style:none;display:flex;flex-wrap:wrap;gap:8px;justify-content:center;padding:0;}
.pagination a,.pagination span{display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;padding:0 14px;border-radius:10px;
  font-weight:600;font-size:.92rem;text-decoration:none;}
.pagination a{color:var(--navy);border:1px solid var(--rule);}
.pagination a:hover{background:var(--paper-alt);}
.pagination .current{background:var(--navy);color:#fff;}

/* ---- Editor canvas ----
   Loaded into the editor by add_editor_style, so these apply there too.
   The canvas constrained blocks to 840px inside a 1278px frame, which is not
   what any of these pages look like: the comp's sections are full-bleed and
   .container does the constraining. Matching that is most of what makes the
   back end resemble the front end. */
/* Sections run edge to edge in the editor exactly as they do on the site;
   .container inside them still holds the copy to 1240px. Without this the
   canvas showed a 1240px box floating inside a 1278px frame, which is not
   what any of these pages look like. */
.editor-styles-wrapper .wp-block[data-type="core/html"]{max-width:none !important;}
.editor-styles-wrapper > .block-editor-block-list__layout > .wp-block[data-type="core/html"]{
  max-width:none !important;}
.editor-styles-wrapper{padding-left:0;padding-right:0;}
/* The post title still wants a readable measure rather than full bleed. */
.editor-styles-wrapper .wp-block-post-title{max-width:1240px;margin-left:auto;margin-right:auto;}

/* ---------------------------------------------------------------------------
 * Fonts (v2, 2026-09-03). Archivo is self-hosted as ONE variable woff2 and
 * preloaded from parts/head-extra.html, so it is normally on screen before
 * first paint. The fallback below is metric-matched to Archivo's normal
 * width so a slow first visit rewraps as little as possible; the expanded
 * display headings have no plain-Arial equivalent and accept a small shift.
 * ------------------------------------------------------------------------ */
@font-face {
	font-family: "Archivo fallback";
	src: local("Arial"), local("Helvetica"), local("Liberation Sans");
	size-adjust: 103%;
	ascent-override: 92%;
	descent-override: 24%;
}
:root {
	--f-display: "Archivo", "Archivo fallback", Arial, sans-serif;
	--f-body: "Archivo", "Archivo fallback", Arial, sans-serif;
}

/* ---------------------------------------------------------------------------
 * Contrast: separate the red used as INK from the red used as a FILL
 *
 * Measured across 6 pages at 1440, 390 and 320, the whole site produced exactly
 * TWO failing colour combinations, repeated on every page:
 *
 *   #E0312F on #F1F5FA   4.13 : 1   the section eyebrow on alt backgrounds
 *   #4285F4 on #FFFFFF   3.56 : 1   the Google "G" in the trust row
 *
 * Small text needs 4.50, so the eyebrow misses by 0.37. The obvious fix is to
 * darken --red, and it is the wrong one: that token is also the fill behind
 * white button text on 12 rules, and white-on-red is a completely different
 * pair that already passes. Darkening the token to fix text would restyle every
 * CTA on the site to solve a problem those buttons do not have.
 *
 * So the roles are split. --red stays exactly as the comp drew it for fills.
 * --red-ink is 8% darker and used only where red sits ON a light background,
 * which clears 4.5 on the alt background (4.57) and improves white to 5.00.
 * The difference is not perceptible next to a button; the ratio is.
 *
 * THE GOOGLE "G" IS LEFT ALONE, DELIBERATELY. #4285F4 is Google's brand blue,
 * and WCAG 1.4.3 exempts "text that is part of a logo or brand name". Repainting
 * another company's mark to satisfy a checker would be both wrong and a brand
 * usage problem. It is marked aria-hidden instead, because the row already says
 * "on Google" in words and the letter is decorative duplication for a screen
 * reader. Any future contrast report should expect this one and skip it.
 * ------------------------------------------------------------------------ */
:root {
	--red-ink: #D92220;
}

.section__head .eyebrow,
.why__body .eyebrow,
.team__body .eyebrow,
.intro__body .eyebrow,
.svc-card__link,
.area-list a:hover,
.nav__menu a:hover {
	color: var(--red-ink);
}

/* ---------------------------------------------------------------------------
   BLOG IMAGERY. All 56 posts carry a featured image and no template rendered
   one, which is the whole of the "51 of 56 posts have no images" finding. The
   post bodies themselves never had inline photography: the preserved Bricks
   trees contain zero image elements.
   --------------------------------------------------------------------------- */

/* width:auto, not 100%. Five of the 56 originals are narrower than the 760px
   measure (one is 300px). Stretching those to the column would upscale them
   into mush; at their own size they are small but sharp. The width and height
   attributes on the tag hold the box, so nothing shifts. */
.postfeat{margin:0 auto 34px;max-width:760px;}
.postfeat img{display:block;width:auto;max-width:100%;height:auto;margin:0 auto;
  border-radius:16px;box-shadow:var(--shadow-sm);}

/* The thumbnail bleeds to the card edge, so it cancels the card's 24px padding
   and picks up the card's own top radius. aspect-ratio plus object-fit means a
   300px-wide source and a 2083px one occupy an identical box, so a row of
   cards cannot go ragged and none of them can shift. */
.pj__thumb{display:block;margin:-24px -24px 18px;border-radius:15px 15px 0 0;
  overflow:hidden;aspect-ratio:16/9;background:var(--paper-alt);}
.pj__thumb img{display:block;width:100%;height:100%;object-fit:cover;
  transition:transform .4s ease;}
.pj--thumbed:hover .pj__thumb img{transform:scale(1.04);}
@media(prefers-reduced-motion:reduce){
  .pj__thumb img,.pj--thumbed:hover .pj__thumb img{transition:none;transform:none;}
}
