@charset "UTF-8";

/* ==========================================================================
   RhinoDecks

   Design direction: the product is invisible. What a customer buys is not the
   deck surface they can see, it is the dry room underneath. Everything here is
   built around that idea — the palette is Vancouver overcast and wet concrete,
   the one warm colour is reserved for the light inside the protected space in
   the cross-section drawing, and red is used only where action is required.

   Type: Archivo carries the display voice with its width axis pushed wide, so
   headlines read as stamped rather than typed. Public Sans sets text. IBM
   Plex Mono is a functional system for specifications (60 MIL, ICC-ES AC39),
   not decoration — it appears only where a real technical value does.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Fonts
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Archivo';
  src: url('../fonts/archivo-var-latin.woff2') format('woff2-variations');
  font-weight: 400 800;
  font-stretch: 62% 125%;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

@font-face {
  font-family: 'Public Sans';
  src: url('../fonts/public-sans-var-latin.woff2') format('woff2-variations');
  font-weight: 400 700;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

@font-face {
  font-family: 'IBM Plex Mono';
  src: url('../fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

/* --------------------------------------------------------------------------
   2. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Wet concrete and overcast. Deliberately cool and slightly green-shifted —
     a warm cream ground would read as a different trade entirely. */
  --ink: #111816;
  --slate: #1a2823;
  --slate-2: #2a3a34;
  --fog: #eef4f1;
  --fog-2: #dce7e2;
  --paper: #fffefa;
  /* --line is decorative only (dividers, card edges). Any border that IS the
     visual boundary of a control uses --line-strong, which clears the 3:1 that
     WCAG 2.2 SC 1.4.11 requires — on both the paper and fog grounds. */
  --line: #d2dcd8;
  --line-strong: #6d7e78;
  --muted: #52635d;

  /* Action only. Never decoration, never a background for large areas. */
  --red: #a73426;
  --red-dark: #80251b;

  /* The light in the protected room. Appears ONLY inside the cross-section. */
  --amber: #d99c3d;

  --focus: #0b7285;

  --font-display: 'Archivo', 'Arial Black', system-ui, sans-serif;
  /* Public Sans over Instrument Sans for body copy. Measured from the OS/2
     tables: Instrument Sans has x-height/upm 0.510 and a plain-stem lowercase
     l indistinguishable from a capital I; Public Sans has 0.517 and a TAILED l.
     It was commissioned for US government legibility. Beier & Oderkerk found
     older readers are more sensitive to legibility differences than younger
     ones, and this site is read by 45-70 year olds checking spec numbers. */
  --font-body: 'Public Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;

  --step--1: 0.8125rem;
  --step-0: 1rem;
  --step-1: 1.125rem;
  --step-2: 1.375rem;
  --step-3: 1.875rem;
  --step-4: 2.75rem;
  --step-5: 4.875rem;

  --gutter: clamp(1.25rem, 4vw, 3rem);
  --measure: 68ch;
  --radius: 3px;
  --radius-lg: 8px;

  --section-y: clamp(3.5rem, 7vw, 7rem);

  /* Header height. The logo lockup carries its own lettering and needs about
     48px to stay legible, which sets this. Five rules depended on a hardcoded
     64px before — header bar, mobile nav offset, hero height and anchor
     scroll-margin — and that is how they drift apart. */
  --header-h: 76px;
  --header-gap: 20px;

  --ease: cubic-bezier(0.2, 0.6, 0.25, 1);
}

@media (max-width: 900px) {
  :root {
    --step-2: 1.25rem;
    --step-3: 1.625rem;
    --step-4: 2.125rem;
    --step-5: 3.25rem;
  }
}

@media (max-width: 560px) {
  :root {
    --step-1: 1.0625rem;
    --step-2: 1.1875rem;
    --step-3: 1.45rem;
    --step-4: 1.875rem;
    --step-5: 2.625rem;
  }
}

/* --------------------------------------------------------------------------
   3. Reset and base
   -------------------------------------------------------------------------- */

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  overflow-x: clip;
}

body {
  /* The source site set no font-family on body, so 319 elements rendered in
     Times New Roman. Setting it here is the fix. */
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

/* The UA stylesheet's `[hidden] { display: none }` has the lowest possible
   specificity, so any author rule that sets `display` silently defeats it.
   `.btn` is `display: inline-flex`, which made the form stepper's hidden Back
   and Submit buttons render on every step. This has to win outright. */
[hidden] {
  display: none !important;
}

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

img {
  height: auto;
}

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

button {
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   Display typography

   Archivo carries a width axis from 62 to 125.

   The ramp runs the other way from size: the larger the type, the narrower it
   is allowed to go, and nothing at text size ever condenses.

     h1 / big figures  78px   wdth 92
     h2                44px   wdth 96
     .prose h2         30px   wdth 100
     h3 and smaller  <=22px   wdth 100   <- floor, never crossed

   An earlier build had this inverted: it expanded the display sizes to 120 and
   118 on the theory that width is the voice and a headline should read as
   stamped rather than typed. In practice that pushes a grotesque 20% past the
   width it was drawn at, and stretched letterforms read as blocky rather than
   confident — the counters go oval, the joins thicken, and the widest, heaviest
   object on the page ends up being the one carrying the least information.

   The floor at 100 stays exactly where it was, because the evidence behind it
   is about small text and signage read at distance, not about a 78px headline
   at arm's length. Nobody misreads a 78px word. So the citations below still
   govern h3, nav, buttons and body — none of which condense — while the
   display sizes are simply set at or near the width the typeface was drawn at:

     - Waller (2007), Heathrow signage study: character width was a more
       significant factor in legibility, condensed sans performed poorly.
     - Nielsen Norman Group: condensed text needed 11.2%% more time (p<0.01).
     - Oderkerk & Beier (2022), Ergonomics: with width the only variable,
       wider fonts gave better recognition and fewer misreadings.
     - DIN 1451 itself specifies its condensed cut only where space is short.

   Every foundry argument for condensed type is about copyfit, never about
   legibility. This site is read by 45-70 year olds checking specifications, so
   it never condenses text to save space. Emphasis comes from size and weight
   rather than from stretching the face.

   Tracking is optical, and it tracks width as well as size. Narrower
   letterforms have tighter counters already, so the display sizes carry less
   negative tracking now than they did at wdth 120 — pulling -0.035em through a
   92-width headline closes the joins up.
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 700;
  text-wrap: balance;
  /* Figures in headings should align and sit on the cap line. */
  font-variant-numeric: lining-nums;
  overflow-wrap: break-word;
}

h1 {
  font-size: var(--step-5);
  font-variation-settings: 'wdth' 92;
  font-weight: 760;
  line-height: 0.98;
  letter-spacing: -0.025em;
}

h2 {
  font-size: var(--step-4);
  font-variation-settings: 'wdth' 96;
  font-weight: 730;
  line-height: 1.05;
  letter-spacing: -0.020em;
}

h3 {
  font-size: var(--step-2);
  font-variation-settings: 'wdth' 100;
  line-height: 1.16;
  letter-spacing: -0.015em;
}

h4 {
  font-size: var(--step-1);
  font-variation-settings: 'wdth' 100;
  line-height: 1.35;
  letter-spacing: 0;
}

/* The fluid scale drops h1 to about 36px on a phone, where display tracking
   closes the counters up. Relax it as the type gets smaller. */
/* The fluid scale drops h1 to about 38px on a phone. Display tracking that
   reads as confident at 78px closes the counters up at that size, so it is
   relaxed here rather than applied uniformly. Tracking is optical: it belongs
   to a size, not to a heading level. */
@media (max-width: 700px) {
  h1 {
    line-height: 1.02;
    letter-spacing: -0.022em;
  }

  h2 {
    line-height: 1.08;
    letter-spacing: -0.018em;
  }
}

p {
  text-wrap: pretty;
}

a {
  color: inherit;
}

:where(a):focus-visible,
:where(button):focus-visible,
:where(input):focus-visible,
:where(select):focus-visible,
:where(textarea):focus-visible,
:where(summary):focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 2px;
}

