/* 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:flex;flex-wrap:wrap;gap:1rem}
/* every photo at its own shape: it grows by its width-to-height ratio, so a row lines up at one height */
.uf-gallery figure{flex:var(--r,1.778) 1 calc(var(--r,1.778) * 200px)}
.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:var(--r,1.778);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 figure{flex-basis:100%}}

/* 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}
}

/* =====================================================================
   2026-10 refresh: the WordPress content comes back
   Component classes rather than Tailwind utilities: tailwind.css is
   purged and only holds what the 2026-07 markup used.
   ===================================================================== */

/* Footer carries the same wordmark as the nav. */
/* one line on a 375px phone */
.uf-footer-mark{margin:0 0 1.5rem;font-size:clamp(1.05rem,4.6vw,1.5rem)}

/* Quote button and phone at the foot of the mobile drawer. */
.uf-drawer-cta{display:flex;flex-direction:column;align-items:flex-start;gap:1.25rem;margin-top:2.5rem}

/* --- Footer: brand / services / company / visit ---------------------- */
.uf-footer-grid{display:grid;grid-template-columns:1fr;gap:3rem}
/* phones: the two link lists side by side, brand and address full width */
@media (max-width:767px){
  .uf-footer-grid{grid-template-columns:1fr 1fr;gap:2.5rem 1.5rem}
  .uf-footer-grid>:first-child,.uf-footer-grid>:last-child{grid-column:1/-1}
}
@media (min-width:768px){
  .uf-footer-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
  .uf-footer-grid>:first-child{grid-column:1/-1}
}
@media (min-width:1024px){
  .uf-footer-grid{grid-template-columns:2fr 1fr 1fr 1.2fr}
  .uf-footer-grid>:first-child{grid-column:auto}
}

/* FGS credit (Website Building Assets/components/fgs-credit). It takes the
   footer's own font, size and colour; only the # cross-bars are orange. */
.fgs-credit{display:inline-flex;align-items:baseline;gap:.12em;color:inherit;text-decoration:none;white-space:nowrap}
.fgs-credit__logo{height:1.05em;width:auto;flex:none;align-self:center}
.fgs-credit:hover span,.fgs-credit:focus-visible span{text-decoration:underline;text-underline-offset:3px}

/* --- Hero ------------------------------------------------------------
   The h1 is now the shop's real headline from WordPress, set as the
   eyebrow. "Surface Authority" stays as the visual lockup, aria-hidden.
   The lockup was md:text-[10rem]: at 160px "AUTHORITY" runs about
   1,290px, so every width from 768 to ~1,340px cut it off. It now sizes
   from its container (cqw) and only reaches 10rem when there is room. */
