/* Utilities the markup uses that the purged tailwind.css does not define. */
.max-w-\[1200px\]{max-width:1200px}
@media(min-width:768px){
  .md\:px-12{padding-left:3rem;padding-right:3rem}
  .md\:text-3xl{font-size:1.875rem;line-height:2.25rem}
}
.shadow-\[0_0_30px_-5px_rgba\(37\,99\,235\,0\.4\)\]{box-shadow:0 0 30px -5px rgba(37,99,235,.4)}
.shadow-\[0_0_20px_rgba\(37\,99\,235\,0\.3\)\]{box-shadow:0 0 20px rgba(37,99,235,.3)}
.text-accent-blue{color:#4f92f7}
.hover\:bg-accent-blue:hover{background-color:#2563eb}

/* --- Editorial type ---------------------------------------------------
   .uf-body and .uf-lede were only ever given a max-width. Nothing set a
   size, a colour or a margin, so consecutive paragraphs sat flush against
   each other and a Lab article read as one undifferentiated wall of text.
   #a8afba measures 8.5:1 on the #121212 ground. */
.uf-lede{max-width:min(56ch,100%);font-size:clamp(1.125rem,1.5vw,1.375rem);
  line-height:1.55;font-weight:300;color:#c8cdd6}
.uf-body{max-width:min(64ch,100%);font-size:1.0625rem;line-height:1.75;color:#a8afba}
.uf-body+.uf-body{margin-top:1.15rem}

/* --- Work galleries ---------------------------------------------------
   Fixed columns per page instead of auto-fit/minmax, which packed four
   across a 1200px container and stranded the ninth photograph alone on its
   own row. photos.py asserts each page's count divides by its columns.
   The figures carry no inline styles any more, so hover and motion can be
   handled here and reduced-motion can opt out. */
.uf-gallery{display:grid;grid-template-columns:repeat(var(--cols,3),minmax(0,1fr));gap:1rem}
.uf-gallery figure{margin:0;overflow:hidden;border:1px solid rgba(255,255,255,.1);background:#0a0a0a}
.uf-gallery img{width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;display:block;
  transition:transform .6s cubic-bezier(.2,.7,.2,1)}
.uf-gallery figure:hover img{transform:scale(1.04)}
@media (prefers-reduced-motion:reduce){
  .uf-gallery img{transition:none}
  .uf-gallery figure:hover img{transform:none}
}
/* No intermediate 2-column step: nine photographs over two columns strands
   the ninth on its own row, which is the raggedness this replaced. The page
   keeps its own column count down to 560px and then goes single, and one
   column divides any count. */
@media (max-width:560px){.uf-gallery{grid-template-columns:1fr}}

/* Lab article sections: heading in a left rail that holds position while
   its prose scrolls past. html{overflow-x:clip} above is what keeps
   position:sticky working here — overflow-x:hidden would have killed it. */
.lab-sec{border-top:1px solid rgba(255,255,255,.1);padding:3.5rem 0;
  display:grid;grid-template-columns:minmax(0,16rem) minmax(0,42rem);
  gap:clamp(2rem,5vw,4.5rem);align-items:start}
.lab-sec h2{margin:0;position:sticky;top:100px}
@media (max-width:900px){
  .lab-sec{grid-template-columns:1fr;gap:1.1rem;padding:2.5rem 0}
  .lab-sec h2{position:static}
}

/* The hero ghost: 1px at 10% alpha on 160px type reads as nothing.
   Heavier stroke and real contrast so it registers as deliberate. */
/* The original rule lives in a <style> block in the BODY, which beats a
   stylesheet linked in the HEAD at equal specificity. Descendant selectors
   (0,1,1) win instead of resorting to !important. */
h1 .text-outline,.hero-headline .text-outline{
  -webkit-text-stroke:3px rgba(255,255,255,.38);color:transparent}
@media(max-width:768px){
  h1 .text-outline,.hero-headline .text-outline{-webkit-text-stroke-width:2px}}

/* Nothing may push the page sideways on a phone. */
img,figure,svg,table,pre{max-width:100%}

/* The mobile menu is an off-canvas drawer: fixed inset-0 parked off the
   right edge with translate-x-full. A closed drawer still extends the
   document, so scrollWidth measured 584 on a 375px viewport across 17
   pages and every width:100% element inflated with it — which is why the
   nav looked like the culprit and why the number differed per page.
   overflow-x:clip contains it WITHOUT creating a scroll container, so
   position:sticky keeps working (overflow-x:hidden would break it). */
html{overflow-x:clip}

/* Eurostile Extended is very wide: at text-5xl (3rem) a word like
   "DETAILING" is wider than a 375px viewport and runs off the edge.
   h1.uf-display is specificity 0,1,1 so it beats .text-5xl without
   !important. Measured against a real browser at 375px, not a headless
   screenshot — those were misreporting viewport width. */
/* Two display classes exist: .uf-display and .font-display. Clamping only
   the first left every /areas-served/ h1 unclamped, and those overflowed
   375px by up to 209px — the width varied per page because the location
   name does. Both are covered now.
   overflow-wrap guards against a single long token that cannot be broken. */
@media (max-width:640px){
  h1.uf-display,h1.font-display,h1.hero-headline{font-size:clamp(1.75rem,8.4vw,2.75rem);line-height:1.04}
  h2.uf-display,h2.font-display{font-size:clamp(1.35rem,6.2vw,2rem);line-height:1.08}
  h3.uf-display,h3.font-display{font-size:clamp(1.15rem,5vw,1.6rem)}
  h1,h2,h3,h4{overflow-wrap:anywhere}
}
@media (max-width:400px){
  h1.uf-display,h1.hero-headline{letter-spacing:-.04em}
}



/* --- Mobile overflow -------------------------------------------------
   Measured at 375px: the homepage had scrollWidth 813, more than twice
   the viewport. The offenders are decorative display type set in
   absolute rem — text-[15rem] is 240px, so a single word is wider than
   a phone. Clamp them to the viewport instead. */
@media (max-width:768px){
  .text-\[15rem\]{font-size:clamp(3.5rem,20vw,7rem)}
  .text-7xl{font-size:clamp(2rem,11vw,3.25rem);line-height:1.05}
  .text-8xl{font-size:clamp(2.25rem,12vw,3.75rem);line-height:1.02}
  main img{max-width:100%}
}

/* --- Contrast (WCAG AA) ----------------------------------------------
   Measured against the #121212 ground: blue-600 #2563eb came out at 3.94
   and gray-500 #6b7280 at 4.10, both under the 4.5 required for text
   below 24px. Lifted just far enough to pass while staying the same
   blue. Backgrounds are untouched — this is text colour only, so the
   buttons keep the brand blue. */
.text-blue-600,.text-blue-500,.text-accent-blue{color:#4f92f7}
.text-gray-500,.text-gray-600{color:#8d95a3}
/* gray-600 #4b5563 measured 2.78 against #121212 — 114 instances on all
   38 pages, mostly the footer copyright and legal links. Well under the
   4.5 AA needs for text under 24px. */


/* --- Keyboard focus (WCAG 2.4.7) -------------------------------------
   Focusing a footer link produced outline-style:none. Only three :focus
   rules existed in the whole stylesheet and none covered ordinary links,
   so a keyboard user had no idea where they were. :focus-visible keeps
   this off for mouse clicks. */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,
textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible{
  outline:2px solid #4f92f7;outline-offset:3px;border-radius:2px}

/* --- Pointer target size (WCAG 2.2 SC 2.5.8) -------------------------
   Footer links measured 16-20px tall against a 24x24 minimum. Padding
   rather than height so the visual rhythm is unchanged; the social icons
   go 40 -> 44 to clear the AAA 44x44 bar as well. */
footer a{display:inline-block;padding-block:4px}
footer a.w-10,footer a[class*="w-10"]{width:44px;height:44px;padding-block:0}
/* one tel: link measured 246x20; padding keeps its underline-offset intact
   where min-height would not */
main a[href^="tel:"],main a[href^="mailto:"]{padding-block:2px}
/* Standalone navigational links ("Back to Directory", "View Services")
   sat at 16-20px tall. These carry inline-flex or .group, which
   distinguishes them from links inside a sentence — SC 2.5.8 exempts
   genuinely inline text links, so those are deliberately left alone. */
main a[class*="inline-flex"],main a.group{padding-block:4px}

/* --- Hero sheen ------------------------------------------------------
   A soft diagonal specular band, the way light travels across corrected
   paint. Sits at z-1: above the photograph, below the z-20 content, so
   nothing over it loses contrast.
   NB the hero is display:flex, and a pseudo-element on a flex container
   becomes a flex ITEM — position:absolute takes it back out of flow. */
.min-h-\[95vh\]::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(112deg,
      rgba(255,255,255,0) 28%,
      rgba(255,255,255,.045) 44%,
      rgba(220,235,255,.085) 51%,
      rgba(255,255,255,.035) 58%,
      rgba(255,255,255,0) 74%),
    radial-gradient(120% 80% at 78% 18%, rgba(96,150,255,.10), transparent 62%);
  mix-blend-mode:screen;
}
@media (prefers-reduced-motion:reduce){.min-h-\[95vh\]::before{background-image:none}}

/* --- Nav weight ------------------------------------------------------
   The bar was h-24 (96px) with a 24px wordmark — heavy for something
   fixed over the hero. Down to 76px with the logo a step smaller.
   #site-header beats .h-24 on specificity, so no !important. */
#site-header .h-24{height:76px}
#site-header .uf-brand-logo{font-size:1.15rem}
@media (min-width:768px){#site-header .uf-brand-logo{font-size:1.35rem}}

/* --- Hero crowding ---------------------------------------------------
   The hero centres its content inside 95vh, but the fixed header covers
   the top 76px of that box, so the eyebrow ends up jammed under the nav.
   Pad the top by the header height so it centres in the VISIBLE area. */
.min-h-\[95vh\]{padding-top:132px}
@media (max-width:768px){
  #site-header .h-24{height:64px}
  .min-h-\[95vh\]{padding-top:96px}
}