::selection {
  background: var(--ink);
  color: var(--paper);
}

.skip-link {
  position: absolute;
  left: var(--gutter);
  top: 0;
  transform: translateY(-120%);
  z-index: 200;
  background: var(--ink);
  color: var(--paper);
  padding: 0.75rem 1.25rem;
  font-weight: 600;
  transition: transform 0.15s var(--ease);
}

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

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

/* --------------------------------------------------------------------------
   4. Layout primitives
   -------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap--narrow {
  max-width: 820px;
}

.section {
  padding-block: var(--section-y);
}

.section--tight {
  padding-block: clamp(2.5rem, 5vw, 4rem);
}

.section--dark {
  background: var(--slate);
  color: var(--fog);
}

.section--fog {
  background:
    linear-gradient(180deg, rgba(255, 254, 250, 0.38), rgba(255, 254, 250, 0)),
    var(--fog);
}

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

.prose {
  max-width: var(--measure);
  font-size: var(--step-1);
}

/* Headings inside running text are subordinate to the page heading. At the
   default h2 scale they compete with the h1 for the same job. */
.prose h2 {
  font-size: var(--step-3);
  font-variation-settings: 'wdth' 100;
}

.prose h3 {
  font-size: var(--step-1);
}

.prose > h2 + *,
.prose > h3 + * {
  margin-top: 0.6em;
}

.prose > * + :is(h2, h3) {
  margin-top: 1.9em;
}

.lede {
  font-size: var(--step-2);
  line-height: 1.45;
  max-width: 60ch;
}

/* --------------------------------------------------------------------------
   5. Spec label — the structural device
   Small monospace tags carrying real technical values. They sit on a hairline
   datum rule the way a callout sits on a drawing. Used only where the value is
   an actual specification.
   -------------------------------------------------------------------------- */

.spec {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.section--dark .spec {
  color: #a9bcc0;
}

.datum {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding-bottom: 0.75rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
  border-bottom: 1px solid var(--line);
}

.section--dark .datum {
  border-bottom-color: #3d5157;
}

.datum::after {
  content: '';
  flex: 1;
}

.datum__title {
  margin-top: 0.35em;
}

/* --------------------------------------------------------------------------
   6. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.9rem 1.6rem;
  min-height: 48px;
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'wdth' 100;
  font-size: var(--step-0);
  letter-spacing: 0.005em;
  text-decoration: none;
  border: 2px solid transparent;
  border-radius: var(--radius);
  max-width: 100%;
  box-shadow: none;
  transition: background-color 0.16s var(--ease), color 0.16s var(--ease),
    border-color 0.16s var(--ease), transform 0.16s var(--ease),
    box-shadow 0.16s var(--ease);
}

.btn--primary {
  background: var(--red);
  color: #fff;
  border-color: var(--red);
  box-shadow: 0 10px 22px rgba(167, 52, 38, 0.22);
}

.btn--primary:hover {
  background: var(--red-dark);
  border-color: var(--red-dark);
  box-shadow: 0 12px 28px rgba(128, 37, 27, 0.26);
}

.btn--dark {
  background: var(--ink);
  color: #fff;
  border-color: var(--ink);
}

.btn--dark:hover {
  background: var(--slate-2);
  border-color: var(--slate-2);
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--line-strong);
}

.btn--ghost:hover {
  border-color: var(--ink);
  background: var(--paper);
}

.section--dark .btn--ghost {
  color: var(--fog);
  border-color: #56696e;
}

.section--dark .btn--ghost:hover {
  border-color: var(--fog);
  background: rgba(255, 255, 255, 0.07);
}

.btn:active {
  transform: translateY(1px);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}

/* Text link with a rule that grows on hover. */
.tlink {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 2px solid var(--red);
  padding-bottom: 2px;
  transition: color 0.16s var(--ease);
}

.tlink:hover {
  color: var(--red);
}

.section--dark .tlink {
  color: var(--fog);
}

.section--dark .tlink:hover {
  color: #fff;
}

/* --------------------------------------------------------------------------
   7. Header
   The source header was 180px tall with a 180px logo — 21% of an iPhone
   viewport. This one is 76px — sized by the logo lockup, and still well under half of it.
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 90;
  background: rgba(17, 24, 22, 0.92);
  color: var(--fog);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: #fff;
  flex-shrink: 0;
}

/* The lockup is a raster badge with its own lettering, so it is sized by
   height and lets width follow the artwork. Height is the legibility
   constraint; 48px is the floor at which DECKS still reads.

   At the top of the page it runs large and overhangs BELOW the bar, then
   shrinks into it on scroll. The negative bottom margin is what makes that
   safe: it cancels the extra height, so the flex line stays 48px tall in both
   states and in every frame between them. The bar therefore never changes
   height, nothing around it reflows, and CLS stays at zero. Growing the header
   itself would reflow the entire page on every scroll.

   The badge carries its own dark plate, which is why the overhang reads
   whether it lands on the dark hero or on a page that opens light. */
.brand__logo {
  display: block;
  height: var(--logo-h, 108px);
  width: auto;
  flex-shrink: 0;
  margin-bottom: calc(48px - var(--logo-h, 108px));
  transition: height 0.28s var(--ease), margin-bottom 0.28s var(--ease);
}

.site-header[data-compact='true'] .brand__logo {
  --logo-h: 48px;
}

@media (max-width: 720px) {
  /* A 108px lockup eats too much of a phone's first screen. */
  .brand__logo {
    --logo-h: 84px;
  }
}

/* The footer lockup has no scroll state to respond to, so it does not scale. */
.brand--footer .brand__logo {
  --logo-h: 56px;
  margin-bottom: 0;
  transition: none;
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 1.75rem);
}

.nav__link {
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 500;
  color: #d7e2df;
  padding: 0.4rem 0;
  border-bottom: 2px solid transparent;
  transition: color 0.16s var(--ease), border-color 0.16s var(--ease);
}

.nav__link:hover {
  color: #fff;
}

.nav__link[aria-current='page'] {
  color: #fff;
  border-bottom-color: #d4573f;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.header-phone {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
}

.header-phone:hover {
  text-decoration: underline;
}

.header-actions .btn {
  padding: 0.55rem 1.1rem;
  min-height: 40px;
  font-size: 0.9375rem;
}

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid #3f5257;
  border-radius: var(--radius);
  color: #fff;
  padding: 0.5rem 0.7rem;
  min-height: 44px;
  min-width: 44px;
  align-items: center;
  justify-content: center;
}