.uf-eyebrow{margin:0;font:500 .75rem/1.5 'Inter',sans-serif;letter-spacing:.35em;
  text-transform:uppercase;color:#c8cdd6}
.uf-hero-wrap{container-type:inline-size}
.hero-headline.uf-lockup{font-size:min(10rem,calc(100cqw / 8.6))}

/* The markup always asked for these two; neither existed in tailwind.css,
   so the eyebrow rule and the closing section's blue wash never showed. */
.bg-accent-blue{background-color:#2563eb}
.bg-accent-blue\/5{background-color:rgba(37,99,235,.05)}
/* The 1px scroll cue at the hero's foot lands on the phone link below 768px. */
@media (max-width:767px){.min-h-\[95vh\]>.bottom-12{display:none}}

.uf-actions{display:flex;flex-wrap:wrap;align-items:center;gap:1.5rem 2.25rem}
.uf-phone{font:500 .85rem/1.2 'JetBrains Mono',monospace;letter-spacing:.06em;color:#fff;
  text-decoration:underline;text-underline-offset:8px;text-decoration-color:rgba(255,255,255,.35)}
.uf-phone:hover{text-decoration-color:#4f92f7}

/* --- Sections --------------------------------------------------------
   py-40 (160px) on every section left the old homepage mostly empty
   space. These carry real content, so they sit tighter. */
.uf-section{padding:clamp(5rem,9vw,7.5rem) 0}
.uf-section-head{display:flex;justify-content:space-between;align-items:flex-end;
  gap:1rem;flex-wrap:wrap;margin-bottom:3rem}
.uf-kicker{display:inline-block;font:500 .7rem/1.4 'JetBrains Mono',monospace;
  letter-spacing:.3em;text-transform:uppercase;color:#8d95a3}
.uf-link{display:inline-block;font-size:.8rem;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;color:#4f92f7;text-decoration:none;
  border-bottom:1px solid currentColor;padding-bottom:.3rem}
.uf-link::after{content:" \2192"}
.uf-link:hover{color:#fff}

/* --- What we do: the WordPress service cards, with their prices ------ */
.uf-svc-grid{display:grid;grid-template-columns:1fr;gap:1px;
  background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.08)}
@media (min-width:640px){.uf-svc-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:1024px){.uf-svc-grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
.uf-svc{display:flex;flex-direction:column;background:#0a0a0a;color:#fff;text-decoration:none;overflow:hidden}
.uf-svc img{display:block;width:100%;height:auto;aspect-ratio:16/10;object-fit:cover;
  filter:saturate(.85);transition:transform .7s cubic-bezier(.2,.7,.2,1),filter .7s}
a.uf-svc:hover img{transform:scale(1.04);filter:saturate(1)}
.uf-svc-body{flex:1;display:flex;flex-direction:column;gap:.75rem;padding:1.75rem 1.75rem 2rem}
.uf-svc h3{margin:0;font:900 1.2rem/1.15 "Eurostile Extended","Arial Black",sans-serif;
  text-transform:uppercase;letter-spacing:-.01em}
.uf-svc p{margin:0;color:#a8afba;font-size:.95rem;line-height:1.6}
.uf-svc .uf-price{margin-top:auto;padding-top:1rem;color:#fff;
  font:900 2rem/1 "Eurostile Extended","Arial Black",sans-serif}
.uf-price span{display:block;margin-bottom:.55rem;font:500 .65rem/1 'JetBrains Mono',monospace;
  letter-spacing:.3em;text-transform:uppercase;color:#4f92f7}
.uf-price small{margin-left:.15em;font-size:.5em;color:#a8afba}
.uf-more{font-size:.75rem;font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:#4f92f7}
.uf-more::after{content:" \2192"}
a.uf-svc:hover .uf-more{color:#fff}
.uf-svc-cta{background:#1d4ed8}
.uf-svc-cta .uf-svc-body{justify-content:center;gap:1.25rem;padding:2.5rem 2rem}
.uf-svc-cta h3{font-size:1.45rem}
.uf-svc-cta p{color:#e3e9ff}
.uf-svc-cta .uf-phone{text-decoration-color:rgba(255,255,255,.5)}
.uf-svc-cta .uf-phone:hover{text-decoration-color:#fff}
@media (prefers-reduced-motion:reduce){.uf-svc img{transition:none}a.uf-svc:hover img{transform:none}}

/* --- Two-column blocks: about, FAQ ----------------------------------- */
.uf-split{display:grid;gap:3rem;align-items:center}
@media (min-width:1024px){.uf-split{grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:5rem}}
.uf-split-media{margin:0;overflow:hidden;border:1px solid rgba(255,255,255,.1)}
.uf-split-media img{display:block;width:100%;height:auto;aspect-ratio:16/10;object-fit:cover}
.uf-split-copy{display:flex;flex-direction:column;align-items:flex-start;gap:1.25rem}
.uf-split-copy h2,.uf-split-faq h2{margin:0}
.uf-chips{display:flex;flex-wrap:wrap;gap:.5rem;list-style:none;margin:.25rem 0 .5rem;padding:0}
.uf-chips li{padding:.6rem .8rem;border:1px solid rgba(255,255,255,.14);color:#c8cdd6;
  font:500 .68rem/1 'JetBrains Mono',monospace;letter-spacing:.12em;text-transform:uppercase}

.uf-split-faq{align-items:start}
.uf-split-faq>div:first-child{display:flex;flex-direction:column;align-items:flex-start;gap:1.25rem}
@media (min-width:1024px){
  .uf-split-faq{grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr)}
  .uf-split-faq>div:first-child{position:sticky;top:120px}
}
.uf-faq details{border-top:1px solid rgba(255,255,255,.1)}
.uf-faq details:last-child{border-bottom:1px solid rgba(255,255,255,.1)}
.uf-faq summary{position:relative;cursor:pointer;list-style:none;padding:1.4rem 2.75rem 1.4rem 0;
  color:#fff;font-size:1.05rem;font-weight:600;line-height:1.45}
.uf-faq summary::-webkit-details-marker{display:none}
.uf-faq summary::after{content:"+";position:absolute;right:.35rem;top:50%;transform:translateY(-50%);
  color:#4f92f7;font:300 1.6rem/1 'Inter',sans-serif;transition:transform .3s}
.uf-faq details[open] summary::after{transform:translateY(-50%) rotate(45deg)}
.uf-faq details p{max-width:62ch;margin:0 0 1.5rem;color:#a8afba;line-height:1.7}

/* --- Closing call to action ------------------------------------------ */
.uf-close{padding:clamp(6rem,12vw,10rem) 0}
.uf-close-title{margin:0 0 2.5rem;font-size:clamp(2.25rem,8.5vw,7.5rem);font-style:italic}
.uf-close-title .text-outline{display:block}
.uf-close-addr{margin-top:3rem;font-size:.85rem;color:#8d95a3}
.uf-close-addr a{color:inherit;text-underline-offset:4px}
.uf-close-addr a:hover{color:#fff}

/* --- What each step involves -----------------------------------------
   The WordPress site gave each step its own 50-word page; those URLs now
   301 to the service they belong to (see _redirects), and their copy
   lives here on that page. */
.uf-gloss{display:grid;grid-template-columns:1fr;column-gap:3rem}
@media (min-width:768px){.uf-gloss{grid-template-columns:repeat(2,minmax(0,1fr))}}
.uf-gloss>div{border-top:1px solid rgba(255,255,255,.1);padding:1.5rem 0}
.uf-gloss h3{margin:0 0 .5rem;color:#fff;font-size:1rem;font-weight:700;letter-spacing:.01em}
.uf-gloss p{margin:0;max-width:60ch;color:#a8afba;font-size:.95rem;line-height:1.7}

/* =====================================================================
   2026-10 design pass
   ===================================================================== */

/* One display face for titles. Section titles were Inter Black italic,
   faked from a 600 weight, while every service page already used
   Eurostile. Italic stays for brand statements; titles stand upright. */
.uf-h2{margin:0;font:900 clamp(1.45rem,2.5vw,2.15rem)/1.08 "Eurostile Extended","Arial Black",sans-serif;
  text-transform:uppercase;letter-spacing:-.01em}
.uf-statement{margin:.9rem 0 0;font:900 clamp(1.9rem,4.4vw,3.85rem)/.98 "Eurostile Extended","Arial Black",sans-serif;
  font-style:italic;text-transform:uppercase;letter-spacing:-.025em}

/* --- Paint correction, in section --------------------------------------
   The page's signature: a cross-section of the paint. Left, glaze sitting
   in a scratch. Right, the clear coat polished down to the scratch's
   floor. Depths are exaggerated to be visible; the order of the layers
   and the 40 to 50 micron clear coat are real. */
.uf-truth-head{display:grid;gap:1.75rem;align-items:end;margin-bottom:3rem}
@media (min-width:1024px){.uf-truth-head{grid-template-columns:minmax(0,1.2fr) minmax(0,.8fr);gap:4rem}}
.uf-truth-head .uf-lede{margin:0}
.uf-xsec{display:grid;gap:1.5rem;margin:0}
@media (min-width:900px){.uf-xsec{grid-template-columns:repeat(2,minmax(0,1fr));gap:1.25rem 2rem}}
.uf-xsec-frame{padding:1.25rem 1.25rem .75rem;background:#08090b;border:1px solid rgba(255,255,255,.1)}
.uf-xsec-panel.is-good .uf-xsec-frame{border-color:rgba(79,146,247,.45)}
.uf-xsec svg{display:block;width:100%;height:auto}
.uf-xsec-label{margin:.9rem 0 0;max-width:46ch;color:#a8afba;font-size:.95rem;line-height:1.6}
.uf-xsec-label span{display:block;margin-bottom:.4rem;color:#c8cdd6;
  font:500 .7rem/1 'JetBrains Mono',monospace;letter-spacing:.3em;text-transform:uppercase}
.uf-xsec-panel.is-good .uf-xsec-label span{color:#4f92f7}
.uf-xsec-legend{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:.6rem 1.75rem;color:#8d95a3;
  font:500 .68rem/1.4 'JetBrains Mono',monospace;letter-spacing:.12em;text-transform:uppercase}
.uf-xsec-legend i{display:inline-block;width:.8rem;height:.8rem;margin-right:.55rem;vertical-align:-.12rem;
  border:1px solid rgba(255,255,255,.22)}
.uf-xsec-legend .sw-cc{background:rgba(214,228,255,.22)}
.uf-xsec-legend .sw-bc{background:#2563eb}
.uf-xsec-legend .sw-pr{background:#3a3f47}
.uf-xsec-legend .sw-mt{background:repeating-linear-gradient(-45deg,#15181d 0 3px,#23272e 3px 5px)}
/* Final state is the default. The script adds .is-pre only for a diagram
   still below the fold, then drops it once it is in view, so the layer
   that polishing removes fades away while you watch. */
.uf-xsec-cut{opacity:0;transform:translateY(-6px);transition:opacity 1.1s ease .35s,transform 1.1s ease .35s}
.uf-xsec-bracket{transition:opacity .5s ease 1.3s}
.uf-xsec.is-pre .uf-xsec-cut{opacity:1;transform:none;transition:none}
.uf-xsec.is-pre .uf-xsec-bracket{opacity:0;transition:none}

.uf-facts{display:grid;gap:1.75rem;margin:3rem 0 0;padding-top:2.25rem;border-top:1px solid rgba(255,255,255,.1)}
@media (min-width:768px){.uf-facts{grid-template-columns:repeat(3,minmax(0,1fr));gap:3rem}}
.uf-facts dt{margin-bottom:.5rem;color:#4f92f7;font-size:.75rem;letter-spacing:.12em;text-transform:uppercase}
.uf-facts dd{margin:0;max-width:40ch;color:#a8afba;font-size:.9rem;line-height:1.6}

/* --- Recent work: a mosaic, each photo named -------------------------
   Seven photos, one feature. Two columns hold down to a phone, so the
   set reads as a set; captions name what is in the frame. */
/* Recent work: rows that fill the width, every photo at its own shape. Each
   photo grows by its width-to-height ratio, so a row lines up at one height
   and nothing gets cropped. Phones let a row wrap. */
.uf-rows{display:grid;gap:.75rem}
.uf-row{display:flex;gap:.75rem}
.uf-row figure{position:relative;flex:var(--r) 1 0;margin:0;overflow:hidden;background:#0a0a0a}
.uf-row img{display:block;width:100%;height:auto;aspect-ratio:var(--r);transition:transform .7s cubic-bezier(.2,.7,.2,1)}
.uf-row figure:hover img{transform:scale(1.04)}
.uf-row figcaption{position:absolute;left:0;right:0;bottom:0;padding:2.25rem .9rem .75rem;
  background:linear-gradient(transparent,rgba(0,0,0,.78));color:#fff;
  font:500 .68rem/1.3 'JetBrains Mono',monospace;letter-spacing:.14em;text-transform:uppercase}
@media (min-width:900px){.uf-rows,.uf-row{gap:1rem}}
@media (max-width:639px){.uf-row{flex-wrap:wrap}.uf-row figure{flex:var(--r) 1 calc(var(--r) * 150px)}}
@media (prefers-reduced-motion:reduce){.uf-row img{transition:none}.uf-row figure:hover img{transform:none}}

/* The shop photo says where it is. */
.uf-split-media figcaption{padding:.8rem 1rem;border-top:1px solid rgba(255,255,255,.1);color:#8d95a3;
  font:500 .68rem/1.3 'JetBrains Mono',monospace;letter-spacing:.14em;text-transform:uppercase}
/* In-diagram labels read at desktop sizes only; the legend and captions carry it on phones. */
.uf-xsec text{fill:#c8cdd6;font:500 11px 'JetBrains Mono',monospace;letter-spacing:.18em}
.uf-xsec text.is-blue{fill:#4f92f7}
@media (max-width:599px){.uf-xsec text,.uf-xsec-note{display:none}}
.uf-xsec-label,.uf-facts dd,.uf-svc p{text-wrap:pretty}
/* Phones: shorter card photos, so six services don't run to six screens. */
@media (max-width:639px){.uf-svc img{aspect-ratio:2/1}}