@media (max-width: 900px) {
  .nav-toggle {
    display: inline-flex;
  }

  /* Full height rather than a dropdown. A panel that stops part-way leaves page
     content bleeding through below its edge, and there is no room for the
     contact actions the header hides at this width. */
  .nav {
    position: fixed;
    inset: var(--header-h) 0 0 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--ink);
    border-top: 1px solid #293a34;
    padding: 0.5rem var(--gutter) calc(1.25rem + env(safe-area-inset-bottom));
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.18s var(--ease), transform 0.18s var(--ease),
      visibility 0.18s;
  }

  /* Contact actions live at the foot of the open menu, because the header's
     phone link and estimate button are both hidden at this width. */
  .nav__cta {
    margin-top: auto;
    padding-top: 1.5rem;
    display: grid;
    gap: 0.6rem;
  }

  .nav__cta .btn {
    width: 100%;
  }

  .nav__cta a[href^='tel:'] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 48px;
    font-family: var(--font-mono);
    font-size: 0.9375rem;
    color: #fff;
    text-decoration: none;
    border: 1px solid #4a5d63;
    border-radius: var(--radius);
  }

  .nav[data-open='true'] {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }

  .nav__link {
    padding: 0.85rem 0;
    border-bottom: 1px solid #26343a;
    font-size: 1.05rem;
  }

  .nav__link[aria-current='page'] {
    border-bottom-color: var(--red);
  }

  .header-phone {
    display: none;
  }
}

@media (max-width: 560px) {
  .header-actions .btn {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   8. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  background: var(--ink);
  color: #fff;
  isolation: isolate;
  overflow: hidden;
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.hero__media picture,
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      96deg,
      rgba(17, 24, 22, 0.9) 0%,
      rgba(17, 24, 22, 0.78) 43%,
      rgba(17, 24, 22, 0.38) 72%,
      rgba(17, 24, 22, 0.16) 100%
    ),
    linear-gradient(
      180deg,
      rgba(17, 24, 22, 0.34) 0%,
      rgba(17, 24, 22, 0.08) 45%,
      rgba(17, 24, 22, 0.58) 100%
    );
}

@media (max-width: 880px) {
  /* On a tall narrow viewport the text runs the full width, so a purely
     horizontal scrim leaves the lower half of the copy over bare photograph.
     Add a vertical pass underneath it. */
  .hero__media::after {
    background:
      linear-gradient(
        180deg,
        rgba(17, 24, 22, 0.82) 0%,
        rgba(17, 24, 22, 0.88) 52%,
        rgba(17, 24, 22, 0.95) 100%
      );
  }
}

/* The hero sits on a photograph, so its ghost button needs the dark-surface
   treatment. Without this it renders as dark text over whatever the image
   happens to show, which is unreadable on the brighter shots. */
.hero .btn--ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.55);
  background: rgba(17, 24, 22, 0.3);
}

.hero .btn--ghost:hover {
  border-color: #fff;
  background: rgba(17, 24, 22, 0.58);
}

.hero__inner {
  min-height: min(780px, calc(100svh - var(--header-h)));
  padding-block: clamp(4.5rem, 8vw, 8rem);
  max-width: 1200px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.hero__inner > :not(.hero__proof) {
  max-width: 44rem;
}

.hero__eyebrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.8rem;
  color: #cbe2de;
  margin-bottom: 1.25rem;
}

.hero__eyebrow::after {
  content: '';
  height: 1px;
  flex: 1;
  max-width: 6rem;
  background: #56696e;
}

.hero h1 {
  margin-bottom: 1.25rem;
  max-width: 10.8ch;
}

.hero h1 em {
  font-style: normal;
  color: #fff;
  box-shadow: inset 0 -0.11em 0 rgba(167, 52, 38, 0.95);
}

.hero__sub {
  font-size: var(--step-2);
  line-height: 1.5;
  color: #dde5e6;
  max-width: 44ch;
  margin-bottom: 2rem;
}

.hero__proof {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  width: min(100%, 44rem);
  margin-top: 2.5rem;
  padding: 1px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, 0.18);
  overflow: hidden;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.hero__proof div {
  padding: 1rem 1.1rem;
  background: rgba(17, 24, 22, 0.38);
}

.hero__proof dt {
  color: #a9bcc0;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.hero__proof dd {
  margin: 0.15rem 0 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'wdth' 100;
  font-size: var(--step-2);
}

/*
   A stat whose value is an action rather than a figure. Warranty coverage
   depends on the assembly, so the site does not print a duration — it links to
   a person. Set a step smaller than the figures beside it and underlined, so it
   reads as something to click rather than as a number, and so "Speak to a
   specialist" does not wrap to three lines in a third-width cell.
*/
.hero__proof dd .ask {
  font-size: var(--step-0);
  line-height: 1.25;
  display: inline-block;
  color: #fff;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.45);
  text-underline-offset: 3px;
}

.hero__proof dd .ask:hover {
  text-decoration-color: #fff;
}

@media (max-width: 700px) {
  .hero__inner {
    min-height: auto;
    padding-block: 3.25rem 3.75rem;
  }

  .hero h1 {
    max-width: 9.8ch;
  }

  .hero__eyebrow::after {
    display: none;
  }

  .hero__proof {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   Split hero (>=1000px)

   Below this width the photograph sits behind the copy, scrimmed, as it always
   has. From 1000px it becomes its own column instead.

   This is a resolution decision as much as a layout one. The hero photograph
   is 1920x1277 and that is the largest version that exists — the source CDN
   returns the identical file whatever size you ask it for. A full-bleed hero
   needs viewport x DPR device pixels, so on a 1440p screen it was being
   upscaled 1.33x and on a 4K screen 2x, which is what read as blurry. At 46vw
   the same file covers 1440p, 4K at either common scaling, and a 2x laptop
   panel without upscaling at all:

     4K   @ dpr 1.5 -> 2560 css -> 46vw = 1178 -> 1766 device px   (fits 1920)
     4K   @ dpr 2   -> 1920 css -> 46vw =  883 -> 1766 device px   (fits 1920)
     1440p @ dpr 1  -> 2560 css -> 46vw = 1178 -> 1178 device px   (fits)
     laptop @ dpr 2 -> 1512 css -> 46vw =  696 -> 1391 device px   (fits)

   Anything at or above 5K still upscales; that needs a bigger original, not a
   layout change. Keep the 46vw in the `sizes` attribute in pages/home.php in
   step with the 46fr column below — if they drift, the browser picks the wrong
   variant and the blur comes back.
   -------------------------------------------------------------------------- */

@media (min-width: 1000px) {
  .hero {
    display: grid;
    grid-template-columns: minmax(0, 54fr) minmax(0, 46fr);
  }

  /* Out of the background layer and into a real grid cell. Leaving the
     negative z-index here would paint the photograph behind --ink. */
  .hero__media {
    position: relative;
    inset: auto;
    z-index: auto;
    grid-area: 1 / 2;
  }

  /* The copy sits on solid --ink now, so the scrim is no longer doing
     legibility work — only blending the photograph's left edge into the panel
     so the two columns meet without a seam. */
  .hero__media::after {
    background: linear-gradient(
      90deg,
      rgba(17, 24, 22, 0.97) 0%,
      rgba(17, 24, 22, 0.55) 9%,
      rgba(17, 24, 22, 0.14) 26%,
      rgba(17, 24, 22, 0) 44%
    );
  }

  /* Keeps the penthouse structure in frame as the column narrows, rather than
     centring on the empty valley to its left. */
  .hero__media img {
    object-position: 58% center;
  }

  .hero__inner {
    grid-area: 1 / 1;
    max-width: none;
    margin-inline: 0;
    min-height: min(720px, calc(100svh - var(--header-h)));
    /* Aligns the copy with the 1200px content column used by every other
       section, instead of with the edge of its own grid cell. */
    padding-left: max(var(--gutter), calc((100vw - 1200px) / 2));
    padding-right: clamp(2rem, 3.5vw, 3.5rem);
  }

  .hero__inner > :not(.hero__proof) {
    max-width: 34rem;
  }

  .hero__proof {
    width: 100%;
  }
}

/* --------------------------------------------------------------------------
   Page heroes
   -------------------------------------------------------------------------- */

.page-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--ink);
  color: #fff;
  padding-block: clamp(4rem, 7vw, 7rem);
}

.page-hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.page-hero__media picture,
.page-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.page-hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      96deg,
      rgba(17, 24, 22, 0.92) 0%,
      rgba(17, 24, 22, 0.84) 46%,
      rgba(17, 24, 22, 0.52) 78%,
      rgba(17, 24, 22, 0.38) 100%
    ),
    linear-gradient(180deg, rgba(17, 24, 22, 0.22), rgba(17, 24, 22, 0.72));
}

.page-hero h1 {
  max-width: 12ch;
  margin: 0.75rem 0 1.25rem;
}

.page-hero__eyebrow {
  color: #cbe2de;
}

.page-hero__lede {
  color: #e0ebe8;
  max-width: 58ch;
}

.page-hero__proof {
  margin-top: 2.75rem;
}

.page-hero__note {
  max-width: 62ch;
  margin-top: 1rem;
  color: #9eb4ae;
}

@media (max-width: 700px) {
  .page-hero {
    padding-block: 3rem;
  }
}

/* --------------------------------------------------------------------------
   9. Cross-section — the signature element
   An annotated drawing of the assembly. This is the trade's own artifact and
   it is the one place the page spends its boldness, so everything around it
   stays quiet. Amber appears here and nowhere else on the site.
   -------------------------------------------------------------------------- */

.detail {
  background: var(--slate);
  color: var(--fog);
  overflow: hidden;
}

.detail__grid {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

@media (min-width: 900px) {
  .detail__grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  }
}

.detail__figure {
  margin: 0;
}

.detail__svg {
  width: 100%;
  height: auto;
  overflow: visible;
}

.detail__caption {
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  color: #a9bcc0;
}

/* The drawing is visible by default and is hidden only once JavaScript has
   confirmed it can animate it back in. Hiding it unconditionally made the
   site's signature element vanish entirely with JavaScript disabled, which is
   the opposite of progressive enhancement. site.js sets data-js; it does not
   set it under prefers-reduced-motion, so the drawing simply stays visible. */
.detail[data-js='true'] .detail__layer,
.detail[data-js='true'] .detail__callout,
.detail[data-js='true'] .detail__rain {
  opacity: 0;
}

.detail[data-js='true'][data-shown='true'] .detail__layer {
  animation: layer-in 0.5s var(--ease) forwards;
}

.detail[data-js='true'][data-shown='true'] .detail__callout {
  animation: layer-in 0.4s var(--ease) forwards;
}

.detail[data-js='true'][data-shown='true'] .detail__rain {
  animation: rain-in 0.6s var(--ease) forwards;
}

/* Delays are set by explicit step classes rather than :nth-child, because the
   animated groups are siblings of <defs>, <title> and <desc> inside the SVG and
   positional selectors would index those too. */
.detail[data-js='true'][data-shown='true'] .step-1 { animation-delay: 0.05s; }
.detail[data-js='true'][data-shown='true'] .step-2 { animation-delay: 0.18s; }
.detail[data-js='true'][data-shown='true'] .step-3 { animation-delay: 0.31s; }
.detail[data-js='true'][data-shown='true'] .step-4 { animation-delay: 0.44s; }
.detail[data-js='true'][data-shown='true'] .step-5 { animation-delay: 0.57s; }
.detail[data-js='true'][data-shown='true'] .step-6 { animation-delay: 0.70s; }
.detail[data-js='true'][data-shown='true'] .step-7 { animation-delay: 0.92s; }
.detail[data-js='true'][data-shown='true'] .step-8 { animation-delay: 1.02s; }
.detail[data-js='true'][data-shown='true'] .step-9 { animation-delay: 1.12s; }
.detail[data-js='true'][data-shown='true'] .step-10 { animation-delay: 1.22s; }
.detail[data-js='true'][data-shown='true'] .step-11 { animation-delay: 1.32s; }

@keyframes layer-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes rain-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.detail__svg text {
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.08em;
  fill: #a9bcc0;
}

.detail__svg .is-key {
  fill: var(--amber);
}

.detail__list {
  list-style: none;
  padding: 0;
  margin-top: 2rem;
  display: grid;
  gap: 1px;
  background: #3d5157;
  border: 1px solid #3d5157;
  border-radius: var(--radius);
  overflow: hidden;
}

.detail__list li {
  background: var(--slate);
  padding: 0.9rem 1.1rem;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
}

.detail__list b {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #a9bcc0;
}

.detail__list span {
  text-align: right;
  font-size: 0.95rem;
}

.detail__list span .ask {
  color: #fff;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.45);
  text-underline-offset: 3px;
}

.detail__list span .ask:hover {
  text-decoration-color: #fff;
}

/* --------------------------------------------------------------------------
   10. Cards and grids
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  gap: clamp(1rem, 2.2vw, 1.75rem);
}

.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }

.card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  transition: border-color 0.18s var(--ease), transform 0.18s var(--ease),
    box-shadow 0.18s var(--ease);
}

.card__icon {
  width: 30px;
  height: 30px;
  color: var(--red);
  margin-bottom: 0.35rem;
}

.card p {
  color: var(--muted);
  font-size: 0.975rem;
}

/* Whole-card link: the anchor covers the card without nesting interactive
   elements, so the accessible name stays the heading text. */
.card--link {
  position: relative;
}

.card--link:hover {
  border-color: var(--ink);
  transform: translateY(-3px);
}

.card--link:has(a:focus-visible) {
  border-color: var(--ink);
}

.card__link::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.card__link {
  text-decoration: none;
}

.card__more {
  margin-top: auto;
  padding-top: 0.75rem;
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--red);
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.card--service .card__media {
  margin: calc(-1 * clamp(1.25rem, 2.5vw, 1.75rem));
  margin-bottom: 1rem;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  overflow: hidden;
}

.card--service .card__media img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  transition: transform 0.4s var(--ease);
}

.card--link:hover .card__media img {
  transform: scale(1.04);
}

/* --------------------------------------------------------------------------
   11. Process — the one place numbering is used, because it is a real sequence
   -------------------------------------------------------------------------- */

.steps {
  list-style: none;
  padding: 0;
  counter-reset: step;
  display: grid;
  gap: 0;
}

.steps li {
  counter-increment: step;
  position: relative;
  padding: 1.5rem 0 1.5rem 4.25rem;
  border-top: 1px solid var(--line);
}

.steps li:last-child {
  border-bottom: 1px solid var(--line);
}

.steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 1.5rem;
  font-family: var(--font-mono);
  font-size: var(--step-1);
  font-weight: 500;
  color: var(--red);
  letter-spacing: 0.05em;
}

.steps h3 {
  margin-bottom: 0.35rem;
}

.steps p {
  color: var(--muted);
  max-width: 62ch;
}

.steps .spec {
  display: block;
  margin-top: 0.5rem;
}

@media (min-width: 800px) {
  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(2rem, 4vw, 3.5rem);
  }

  .steps li:nth-last-child(2) {
    border-bottom: 1px solid var(--line);
  }
}

/* --------------------------------------------------------------------------
   12. Gallery
   -------------------------------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 2rem;
}

.filter {
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: 100px;
  padding: 0.5rem 1rem;
  min-height: 40px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--muted);
  transition: all 0.16s var(--ease);
}

.filter:hover {
  border-color: var(--ink);
  color: var(--ink);
}

.filter[aria-pressed='true'] {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
  list-style: none;
  padding: 0;
}

.gallery li[hidden] {
  display: none;
}

.shot {
  position: relative;
  width: 100%;
  padding: 0;
  border: 0;
  background: var(--fog-2);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: block;
  text-align: left;
}

.shot img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform 0.45s var(--ease);
}

.shot:hover img {
  transform: scale(1.045);
}

.shot__meta {
  position: absolute;
  inset: auto 0 0 0;
  /* The caption sits on the photograph, so it needs the same optical margin a
     caption would get on a page. At 0.9rem the two lines crowded the bottom
     edge of the tile and read as clipped rather than placed. */
  padding: 3rem 1.15rem 1.25rem;
  background: linear-gradient(transparent, rgba(17, 24, 22, 0.9));
  color: #fff;
}

.shot__meta strong {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'wdth' 100;
  font-size: 1.0625rem;
  line-height: 1.2;
}

.shot__meta span {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #cdd8da;
}

.gallery__empty {
  padding: 3rem 0;
  color: var(--muted);
}

/* Lightbox */
.lightbox {
  border: 0;
  padding: 0;
  background: transparent;
  max-width: min(96vw, 1400px);
  max-height: 96vh;
  overflow: visible;
}

.lightbox::backdrop {
  background: rgba(10, 15, 17, 0.93);
}

.lightbox__figure {
  margin: 0;
  display: grid;
  gap: 0.75rem;
}

.lightbox img {
  max-width: 100%;
  max-height: 82vh;
  width: auto;
  margin-inline: auto;
  border-radius: var(--radius);
}

.lightbox figcaption {
  color: #dde5e6;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  font-size: 0.9375rem;
}

.lightbox figcaption span {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #9fb2b6;
}

.lightbox__bar {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.lightbox__btn {
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.25);
  color: #fff;
  border-radius: var(--radius);
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.lightbox__btn:hover {
  background: rgba(255, 255, 255, 0.2);
}


/* --------------------------------------------------------------------------
   14. FAQ
   Native details/summary so it opens and closes with JavaScript disabled.
   -------------------------------------------------------------------------- */

.faq-group + .faq-group {
  margin-top: clamp(2rem, 4vw, 3rem);
}

.faq-list {
  border-top: 1px solid var(--line);
}

.section--dark .faq-list {
  border-top-color: #3d5157;
}

.qa {
  border-bottom: 1px solid var(--line);
}

.section--dark .qa {
  border-bottom-color: #3d5157;
}

.qa summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.15rem 0;
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'wdth' 100;
  font-size: var(--step-1);
  line-height: 1.35;
  list-style: none;
}

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

.qa summary::after {
  content: '';
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  margin-top: 0.4em;
  border-right: 2px solid var(--red);
  border-bottom: 2px solid var(--red);
  transform: rotate(45deg);
  transition: transform 0.2s var(--ease);
}

.qa[open] summary::after {
  transform: rotate(-135deg);
}

.qa__body {
  padding-bottom: 1.35rem;
  max-width: var(--measure);
  color: var(--muted);
}

.section--dark .qa__body {
  color: #c2d0d3;
}

/* --------------------------------------------------------------------------
   15. Service areas
   -------------------------------------------------------------------------- */

/* Each cell draws its own hairline via box-shadow rather than the container
   painting a background that shows through a 1px gap. The gap trick fills any
   grid area with no item in it — with twelve cities in a five-column grid that
   left three solid grey blocks in the last row. This way an empty area is just
   empty, whatever the item count happens to be. */
.areas {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr));
  gap: 1px;
  background: var(--paper);
  border-radius: var(--radius);
}

.areas li {
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--line);
  padding: 1rem 1.1rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 500;
}

.areas li::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--red);
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   16. Split section (image beside text)
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

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

  .split--reverse > :first-child {
    order: 2;
  }
}

.split img {
  border-radius: var(--radius-lg);
  width: 100%;
}

.checklist {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.65rem;
  margin-top: 1.5rem;
}

.checklist li {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  line-height: 1.5;
}

.checklist li::before {
  content: '';
  flex-shrink: 0;
  width: 1.1em;
  height: 1.1em;
  margin-top: 0.25em;
  background: var(--red);
  /* A check mark drawn with a clip path rather than an icon font. */
  clip-path: polygon(
    14% 47%, 0 61%, 39% 100%, 100% 22%, 85% 8%, 38% 70%
  );
}

.section--dark .checklist li::before {
  background: var(--amber);
}

/* --------------------------------------------------------------------------
   17. Quote form
   -------------------------------------------------------------------------- */

.form {
  display: grid;
  gap: 1.5rem;
}

.field {
  display: grid;
  gap: 0.4rem;
}

.field > label,
.fieldset > legend {
  font-weight: 600;
  font-size: 0.9375rem;
}

.field__hint {
  font-size: 0.875rem;
  color: var(--muted);
}

.field input[type='text'],
.field input[type='email'],
.field input[type='tel'],
.field select,
.field textarea {
  width: 100%;
  padding: 0.8rem 0.9rem;
  min-height: 48px;
  background: var(--paper);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  transition: border-color 0.16s var(--ease), box-shadow 0.16s var(--ease);
}

.field textarea {
  min-height: 8rem;
  resize: vertical;
}

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

.field [aria-invalid='true'] {
  border-color: var(--red);
  box-shadow: 0 0 0 1px var(--red);
}

.field__error {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--red-dark);
  display: flex;
  gap: 0.4rem;
  align-items: flex-start;
}

.fieldset {
  border: 0;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.6rem;
}

.choices {
  display: grid;
  gap: 0.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
}

.choice {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.85rem 1rem;
  min-height: 48px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 0.9375rem;
  transition: border-color 0.16s var(--ease), background-color 0.16s var(--ease);
}

.choice:hover {
  border-color: var(--muted);
}

.choice input {
  accent-color: var(--red);
  width: 1.15rem;
  height: 1.15rem;
  flex-shrink: 0;
  margin: 0;
}

.choice:has(input:checked) {
  border-color: var(--ink);
  background: var(--fog);
}

.choice:has(input:focus-visible) {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.consent {
  align-items: flex-start;
  line-height: 1.5;
}

.consent input {
  margin-top: 0.15rem;
}

/* The honeypot. Kept out of the accessibility tree and off screen rather than
   display:none, because some bots skip fields that are display:none. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form__alert {
  padding: 1rem 1.15rem;
  border-radius: var(--radius);
  border: 1px solid var(--red);
  background: #fdf2f1;
  color: var(--red-dark);
  font-weight: 500;
}

.form__step {
  border-top: 1px solid var(--line);
  padding-top: 1.5rem;
}

.form__step:first-of-type {
  border-top: 0;
  padding-top: 0;
}

.form__steptitle {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}

.form__steptitle h2 {
  font-size: var(--step-2);
}

.required {
  color: var(--red-dark);
}

/* --------------------------------------------------------------------------
   18. Sticky mobile action bar
   -------------------------------------------------------------------------- */

.actionbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 80;
  display: none;
  background: var(--ink);
  border-top: 1px solid #293a34;
  padding: 0.5rem;
  gap: 0.5rem;
  padding-bottom: max(0.5rem, env(safe-area-inset-bottom));
}

.actionbar a {
  flex: 1;
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  border-radius: var(--radius);
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.9375rem;
}

.actionbar__call {
  background: transparent;
  border: 1px solid #4a5d63;
  color: #fff;
}

.actionbar__quote {
  background: var(--red);
  color: #fff;
}

@media (max-width: 720px) {
  .actionbar {
    display: flex;
  }

  body {
    padding-bottom: 4.5rem;
  }
}

/* --------------------------------------------------------------------------
   19. CTA band and footer
   -------------------------------------------------------------------------- */

.cta {
  background: var(--slate);
  color: var(--fog);
}

.cta__inner {
  display: grid;
  gap: 2rem;
  align-items: center;
}

@media (min-width: 860px) {
  .cta__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 3rem;
  }
}

.cta h2 {
  color: #fff;
  margin-bottom: 0.75rem;
}

.cta p {
  color: #c2d0d3;
  max-width: 52ch;
}

.site-footer {
  background: var(--ink);
  color: #b9c9cc;
  padding-block: clamp(3rem, 6vw, 4.5rem) 2rem;
  font-size: 0.9375rem;
}

.site-footer a {
  color: #dde5e6;
  text-decoration: none;
}

.site-footer a:hover {
  color: #fff;
  text-decoration: underline;
}

.footer__grid {
  display: grid;
  gap: 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
}

.footer__grid h2,
.footer__areas h2 {
  font-size: 0.8125rem;
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #7e9297;
  margin-bottom: 1rem;
}

/* The band sets its own gap, so the column heading's bottom margin would
   double it. */
.footer__areas h2 {
  margin-bottom: 0;
}

.footer__list {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.6rem;
}

.footer__brand .brand {
  margin-bottom: 1rem;
}

.footer__brand p {
  max-width: 34ch;
}

/*
   Credibility marker. NN/g recommends these specifically for newer brands, and
   it reads as a credential only if it is set apart from the sentence around it
   — the same words mid-paragraph are just prose.
*/
.footer__credential {
  margin-top: 0.9rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #cbe2de;
}

.footer__credential::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--amber);
  flex: none;
}

/*
   The primary action in the footer. Sized up because the phone is what a
   reader who has scrolled this far is usually looking for; the email and
   address stay at body size beneath it.
*/
.site-footer .footer__phone {
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'wdth' 100;
  font-size: var(--step-2);
  line-height: 1.15;
  color: #fff;
}

/*
   Service areas. A band rather than a fifth column: twelve city names would
   make a very tall column and a very short line, and this reads as one answer
   to one question. Every link goes to the single /service-areas page.
*/
.footer__areas {
  margin-top: 2.75rem;
  padding-top: 1.75rem;
  border-top: 1px solid #263539;
  display: grid;
  gap: 0.75rem;
}

.footer__areas ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.4rem;
}

.footer__areas li {
  position: relative;
}

/* Separators are drawn rather than typed, so they are not read aloud between
   every city name. */
.footer__areas li + li::before {
  content: '';
  position: absolute;
  left: -0.75rem;
  top: 50%;
  translate: 0 -50%;
  width: 1px;
  height: 0.85em;
  background: #33474c;
}

address {
  font-style: normal;
  display: grid;
  gap: 0.6rem;
}

.footer__bottom {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid #263539;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  align-items: center;
  font-size: 0.875rem;
  color: #7e9297;
}

.footer__bottom nav {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   20. Utilities and motion preferences
   -------------------------------------------------------------------------- */

.stack-sm > * + * { margin-top: 0.75rem; }
.stack > * + *    { margin-top: 1.5rem; }
.stack-lg > * + * { margin-top: 2.5rem; }

.text-center { text-align: center; }
.mt-lg { margin-top: clamp(2rem, 4vw, 3rem); }

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  /* The drawing must still be fully visible without its build sequence. */
  .detail__layer,
  .detail__callout,
  .detail__rain {
    opacity: 1;
  }
}

@media print {
  .site-header,
  .actionbar,
  .cta,
  .filters {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   21. Sticky-header offset
   Any in-page target must clear the sticky header, or an anchor link
   lands with its heading hidden behind the bar.
   -------------------------------------------------------------------------- */

:target,
.section,
[id] {
  scroll-margin-top: calc(var(--header-h) + var(--header-gap));
}

/* The in-menu contact block is mobile-only; the header bar carries these
   actions at wider widths. */
@media (min-width: 901px) {
  .nav__cta {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   22. Cross-section at narrow widths
   The SVG scales down with its container, taking its callout text with it. At
   390px that text lands near 5.8 CSS pixels — legible only in the sense that a
   high-DPI screen renders it sharply. Below 760px the drawing keeps the
   assembly (which reads perfectly well as shapes) and hands its annotations to
   real HTML alongside.
   -------------------------------------------------------------------------- */

.detail__legend {
  display: none;
}

@media (max-width: 760px) {
  .detail__svg {
    overflow: hidden;
  }

  .detail__callout,
  .detail__svg text[style*='9px'] {
    display: none;
  }

  /* The one in-drawing label worth keeping: it is the payoff of the whole
     figure. Scaled so it survives the container's downscale. */
  .detail__svg .is-key {
    font-size: 26px;
  }

  .detail__legend {
    display: grid;
    gap: 0.55rem;
    list-style: none;
    padding: 1.25rem 0 0;
    margin: 0;
  }

  .detail__legend li {
    display: flex;
    align-items: baseline;
    gap: 0.7rem;
    font-size: 0.9375rem;
    color: #c2d0d3;
  }

  .detail__legend span {
    flex-shrink: 0;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--red);
    transform: translateY(-1px);
  }
}

/* --------------------------------------------------------------------------
   23. Contact aside
   Sticky only once the page is genuinely two columns. In the stacked layout
   the aside is the last thing on the page, so sticking it there does nothing
   useful and can leave it hanging mid-scroll.
   -------------------------------------------------------------------------- */

@media (min-width: 880px) {
  .contact__aside {
    position: sticky;
    top: 88px;
  }
}

/* ==========================================================================
   24. Elevation and surface
   The first pass was flat: every element sat on one plane with a hairline
   border. Real materials have weight. These shadows are tinted with the ink
   colour rather than neutral grey so they read as shade on a cool surface,
   not as a drop shadow bolted on.
   ========================================================================== */

:root {
  --shadow-sm: 0 1px 2px rgba(17, 24, 22, 0.05), 0 2px 6px rgba(17, 24, 22, 0.04);
  --shadow-md: 0 2px 4px rgba(17, 24, 22, 0.05), 0 10px 24px rgba(17, 24, 22, 0.07);
  --shadow-lg: 0 4px 10px rgba(17, 24, 22, 0.07), 0 22px 48px rgba(17, 24, 22, 0.12);
}

/* ==========================================================================
   25. Service tiles
   Replaces the bordered card. The photograph leads and carries a gradient
   foot so the label sits on it; the body copy sits on paper below. The
   flagship service spans two columns, because one of these eight is the
   product and the other seven are applications of it.
   ========================================================================== */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: clamp(1rem, 1.8vw, 1.5rem);
}

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

.tile {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid rgba(17, 24, 22, 0.08);
  box-shadow: var(--shadow-sm);
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.tile:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
}

.tile:has(a:focus-visible) {
  box-shadow: var(--shadow-lg);
}

.tile__media {
  position: relative;
  overflow: hidden;
  background: var(--fog-2);
}

.tile__media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}

.tile:hover .tile__media img {
  transform: scale(1.05);
}

/* Gradient foot so the eyebrow reads on any photograph. */
.tile__media::after {
  content: '';
  position: absolute;
  inset: 40% 0 0 0;
  background: linear-gradient(to bottom, transparent, rgba(17, 24, 22, 0.84));
  pointer-events: none;
}

.tile__eyebrow {
  position: absolute;
  left: 1.15rem;
  bottom: 0.9rem;
  z-index: 1;
  color: #e0ebe8;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.tile__body {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 1.35rem 1.45rem 1.55rem;
  flex: 1;
}

.tile__body h3,
.tile__body h2 {
  font-size: var(--step-2);
  line-height: 1.15;
}

.tile__body p {
  color: var(--muted);
  font-size: 0.9688rem;
  line-height: 1.55;
}

.tile__link {
  text-decoration: none;
}

.tile__link::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

/* A rule that draws itself under the title on hover — the only motion the
   tile has beyond the lift. */
.tile__more {
  margin-top: auto;
  padding-top: 0.9rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'wdth' 100;
  font-size: 0.9375rem;
  color: var(--red);
}

.tile__more span {
  display: inline-block;
  transition: transform 0.3s var(--ease);
}

.tile:hover .tile__more span {
  transform: translateX(4px);
}

/* The flagship: wider, photograph beside the copy rather than above it. */
@media (min-width: 1100px) {
  .tile--featured {
    grid-column: span 2;
    flex-direction: row;
  }

  .tile--featured .tile__media {
    flex: 0 0 46%;
  }

  .tile--featured .tile__media img {
    height: 100%;
    aspect-ratio: auto;
  }

  .tile--featured .tile__body {
    justify-content: center;
    padding: 2rem 2.25rem;
  }

  .tile--featured .tile__body h2,
  .tile--featured .tile__body h3 {
    font-size: var(--step-3);
  }

  .tile--featured .tile__body p {
    font-size: var(--step-1);
  }
}

.tile__flag {
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--red-dark);
  background: #fae9e5;
  border-radius: 100px;
  padding: 0.3rem 0.7rem;
  margin-bottom: 0.15rem;
}

/* In the featured tile the body is vertically centred, so pushing the link to
   the bottom with margin-top:auto leaves a hole between copy and link. */
@media (min-width: 1100px) {
  .tile--featured .tile__more {
    margin-top: 0.5rem;
  }
}

/* ==========================================================================
   26. Proof band
   A full-bleed photograph carrying the three Duradek figures. It exists to
   break the page's white / fog / white rhythm and to give eighteen good
   photographs somewhere to be large. Text sits on a scrim measured against
   the brightest image in the set, not judged by eye.
   ========================================================================== */

.band {
  position: relative;
  isolation: isolate;
  color: #fff;
  background: var(--ink);
  padding-block: clamp(4rem, 9vw, 8rem);
}

.band__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}

.band__media picture,
.band__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.band__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to right,
    rgba(17, 24, 22, 0.9) 0%,
    rgba(17, 24, 22, 0.84) 45%,
    rgba(17, 24, 22, 0.7) 100%
  );
}

.band h2 {
  max-width: 22ch;
  margin-bottom: 1rem;
}

.band p {
  color: #cfdadc;
  max-width: 54ch;
}

.figures {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid rgba(255, 255, 255, 0.18);
}

.figures dt {
  font-family: var(--font-display);
  font-weight: 760;
  font-variation-settings: 'wdth' 92;
  font-size: var(--step-5);
  line-height: 1;
  letter-spacing: -0.025em;
  color: #fff;
}

.figures dd {
  margin: 0.6rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #dce7e4;
  max-width: 22ch;
}

.band__note {
  margin-top: 2rem;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  color: #8fa3a7;
  max-width: 62ch;
  line-height: 1.6;
}

.band__note .ask {
  color: #dce7e4;
  text-decoration: underline;
  text-decoration-color: rgba(220, 231, 228, 0.5);
  text-underline-offset: 3px;
}

.band__note .ask:hover {
  text-decoration-color: #dce7e4;
}

/* ==========================================================================
   27. Testimonials
   Editorial pull-quotes rather than bordered boxes. The headline the customer
   gave carries the weight; the body sits quieter beneath it. A single oversized
   quote mark anchors the card without becoming decoration.
   ========================================================================== */

.quotes {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
}

.quote {
  position: relative;
  background: var(--paper);
  border: 1px solid rgba(17, 24, 22, 0.08);
  border-radius: var(--radius-lg);
  padding: clamp(1.75rem, 3vw, 2.25rem);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  overflow: hidden;
}

/* No decorative quote glyph here: the subset Archivo build has no U+201C, so
   it rendered as tofu. The quoted headline already signals this is a quote,
   and the mark was decoration rather than information. */

.quote > * {
  position: relative;
  z-index: 1;
}

.quote h3 {
  font-size: var(--step-2);
  line-height: 1.2;
  max-width: 18ch;
}

.quote blockquote {
  margin: 0;
  color: var(--muted);
  font-size: 0.9688rem;
  line-height: 1.6;
}

.quote figcaption {
  margin-top: auto;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  /* Grid, not wrapping flex: the author and the location wrapped differently
     in each card depending on name length, which read as misalignment. */
  display: grid;
  gap: 0.25rem;
}

.quote figcaption b {
  font-weight: 600;
}

/* ==========================================================================
   28. Process
   A connecting rule runs through the numbers so the sequence reads as one
   run of work rather than five unrelated blocks.
   ========================================================================== */

/* The connector only makes sense in a single column, where the visual order
   and the sequence are the same thing. In the two-column layout the reading
   order is 01-02 across then 03-04, so a vertical rule would draw 01 to 03 and
   assert a sequence that does not exist. The numerals carry the order there. */
@media (max-width: 799px) {
  .steps li:not(:last-child)::after {
    content: '';
    position: absolute;
    left: 1.05rem;
    top: 3.4rem;
    bottom: -0.4rem;
    width: 1px;
    background: linear-gradient(var(--line), transparent);
  }
}

.steps li::before {
  /* Sit the numeral on the page rather than floating it beside the text. */
  background: var(--paper);
  padding-bottom: 0.35rem;
  z-index: 1;
}

.section--fog .steps li::before {
  background: var(--fog);
}

/* Bring the remaining bordered cards onto the same surface language as the
   service tiles, so warranty / 404 / contact do not read as a different site.
   Informational cards keep a hairline; only interactive ones lift on hover. */
.card {
  border-color: #dde3e2;
  box-shadow: var(--shadow-sm);
}

.card--link:hover {
  box-shadow: var(--shadow-lg);
}

/* ==========================================================================
   29. Service page hero
   Was a white split with a floating image and a large dead zone bottom-right.
   Each service page is a search landing page, so it now opens the way the home
   page does: one photograph, a scrim, and the claim over it. The service's
   defining specification sits in the hero as a chip rather than buried
   two screens down.
   ========================================================================== */

.svc-hero {
  position: relative;
  isolation: isolate;
  background: var(--ink);
  color: #fff;
  padding-block: clamp(2.5rem, 5vw, 4rem) clamp(3.5rem, 7vw, 6rem);
}

.svc-hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}

.svc-hero__media picture,
.svc-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.svc-hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(17, 24, 22, 0.92) 0%,
    rgba(17, 24, 22, 0.84) 42%,
    rgba(17, 24, 22, 0.58) 78%,
    rgba(17, 24, 22, 0.42) 100%
  );
}

.svc-hero__inner {
  max-width: 40rem;
}

.crumb {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #a9bcc0;
}

.crumb a {
  color: #cfdadc;
  text-decoration: none;
  border-bottom: 1px solid rgba(207, 218, 220, 0.4);
  padding-bottom: 1px;
}

.crumb a:hover {
  color: #fff;
  border-bottom-color: #fff;
}

.svc-hero__eyebrow {
  display: block;
  color: #a9bcc0;
  margin-bottom: 1rem;
}

.svc-hero h1 {
  margin-bottom: 1.15rem;
  font-size: var(--step-4);
}

.svc-hero__lede {
  font-size: var(--step-2);
  line-height: 1.5;
  color: #dde5e6;
  max-width: 46ch;
  margin-bottom: 2rem;
}

.svc-hero .btn-row {
  margin-bottom: 2rem;
}

/* The hero's ghost button sits on a photograph, same as the home hero. */
.svc-hero .btn--ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.55);
  background: rgba(17, 24, 22, 0.3);
}

.svc-hero .btn--ghost:hover {
  border-color: #fff;
  background: rgba(17, 24, 22, 0.58);
}

.svc-hero__spec {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.6rem 1rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.06);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
}

.svc-hero__spec b {
  color: #a9bcc0;
  font-weight: 500;
  text-transform: uppercase;
}

.svc-hero__spec span {
  color: #fff;
}

/* Split variant that aligns both columns to the top. The default centres them,
   which on the service pages left the checklist floating in the middle of a
   much taller prose column with dead space above and below it. */
.split--top {
  align-items: start;
}

/* The points list is a specification, so it gets a surface that says so
   rather than floating loose beside the prose. */
.spec-panel {
  background: var(--paper);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: clamp(1.5rem, 3vw, 2rem);
}

.spec-panel h3 {
  font-size: var(--step-1);
  margin-bottom: 1.1rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--line);
}

.spec-panel .checklist {
  margin-top: 0;
}

/* ==========================================================================
   30. Closing CTA
   The slate CTA and the ink footer sat only one value step apart, so they read
   as one undifferentiated dark mass with the buttons floating in it. A red rule
   marks the boundary, the band is tightened, and the two surfaces now separate.
   ========================================================================== */

.cta {
  border-top: 3px solid var(--red);
  padding-block: clamp(3rem, 5.5vw, 4.75rem);
}

.cta__inner {
  align-items: center;
}

.cta h2 {
  font-size: var(--step-3);
  max-width: 18ch;
}

.cta p {
  margin-top: 0.85rem;
  font-size: var(--step-1);
}

/* Give the footer a little more separation from the CTA above it. */
.site-footer {
  border-top: 1px solid #1d282c;
}

@media (min-width: 860px) {
  .cta .btn-row {
    justify-content: flex-end;
  }
}

/* ==========================================================================
   31. Gallery affordance
   "— view larger" was printed on all twelve tiles, which read as noise rather
   than help. It stays in the accessible name for screen readers; sighted users
   get a corner glyph on hover instead.
   ========================================================================== */

.shot {
  box-shadow: var(--shadow-sm);
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}

.shot:hover,
.shot:focus-visible {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
}

.shot::after {
  content: '';
  position: absolute;
  top: 0.85rem;
  right: 0.85rem;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(17, 24, 22, 0.62) center / 15px 15px no-repeat
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7'/%3E%3C/svg%3E");
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
  pointer-events: none;
}

.shot:hover::after,
.shot:focus-visible::after {
  opacity: 1;
  transform: scale(1);
}

@media (max-width: 880px) {
  /* Same fix the home hero needed: on a tall narrow viewport a purely
     horizontal scrim leaves the lower half of the content over bare
     photograph. Add a vertical pass. */
  .svc-hero__media::after {
    background: linear-gradient(
      180deg,
      rgba(17, 24, 22, 0.86) 0%,
      rgba(17, 24, 22, 0.9) 55%,
      rgba(17, 24, 22, 0.95) 100%
    );
  }
}

@media (max-width: 560px) {
  /* Buttons that wrap onto separate lines size to their own content, which
     leaves a wide primary above a narrow secondary. Full width reads as
     deliberate and gives both a comfortable tap target. */
  .btn-row .btn {
    width: 100%;
  }
}

/* ==========================================================================
   32. Figures and labels

   Two things the first build left to defaults.

   Numerals: anywhere figures sit in a column or a row and are meant to be
   compared — the stat band, the process numbers, spec values, phone numbers —
   they need tabular lining figures so digits occupy equal width and align.
   Proportional figures make "50+" and "193M" sit on visibly different rhythms.

   Mono labels inherited the body's 1.65 line-height, which is a paragraph
   setting. A one- or two-line uppercase label wants roughly 1.3, or the two
   lines drift apart and stop reading as one label.
   ========================================================================== */

.spec,
.figures dt,
.figures dd,
.hero__proof dt,
.hero__proof dd,
.steps li::before,
.svc-hero__spec,
.detail__list b,
.shot__meta span,
.header-phone,
.crumb,
address,
a[href^='tel:'] {
  font-variant-numeric: tabular-nums lining-nums;
}

.spec,
.crumb,
.tile__eyebrow,
.shot__meta span,
.band__note,
.footer__grid h2 {
  line-height: 1.3;
}

/* The mono face carries a slashed zero and a dotted i by design; keep its
   ligatures off so specification strings read exactly as typed. */
.spec,
.crumb,
.tile__eyebrow,
.svc-hero__spec,
.detail__list b,
.figures dd,
.band__note,
.detail__caption {
  font-variant-ligatures: none;
}
