/* ---- tokens.css ---- */
/* ============================================================================
   TOKENS — AdLiBb.

   Every value below was measured off the live site (adlibb.com, Porto theme)
   in headless Chrome on 2026-09-25, at 1440 / 1200 / 992 / 768 / 390px.
   .scrape/DESIGN-NOTES.md has the tables. The original's type is FIXED, not
   fluid: the hero heading is 70px at every width down to 768. Where a value
   here uses clamp(), its maximum is the measured desktop value and the
   minimum only exists so a 360px phone does not overflow.
   ========================================================================= */

:root {
  /* ---- brand ---------------------------------------------------------- */
  --dark: #2a2a2a;            /* header, dark bands, buttons, footer */
  --dark-hover: #3d3d3d;      /* dark button hover */
  --dark-edge: #101010;       /* dark button bottom border */
  --ink: #212529;             /* headings */
  --ink-soft: #222529;        /* portfolio section headings */
  --blue: #1e73be;            /* inner-page banner box, service icons */
  --blue-bright: #0088cc;     /* "Visit Site" buttons */
  --blue-bright-hover: #0074ad;

  /* ---- neutrals ------------------------------------------------------- */
  --body: #777777;            /* body copy */
  --muted: #999999;           /* footer copy, testimonial author */
  --nav-sub: #adadad;         /* dropdown links */
  --white: #ffffff;
  --grey-soft: #f7f7f7;       /* FAQ question rows */
  --grey-faq: #f5f5f5;        /* FAQ archive rows */
  --line: #ededed;
  --card-line: rgba(0, 0, 0, 0.06);
  --overlay: rgba(33, 37, 41, 0.6);      /* hero stage */
  --thumb-title: rgba(33, 37, 41, 0.8);  /* portfolio card caption */

  /* ---- type ----------------------------------------------------------- */
  /* All three families are self-hosted in base/fonts.css. */
  --font: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-head: "Overpass", "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-serif: "PT Serif", Georgia, "Times New Roman", serif;

  /* The original's type is FIXED, with one step: below 576px Porto drops
     the base size from 14px to 13px and every em-sized heading follows, so
     each value is 13/14 of its desktop size there (measured at 390: hero
     65px, titles 35.75px, lead 19.5px, body 13px/20px). No clamp(): a fluid
     scale would put 30px titles at 390 where the original has 35.75px. */
  --fs-body: 14px;
  --lh-body: 26px;
  --fs-lead: 21px;            /* PT Serif lead, line-height 1.4 */
  --fs-hero: 70px;            /* measured 768 through 1440 */
  --fs-hero-sub: 25.2px;      /* weight 300, 2.5px tracking */
  --fs-banner: 49px;          /* 3.5em of 14 */
  --fs-h2: 38.5px;            /* 2.75em, weight 900 */
  --fs-h2-light: 36px;        /* weight 400 */
  --fs-cta: 35px;             /* 2.5em */
  --fs-eyebrow: 16.8px;       /* 1.2em, weight 300, 2.5px */
  --fs-text: 15.4px;          /* the "1.1em" paragraphs */
  --fs-small: 12.6px;         /* footer */
  --ls-tight: -0.05em;

  /* ---- layout --------------------------------------------------------- */
  --container: 1140px;        /* Porto .container, measured max-width */
  --gutter: 15px;
  /* Most full-width rows are inset by 6.4vw each side (92px at 1440), which
     is what lines the hero stage, the banner box and the CTA band up. */
  --wrap-inset: 6.4vw;
  --section-y: clamp(3rem, 2rem + 3vw, 5rem);
  --gap: 30px;

  /* ---- chrome --------------------------------------------------------- */
  --header-h: 125px;          /* measured, every width */
  --logo-w: 250px;            /* header logo 250 x 118 */
  --logo-w-mobile: 123px;     /* the original swaps to 123 x 58 below 992 */

  --radius: 0;                /* square throughout */
  --shadow-box: 0 30px 60px -30px rgba(0, 0, 0, 0.45);
  --shadow-card: 0 0 30px rgba(0, 0, 0, 0.08);

  --transition: 0.3s ease;
  --delay: 0ms;               /* per element, set by 50-reveal.js from data-delay */
  --pct: 100%;                /* per skill bar, set in the markup */
  --reveal: 1s ease;          /* every appear animation is 1s ease */

  /* ---- the one structural breakpoint --------------------------------- */
  --bp-nav: 991px;
}

@media (max-width: 575px) {
  :root {
    --fs-body: 13px;
    --lh-body: 20px;
    --fs-lead: 19.5px;
    --fs-hero: 65px;
    --fs-hero-sub: 23.4px;
    --fs-banner: 45.5px;
    --fs-h2: 35.75px;
    --fs-h2-light: 33.43px;
    --fs-cta: 32.5px;
    --fs-eyebrow: 15.6px;
    --fs-text: 14.3px;
    --fs-small: 11.7px;
  }
}

/* ---- base/fonts.css ---- */
/* ============================================================================
   FONTS — self-hosted. Every typeface this site uses is served from its own
   origin, out of assets/fonts/, which build.js copies into dist/.

   No font is loaded from a third-party host: no <link> to a font service, no
   @import, and no font host in the CSP (_headers keeps font-src at 'self').
   The hostnames are deliberately not spelled out in this comment: two checks
   grep src/ for them, and a comment naming them would fail both.
   A remote font is one more origin that can be slow, blocked or gone, and it
   is the one request on every page that tells a third party who visited.

   One @font-face per family, weight and style the CSS actually uses:
     font-family   the exact name tokens.css puts in --font
     src           the woff2 under /assets/fonts/, with format("woff2")
     font-weight   one weight per rule, as the source declared it
     font-style    normal or italic
     font-display  swap
     unicode-range copy it when the source CSS gives one; a subset the page
                   never uses is then never downloaded

   Where the files come from, on a conversion: the original site's own font
   files (the scrape downloads them), or for a Google font the css2 URL fetched
   with a desktop Chrome User-Agent — other User-Agents are served other
   formats — saving every woff2 it lists. Keep the families, weights, styles and
   unicode-range exactly as the source had them.

   Until a face is declared here, the family in --font falls back to the system
   stack after it, which is what the bare template renders with.

   The example is described in words on purpose: verify.js reads every
   url() in the bundle, comments included, and fails the build on one that
   does not resolve.

   THIS SITE (measured 2026-09-25): the original loads one Google Fonts
   request, css?family=Poppins:300,400,500,600,700|Overpass:300,300italic,
   400,400italic,500,600,700,800,900|PT+Serif:400,600,700, through the
   theme's webfont.js. Every face that request returns is declared below,
   in the order Google served them, with its unicode-range. Overpass is a
   variable font: Google points every weight of a subset at the same file,
   so 68 rules use 33 files. PT Serif has no 600, so Google serves none.
   Poppins is the body face, Overpass the headings, nav and buttons, and
   PT Serif the large lead paragraphs.
   ========================================================================= */

/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-400-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/assets/fonts/overpass-300-900-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-400-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-400-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* latin-ext */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-700-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-700-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* latin-ext */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-700-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "PT Serif";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/pt-serif-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/poppins-300-devanagari.woff2") format("woff2");
  unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
}
/* latin-ext */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/poppins-300-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/assets/fonts/poppins-300-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/poppins-400-devanagari.woff2") format("woff2");
  unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
}
/* latin-ext */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/poppins-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/poppins-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/poppins-500-devanagari.woff2") format("woff2");
  unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
}
/* latin-ext */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/poppins-500-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/poppins-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/poppins-600-devanagari.woff2") format("woff2");
  unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
}
/* latin-ext */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/poppins-600-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/poppins-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/poppins-700-devanagari.woff2") format("woff2");
  unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
}
/* latin-ext */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/poppins-700-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/poppins-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- base/reset.css ---- */
/* ---- reset & document defaults ------------------------------------------ */

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

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--body);
  background: var(--white);
  /* No -webkit-font-smoothing: antialiased. The original leaves smoothing at
     the browser's default, and on a Mac antialiased draws every glyph
     thinner — light text on the dark bands read grey beside the original
     (client review, 2026-10-13). */
  overflow-x: hidden;
}

img, svg {
  max-width: 100%;
  height: auto;
  display: block;
  border: 0;
}

a {
  color: var(--dark);
  text-decoration: none;
  transition: color var(--transition);
}
a:hover { color: var(--ink); }

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 1rem; padding-left: 1.25rem; }

button { font: inherit; }

/* Keyboard focus was invisible in the original theme. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

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

.skip-link {
  position: absolute;
  top: -60px;
  left: 12px;
  z-index: 2000;
  padding: 10px 18px;
  background: var(--dark);
  color: var(--white);
  font-weight: 600;
  transition: top var(--transition);
}
.skip-link:focus { top: 12px; color: var(--white); }

/* ---- base/typography.css ---- */
/* ---- typography ----------------------------------------------------------
   Measured off the original (Porto): body Poppins 14px/26px #777, headings
   Overpass, the large lead paragraphs PT Serif. The original's eyebrow was an
   h2 and its title an h3; here the eyebrow is a <p> and the title the h2, so
   the outline reads in order. The look is the same.
   -------------------------------------------------------------------------- */

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 1rem;
  font-family: var(--font-head);
  color: var(--ink);
  font-weight: 700;
  line-height: 1.2;
}

/* 16.8px, weight 300, 2.5px tracking. The source text is already uppercase. */
.eyebrow {
  margin: 0 0 8px;
  font-family: var(--font-head);
  font-size: var(--fs-eyebrow);
  font-weight: 300;
  line-height: 1.3;
  letter-spacing: 2.5px;
  color: var(--body);
}
.eyebrow--light { color: var(--white); opacity: 0.6; }
@media (max-width: 575px) { .eyebrow { margin-bottom: 7.43px; } }

/* 38.5px (2.75em of 14), weight 900, -0.05em. */
.title {
  margin: 0 0 16px;
  font-family: var(--font-head);
  font-size: var(--fs-h2);
  font-weight: 900;
  line-height: 1.2;
  letter-spacing: var(--ls-tight);
  color: var(--ink);
}
.title--white { color: var(--white); }
.title--sm { font-size: calc(2 * var(--fs-body)); }   /* 28px "Send a Message" (2em) */

/* The portfolio headings on the home page: 36px on a 44px line (33.43px on
   a 33.85px line below 576px — measured 2026-10-13), weight 400, centred. */
.title--light {
  margin: 0 0 32px;
  font-size: var(--fs-h2-light);
  font-weight: 400;
  line-height: 44px;
  letter-spacing: var(--ls-tight);
  color: var(--ink-soft);
  text-align: center;
}
@media (max-width: 575px) { .title--light { line-height: 33.85px; } }

/* The hatched bar under titles: the original's own 120x15 image at 50%. */
.divider {
  width: 120px;
  height: 15px;
  margin: 0 0 24px;
  opacity: 0.5;
}
.center .divider,
.section-head--center .divider { margin-left: auto; margin-right: auto; }

/* PT Serif 21px / 29.4px — the original's "custom-font3" paragraphs. */
.lead {
  margin: 0 0 24px;
  font-family: var(--font-serif);
  font-size: var(--fs-lead);
  line-height: 1.4;
  color: var(--body);
}

/* The original's "1.1em" paragraphs: 15.4px / 26px. */
.text {
  margin: 0 0 24px;
  font-size: var(--fs-text);
  line-height: 26px;
}

/* Below 576px Porto's rem is 14.86px and its 1rem / 1.5rem margins follow:
   titles 14.86px, paragraphs 22.29px apart; the hatched divider 18px above
   what follows (measured 2026-10-13 on About, Home and Contact). */
@media (max-width: 575px) {
  .title { margin-bottom: 14.86px; }
  .lead,
  .text { margin-bottom: 22.29px; }
  .divider { margin-bottom: 18px; }
}

.small { font-size: var(--fs-body); }

.center { text-align: center; }
.rel { position: relative; }

.section-head { position: relative; margin-bottom: 40px; }
.section-head--center { text-align: center; }

/* The huge outlined word behind a heading ("AdLiBb", "SOLUTIONS",
   "PROJECTS"…). A span, aria-hidden, never a heading: the original used
   h2 elements for these, which put "SOLUTIONS" in the page outline.
   Measured: Overpass 900, 147.2px (9.2rem), -0.05em, white fill with a 1px
   #2a2a2a stroke, at 10% opacity. */
.watermark {
  position: absolute;
  left: 0;
  top: 50%;
  z-index: -1;
  transform: translateY(-50%);
  font-family: var(--font-head);
  font-size: calc(var(--fs-body) * 10.514);   /* 147.2px; 136.7px below 576 */
  font-weight: 900;
  line-height: 1;
  letter-spacing: var(--ls-tight);
  white-space: nowrap;
  color: var(--white);
  -webkit-text-stroke: 1px var(--dark);
  opacity: 0.1;
  pointer-events: none;
  user-select: none;
}
.watermark--center { left: 50%; transform: translate(-50%, -50%); }
/* The original set the second outlined word on a page smaller: 115.2px
   (8.229em of 14px; 106.98px below 576px) — "SOLUTIONS" on the home page,
   "AdLiBb" on About (measured 2026-10-13). */
.watermark--sm { font-size: calc(var(--fs-body) * 8.229); }
/* About and the privacy policy: the original put this one 100px below the
   top of the heading block and 95px left of it, on a 42px line so the
   glyphs overflow it evenly (measured 2026-10-13) — not centred on it. */
.watermark--desc { top: 100px; left: -95px; line-height: 42px; transform: none; }
/* /projects/ and the category pages: 100px below the eyebrow too, across the
   heading's column and its two 15px gutters and centred in that — so 15px
   right of the page's centre — and from the left once it is wider than that,
   as the original's overflowed (measured 2026-10-13). */
.watermark--archive { top: 100px; left: 0; width: calc(100% + 30px); line-height: 42px; text-align: center; transform: none; }
@media (max-width: 575px) { .watermark--archive { top: 103.43px; } }

/* The watermark sits BEHIND the heading, so its section needs a stacking
   context of its own, or z-index:-1 would put it behind the page. */
.section-head,
.faq-block__intro,
.rel { isolation: isolate; }

.rule {
  height: 1px;
  margin: 0;
  border: 0;
  background: var(--card-line);
}

/* ---- base/layout.css ---- */
/* ---- layout primitives ---------------------------------------------------
   The original's rows are inset 6.4vw from each edge (92px at 1440) with a
   15px gutter inside, which puts content at 107..1333px on a 1440 screen —
   measured. .wrap reproduces that. The grids use auto-fit + minmax so they
   reflow without media queries.
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.wrap {
  width: 100%;
  max-width: calc(1440px + 12.8vw);
  margin: 0 auto;
  padding: 0 calc(var(--wrap-inset) + var(--gutter));
}
/* Below 576px the original's rows keep the 6.4vw inset and drop the gutter
   (content 340px wide at 390 — measured). */
@media (max-width: 575px) {
  .wrap { padding: 0 var(--wrap-inset); }
  /* ...except where the original kept it (sidebar pages). */
  .wrap.with-sidebar { padding: 0 calc(var(--wrap-inset) + var(--gutter)); }
}
.wrap--flush { padding: 0 var(--wrap-inset); }
/* A row whose content sat in Porto's .container inside the 6.4vw inset on the
   original (the /service/ cards, the Members archive): that container stops
   at 960px from 992px and 1140px from 1170px (1440 from 1500px, as .wrap),
   so from about 1125 to 1169px and 1308 to 1499px the content is narrower
   than a plain row's — /service/'s cards 295px at 1440, not 334; the
   Members' 355px, not 395 (measured 2026-10-20). */
@media (min-width: 992px) and (max-width: 1169px) { .wrap--box { max-width: calc(960px + 12.8vw); } }
@media (min-width: 1170px) and (max-width: 1499px) { .wrap--box { max-width: calc(1140px + 12.8vw); } }
/* Porto's own .container, where the original used it without the 6.4vw
   inset (Our Work, the FAQ pages): 1440px wide from 1500px, 1140 from
   1170, 960 from 992 — 15px padding inside — and below that the window's
   width less 15px a side, the whole width below 576px (measured
   2026-10-13). */
.pwrap { margin: 0 auto; padding: 0 15px; }
@media (min-width: 992px) { .pwrap { max-width: 960px; } }
@media (min-width: 1170px) { .pwrap { max-width: 1140px; } }
@media (min-width: 1500px) { .pwrap { max-width: 1440px; } }
@media (max-width: 575px) { .pwrap { padding: 0; } }
.wrap--narrow { max-width: calc(1060px + 2 * var(--gutter)); padding: 0 var(--gutter); }

/* overflow-x: clip, not hidden: the outline watermarks are wider than a
   phone, as on the original, and are cut at the section's edge. clip makes
   no scroll container, so the sticky sidebars inside still stick. */
.section { position: relative; padding: var(--section-y) 0; overflow-x: clip; }
.section--tight { padding: clamp(1.5rem, 1rem + 2vw, 2.5rem) 0; }
.section--flush-top { padding-top: 0; }
/* The opening section of About, the privacy policy, /projects/ and the
   project category pages: the original started its heading 192px below the
   banner band (4 x 3rem), i.e. 89px below the blue box; 178px and 75px below
   576px, where its rem is 14.86px (measured 2026-10-13). */
.section--desc { padding-top: 89px; }
@media (max-width: 575px) { .section--desc { padding-top: 75.29px; } }

/* The privacy policy, as the original set it (measured 2026-10-14 at 1512
   and 390): the lead straight under the divider; then plain paragraphs on
   26px lines, 20px apart; the first two 1.1em and 24px apart, the second
   16px taller below; 92px under the first (two empty paragraphs of the
   original's, 34px each, plus its 24px); 54px from the last to the footer.
   Below 576px the plain ones on 20px lines and the gaps the original's rem
   (14.86px) makes. */
.section-head--policy { margin-bottom: 0; }
.section--policy { padding-bottom: 34px; }
.policy p { margin: 0 0 20px; line-height: 26px; }
.policy .policy__big { margin-bottom: 24px; font-size: 1.1em; }
.policy .policy__intro { margin-bottom: 92px; }
.policy .policy__list { padding-bottom: 16px; }
@media (max-width: 575px) {
  .section--policy { padding-bottom: 31.57px; }
  .policy p { margin-bottom: 18.57px; line-height: 20px; }
  .policy .policy__big { margin-bottom: 22.29px; line-height: 26px; }
  .policy .policy__intro { margin-bottom: 85.43px; }
  .policy .policy__list { padding-bottom: 14.86px; }
}
/* Around the dark call-to-action band on the home page: 105px above it from
   the web projects (102px below 576px), 40px below it to "Portrait
   Photography" (37.14px) — the original's (measured 2026-10-13). */
.section--before-cta { padding-bottom: 105px; }
.section--after-cta { padding-top: 40px; }
@media (max-width: 575px) {
  .section--before-cta { padding-bottom: 102px; }
  .section--after-cta { padding-top: 37.14px; }
}

.grid-2,
.grid-3 {
  display: grid;
  gap: var(--gap);
}
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }

/* Text beside media. Collapses by width, not by breakpoint. */
.split {
  display: grid;
  gap: clamp(2rem, 1rem + 4vw, 5rem);
  align-items: center;
  grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr));
}
.split__media { position: relative; min-width: 0; }
.split__text { position: relative; min-width: 0; }
/* The media column comes first in the DOM and draws on the left. */
.split--media-first > .split__media { order: 0; }
.split__text--right { text-align: right; }
/* About's "Meet Our Team": the carousel takes two thirds, the text one. */
@media (min-width: 992px) { .split--wide-media { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); } }
.split__text--right .divider { margin-left: auto; }

/* Main column + sidebar. The original's sidebar was 25% of the row at
   1201px and up and 33.3% from 992 to 1200, stacked below 992. It is AFTER
   the main column in the DOM on every page; the service pages draw it on
   the left, the project pages on the right — as here. */
.with-sidebar {
  display: grid;
  gap: 30px;
  align-items: start;
}
.with-sidebar__main { min-width: 0; }
.with-sidebar__side { min-width: 0; }

@media (min-width: 992px) {
  /* Porto's col-lg-8/col-lg-4 with 15px gutters, over this row's width W:
     main 2/3 of (W + 30) less 30, sidebar 1/3 of (W + 30) less 30. */
  .with-sidebar { grid-template-columns: calc(66.667% - 10px) calc(33.333% - 20px); }
  .with-sidebar--left { grid-template-columns: calc(33.333% - 20px) calc(66.667% - 10px); }
  .with-sidebar--left .with-sidebar__side { grid-column: 1; grid-row: 1; }
  .with-sidebar--left .with-sidebar__main { grid-column: 2; }
  /* The original's sidebar stuck while the page scrolled, from 992px up. */
  .with-sidebar__side { position: sticky; top: 24px; }
}
@media (min-width: 1201px) {
  /* col-9/col-3: 912px and 284px at 1440 — measured. */
  .with-sidebar { grid-template-columns: calc(75% - 7.5px) calc(25% - 22.5px); }
  .with-sidebar--left { grid-template-columns: calc(25% - 22.5px) calc(75% - 7.5px); }
}

/* ---- components/button.css ---- */
/* ---- buttons -------------------------------------------------------------
   The original's "custom-btn-style-1": a dark button with a 1px outline
   frame drawn 5px outside it by ::before. On hover the frame slides 5px down
   and right so its top-left corner meets the button's, and the fill lightens.
   Measured: Overpass 14px/21px, weight 700, padding 16px 48px, 190x55 for
   "GET STARTED"; the frame 198x63.

   `z-index: 1` on the button creates the stacking context that keeps the
   frame's z-index:-1 above the section behind it. */
.btn {
  position: relative;
  z-index: 1;
  display: inline-block;
  padding: 16px 48px;
  border: 1px solid var(--dark);
  border-bottom-color: var(--dark-edge);
  border-radius: var(--radius);
  background: var(--dark);
  color: var(--white);
  font-family: var(--font-head);
  font-size: var(--fs-body);
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  cursor: pointer;
  transition: background-color var(--transition), border-color var(--transition), color var(--transition);
}
.btn::before {
  content: "";
  position: absolute;
  inset: -5px;
  z-index: -1;
  border: 1px solid var(--dark);
  pointer-events: none;
  transition: inset var(--transition);
}
.btn:hover {
  background: var(--dark-hover);
  border-color: #444444 #444444 var(--dark);
  color: var(--white);
}
.btn:hover::before { inset: 0 -10px -10px 0; }

/* On dark bands: white, dark text, a translucent frame. */
.btn--light {
  background: var(--white);
  border-color: #d9d9d9 #d9d9d9 #bfbfbf;
  color: var(--ink);
}
.btn--light::before { border-color: rgba(255, 255, 255, 0.5); }
.btn--light:hover {
  background: #f2f2f2;
  border-color: #e6e5e5 #e6e5e5 #cccccc;
  color: var(--ink);
}

/* "Visit Site" on the web projects: WPBakery's modern rounded button,
   #0088cc with a light top gradient; #0074ad on hover. Measured 132x53. */
.btn--blue {
  padding: 12.8px 32px;
  border: 1px solid var(--blue-bright);
  border-radius: 5px;
  background: var(--blue-bright) linear-gradient(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.01));
  font-family: var(--font);
  font-size: calc(var(--fs-body) * 1.143);
  font-weight: 400;
  line-height: normal;
}
.btn--blue::before { display: none; }
.btn--blue:hover { background-color: var(--blue-bright-hover); border-color: var(--blue-bright-hover); color: #f7f7f7; }

.btn-row { margin: 32px 0 0; }

/* Below 576px Porto's rem is 14.86px and every button's 1rem / 3rem padding
   follows (measured 2026-10-13: 177x51 and 170x51 at 390, where these were
   54px tall). */
@media (max-width: 575px) {
  .btn { padding: 14.86px 44.57px; }
  .btn--blue { padding: 11.89px 29.71px; }
}
/* "Load More..." was the original's pagination link styled as a button, in
   px: 16px 48px and 14px text at every width (188x55 at 390 — measured). */
@media (max-width: 575px) {
  .btn[data-load-more] { padding: 16px 48px; font-size: 14px; line-height: 21px; }
}

/* ---- components/header.css ---- */
/* ---- header & navigation -------------------------------------------------
   Measured: a 125px #2a2a2a band at every width. The 250x118 logo hangs from
   the top-left, the nav is centred, the social icons sit right (hidden below
   992px). Nav links: Overpass 14px/20px, weight 600, 1px tracking, white,
   40px 14.4px padding (a 100px-tall target); the current page has a 3px
   white bar under its label, and hovering any item moves the bar to it.

   On desktop (992px and up) the original's header scrolled away with the
   page; once it was out of sight it became a bar fixed to the top — 128px
   with a 3px #ededed top edge, the 98px logo 30px in, a faint shadow —
   hidden while the page scrolls down and sliding in (0.3s) as soon as it
   scrolls up; back at the top it was the plain header again (measured
   2026-10-13). 10-header.js sets .is-stuck, .is-hidden and .is-ready; the
   wrapper keeps the header's 125px in the page while it is fixed.

   The 991px breakpoint is structural: the nav becomes the phone menu.
   -------------------------------------------------------------------------- */

.header-wrap { min-height: var(--header-h); }
.site-header {
  position: relative;
  z-index: 1000;
  background: var(--dark);
}
@media (min-width: 992px) {
  .site-header.is-stuck {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    border-top: 3px solid #ededed;
    box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.06);
  }
  .site-header.is-stuck.is-ready { transition: transform 0.3s, opacity 0.3s, visibility 0.3s; }
  .site-header.is-stuck.is-hidden { transform: translate3d(0, -100%, 0); opacity: 0; visibility: hidden; }
  .site-header.is-stuck .brand { align-self: center; padding-left: 15px; }
  .site-header.is-stuck .brand img { width: 98px; }
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 20px;
  min-height: var(--header-h);
  padding: 0 15px;
}

.brand { flex: 1 1 0; align-self: flex-start; }
.brand img {
  width: var(--logo-w);
  height: auto;
}

/* The original centred a column 15px wider than its menu and set the menu
   at the column's left, so the menu sits 7.5px left of the centre. */
.main-nav { flex: 0 0 auto; padding-right: 15px; }
@media (max-width: 991px) { .main-nav { padding-right: 0; } }
.nav-list {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav-list > li { position: relative; }
.nav-list > li > a {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 40px 14.4px;
  color: var(--white);
  font-family: var(--font-head);
  font-size: 14px;
  font-weight: 600;
  line-height: 20px;
  letter-spacing: 1px;
  white-space: nowrap;
}
.nav-list > li > a::before {
  content: "";
  position: absolute;
  left: 14.4px;
  right: 14.4px;
  bottom: 32px;
  height: 3px;
  background: var(--white);
  opacity: 0;
  transition: opacity var(--transition);
}
.nav-list > li > a:hover,
.nav-list > li.is-active > a { color: var(--white); }
.nav-list > li > a:hover::before,
.nav-list > li > a[aria-current="page"]::before,
.nav-list > li.is-active > a::before { opacity: 1; }
/* While the pointer is on another item, the current page's bar goes, as on
   the original: one bar at a time. */
.nav-list:hover > li:not(:hover) > a::before { opacity: 0; }
/* The small chevron after "Services": 9.89px wide, 5px after the word, on
   its baseline, as the original's icon-font glyph (measured 2026-10-13). */
.nav-caret { display: block; width: 9.89px; height: 14px; margin-left: 5px; }
@media (max-width: 991px) { .nav-caret { display: none; } }

/* Dropdown: 200px, #1e1e1e with a soft shadow, 5px top and bottom; links
   Overpass 14px/24px, weight 400, -0.5px, #adadad. It hangs from the foot
   of the 100px-tall menu link, 12px above the header's edge (measured
   2026-10-13). */
.sub-nav {
  position: absolute;
  top: 100%;
  left: 0;
  width: 200px;
  margin: 0;
  padding: 5px 0;
  box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.15);
  list-style: none;
  background: #1e1e1e;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity var(--transition), transform var(--transition), visibility 0s linear 0.3s;
}
.has-sub:hover > .sub-nav,
.has-sub:focus-within > .sub-nav {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity var(--transition), transform var(--transition), visibility 0s;
}
.sub-nav a {
  display: block;
  padding: 8px 18px;
  border-bottom: 1px solid #2b2b2b;
  color: var(--nav-sub);
  font-family: var(--font-head);
  font-size: 14px;
  line-height: 24px;
  letter-spacing: -0.5px;
}
.sub-nav li:last-child a { border-bottom: 0; }
.sub-nav a:hover,
.sub-nav a[aria-current="page"] { background: #282828; color: var(--white); }

.header-social {
  flex: 1 1 0;
  display: flex;
  justify-content: flex-end;
  gap: 5.6px;
}
.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 33px;
  height: 33px;
  border-radius: 50%;
  color: var(--white);
  transition: background-color var(--transition), opacity var(--transition);
}
/* The original's Font Awesome glyphs at 14.4px paint the "f" 15px tall and
   the other two 13px — a little over the em, so the SVGs are drawn 15.5px
   (measured 2026-10-13 from screenshots of both). */
.social-link svg { width: auto; height: 15.5px; }
.social-link:hover { color: var(--white); opacity: 0.9; }

/* The original's menu button: Font Awesome's bars at 1.2em in a 34px-tall
   button, 7px 13px around it (40.7px wide at 768). */
.nav-toggle {
  display: none;
  height: 34px;
  padding: 7px 13px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--white);
  font-size: 1.2em;
  line-height: 20px;
  cursor: pointer;
}
.nav-toggle svg { display: block; width: 0.875em; height: 1em; }
.nav-expand { display: none; }

/* ---- phone menu ---------------------------------------------------------
   The original's, below 992px (measured 2026-10-14 at 390, 600, 700, 768
   and 991): the button opens a #2a2a2a panel the width of the window under
   the 125px header, sliding down over the page in 0.4s, as jQuery's
   slideToggle did (20-nav.js) — the page itself does not move. In it, 30px
   above and below, a column inset 6.5vw + 15px each side; rows 38px apart,
   a 1px #3e3e3e line under each but the last; the links Poppins 0.9em on
   25px lines, weight 700, capitals, white, 5px 6px around them. Services'
   pages open from a chevron in a 30x35 box 5px from the row's right end
   (#dedede, white while open; the link itself goes to the page), 20px in,
   in #dedede without capitals. The original's current-page row is #2a2a2a,
   the panel's own colour, so nothing marks it. A tap outside the header
   closes the menu here; on the original nothing but the button does. */
@media (max-width: 991px) {
  .header-inner { padding: 0 6.5vw; }
  .brand { align-self: center; }
  .brand img { width: var(--logo-w-mobile); }
  .header-social { display: none; }
  .nav-toggle { display: inline-flex; align-items: center; margin-left: auto; }

  .main-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: none;
    overflow: hidden;
    padding: 30px 0;
    background: var(--dark);
  }
  .main-nav.is-open { display: block; }

  .nav-list { display: block; margin: 0 calc(6.5vw + 15px); }
  .nav-list li { position: relative; padding: 1px 0; border-bottom: 1px solid #3e3e3e; }
  .nav-list li:last-child { border-bottom: 0; }
  .nav-list > li > a,
  .sub-nav a {
    display: block;
    padding: 5px 6px;
    border: 0;
    color: var(--white);
    font-family: var(--font);
    font-size: 0.9em;
    font-weight: 700;
    line-height: 25px;
    letter-spacing: normal;
    text-transform: uppercase;
    white-space: normal;
  }
  .nav-list > li > a::before { display: none; }
  .nav-list > li.has-sub > a { padding-right: 33px; }

  .nav-expand {
    position: absolute;
    top: 0;
    right: 5px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 35px;
    padding: 0;
    border: 0;
    background: transparent;
    color: #dedede;
    cursor: pointer;
  }
  .nav-expand[aria-expanded="true"] { color: var(--white); }
  .nav-expand svg { display: block; width: 9px; height: 6.3px; }

  .sub-nav {
    position: static;
    display: none;
    width: auto;
    margin: 0 0 0 20px;
    padding: 0;
    overflow: hidden;
    box-shadow: none;
    background: transparent;
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: none;
  }
  .has-sub.is-open > .sub-nav { display: block; }
  .sub-nav a { color: #dedede; text-transform: none; }
  .sub-nav a:hover,
  .sub-nav a[aria-current="page"] { background: transparent; color: var(--white); }
}

/* ---- components/page-banner.css ---- */
/* ---- inner-page banner ----------------------------------------------------
   Measured at 1440: the dark band continues 120px below the header; a blue
   (#1e73be) box, inset 6.4vw each side, starts at the header's bottom edge
   and hangs 103px below the band onto the white page, with a soft shadow.
   Title: Overpass 49px (3.5em), weight 900, white, capitalised by CSS as on
   the original. Breadcrumb: Overpass 16.8px, 4px tracking, white; chevrons
   at 50%, the current page at 70%.

   The original pushed the box down with a transform, so on pages whose
   content had no top padding (FAQ answers, member pages, Our Work,
   "Does Your Website Convert?") the box covered the first lines of content.
   Here the box is in the flow and the band reserves its overhang, so
   nothing can sit under it.

   flow-root keeps the box's -103px bottom margin inside the band. Without it
   that margin collapsed with the band's own 103px into none, and the band
   ran dark down to the box's bottom edge — no overhang at all (the client
   review of 2026-10-13 noticed). */
.page-banner {
  position: relative;
  z-index: 1;
  display: flow-root;
  margin-bottom: 103px;
  padding: 0 var(--wrap-inset);
  background: var(--dark);
}
.page-banner__box {
  max-width: calc(1440px + 12.8vw);
  margin: 0 auto -103px;
  /* 10px, plus the 15px of the original's container inside it: its title and
     breadcrumb wrapped within 1268px at 1512 (measured 2026-10-13). */
  padding: 58px 25px 80px;
  background: var(--blue);
  text-align: center;
  box-shadow: 0 20px 30px -20px rgba(0, 0, 0, 0.3);
}
.page-banner__title {
  margin: 0;
  color: var(--white);
  font-size: var(--fs-banner);
  font-weight: 900;
  line-height: 1.2;
  letter-spacing: var(--ls-tight);
  text-transform: capitalize;
  overflow-wrap: anywhere;
}

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--white);
  font-family: var(--font-head);
  font-size: 16.8px;
  line-height: 26px;
  letter-spacing: 4px;
}
.breadcrumb li:last-child { opacity: 0.7; }
/* The original's separator: Porto's thin "›" glyph in a 20px box, 9px after
   the item and 8px before the next, at half strength (measured 2026-10-13). */
.breadcrumb li:not(:last-child)::after {
  content: "";
  display: inline-block;
  width: 20px;
  height: 26px;
  margin: 0 8px 0 9px;
  vertical-align: top;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 14'%3E%3Cpolyline points='1.5,1.5 7,7 1.5,12.5' fill='none' stroke='%23fff' stroke-width='1.6'/%3E%3C/svg%3E") center / 9px 14px no-repeat;
  opacity: 0.5;
}
.breadcrumb a {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  color: var(--white);
}
.breadcrumb a:hover { color: var(--white); text-decoration: underline; }
/* The title and breadcrumb sat in Porto's .container inside the box: 960px
   from 992px, 1140 from 1170, 1440 from 1500, less its 15px a side. Where the
   box is wider than that, they wrap within it — a two-category project's
   breadcrumb takes two lines at 1440 there (Larkin, measured 2026-10-20). */
@media (min-width: 992px) { .page-banner__box > * { max-width: 930px; margin-right: auto; margin-left: auto; } }
@media (min-width: 1170px) { .page-banner__box > * { max-width: 1110px; } }
@media (min-width: 1500px) { .page-banner__box > * { max-width: 1410px; } }
/* A project in two categories: the original puts 5px more after the comma. */
.breadcrumb a + a { margin-left: 5px; }

/* Below 576px the original's box padding is 5rem at its 14.86px rem and the
   breadcrumb runs on 20px lines, so the box ends 18px sooner than at 26px
   (measured 2026-10-13). The links keep their 26px tap height without
   growing the line. */
/* From 576 to 991px the original's container adds its 15px gutter as well,
   so the title wraps 40px in from the box's sides (measured 2026-10-14 at
   991, 768, 700 and 576: "Professional Photography" on two lines at 700). */
@media (min-width: 576px) and (max-width: 991px) {
  .page-banner__box { padding-right: 40px; padding-left: 40px; }
}
@media (max-width: 575px) {
  /* ...and no container padding inside it (the original's was 0 here). */
  .page-banner__box { padding: 52px 10px 74.29px; }
  .breadcrumb { line-height: 20px; }
  .breadcrumb li:not(:last-child)::after { height: 20px; }
  .breadcrumb a { margin: -3px 0; }
}

/* ---- components/hero.css ---- */
/* ---- home hero -------------------------------------------------------------
   The original's (measured 2026-10-13 at 1512 / 1024 / 768 / 500 / 390):

   - A #2a2a2a band from the page top to y=800 (600 below 768), under the
     125px header — here the section starts below the header, so it is
     675px (475px) tall and everything else is offset by -125px.
   - The stage: a box inset 6.4vw each side, from y=103 to y=903 (703 below
     768), overflow hidden. Two columns side by side (one, the left, below
     576px), each a strip of four panels one stage tall: blank, bulb, bulb,
     bulb on the left; bulb, bulb, blank, bulb on the right. Every panel is
     the bulb (object-fit: cover) or nothing, under #212529 at 60% — so the
     bulb reads muted grey, and a blank panel is a dark layer over the band
     and a grey strip where the stage hangs 103px onto the white page.
   - Two text slides with the same words, crossfading (1s): slide 1 left,
     over the left column's blank panel; slide 2 right-aligned, over the
     right column's blank panel, with its button still on the left. On the
     change the left strip moves up one panel and the right strip down one
     (transform, 1s), so the bulb crosses to the other side.
   - Autoplay changes slide after 5s (paused while the pointer is over it)
     and stops on slide 2: the original's carousel neither loops nor rewinds.
   - Prev/next arrows (45x60, rgba(38,42,47,.4), white chevrons, 33px in from
     each edge) only from 1200px, only from about 3s after load, and only
     under the pointer, sliding 10px in; the one at the end is at 50%. From
     then the stage also carries a soft shadow.

   The text block is 78% of the page wide, its box 16px below the band top
   with 48px / 15px padding, the words centred in what is left: heading
   Overpass 70px/1 weight 900 white; the line under it 25.2px weight 300,
   2.5px tracking, 80% white; the tagline 15.4px/26px, 60% white (white under
   the pointer), 48px above the button. */
.hero {
  position: relative;
  z-index: 0;
  height: 675px;
  margin-bottom: 103px;
  background: var(--dark);
}
.hero__stage {
  position: absolute;
  top: -22px;               /* y=103 on the page */
  left: var(--wrap-inset);
  right: var(--wrap-inset);
  z-index: -1;
  display: flex;
  height: 800px;
  overflow: hidden;
  transition: box-shadow 0.3s;
}
.hero.has-shadow .hero__stage { box-shadow: 0 20px 30px -20px rgba(0, 0, 0, 0.3); }
.hero__col { flex: 0 0 50%; height: 100%; }
.hero__strip {
  display: flex;
  flex-direction: column;
  height: 100%;
  transform: translate3d(0, calc(var(--slide, 0) * -100%), 0);
  transition: transform 1s;
}
.hero__col--rev .hero__strip { transform: translate3d(0, calc((3 - var(--slide, 0)) * -100%), 0); }
.hero.is-b { --slide: 1; }
.hero__panel { position: relative; flex: 0 0 100%; height: 100%; }
.hero__panel::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--overlay);
}
.hero__panel img { width: 100%; height: 100%; max-width: none; object-fit: cover; }

.hero__slides {
  position: absolute;
  top: -125px;
  left: 0;
  right: 0;
  height: 800px;
}
.hero__slide { position: absolute; inset: 0; }
.hero__box {
  display: flex;
  align-items: center;
  box-sizing: border-box;
  max-width: 78%;
  height: 100%;
  margin: 16px auto 0;
  padding: 48px 15px 0;
}
.hero__text { width: 100%; }
.hero__slide--b { opacity: 0; pointer-events: none; text-align: right; }
.hero__slide--b .hero__btn-space { text-align: center; }
.hero__fade, .hero__slide--b { transition: opacity 1s ease; }
.hero.is-b .hero__fade { opacity: 0; }
.hero.is-b .hero__slide--b { opacity: 1; }
.hero__btn-space { display: inline-block; visibility: hidden; }

/* Each change of slide, wider than 767px, ends (after the 1s crossfade) by
   playing the new slide's entrance again, as Porto's carousel does: the
   heading rises into its own clipped box at 100ms, the line under it and
   the tagline fade up 30px at 250 and 500ms, the button at 750ms. */
.hero__clip { overflow: hidden; }
/* reset.css zeroes a last paragraph's bottom margin, and each line is the
   last thing in its clip box: the margins are restated at a higher weight. */
.hero__clip > .hero__sub { margin-bottom: 4px; }
.hero__clip > .hero__tag { margin-bottom: 48px; }
.hero.is-replay:not(.is-b) .hero__slide--a .hero__title,
.hero.is-replay.is-b .hero__slide--b .hero__title { animation: hero-rise 1s ease 0.1s both; }
.hero.is-replay:not(.is-b) .hero__slide--a .hero__sub,
.hero.is-replay.is-b .hero__slide--b .hero__sub { animation: fade-in-up 1s ease 0.25s both; }
.hero.is-replay:not(.is-b) .hero__slide--a .hero__tag,
.hero.is-replay.is-b .hero__slide--b .hero__tag { animation: fade-in-up 1s ease 0.5s both; }
.hero.is-replay .hero__slide--a .btn { animation: fade-in-up 1s ease 0.75s both; }
@keyframes hero-rise { from { transform: translateY(100%); } to { transform: none; } }

.hero__title {
  margin: 0;
  color: var(--white);
  font-family: var(--font-head);
  font-size: var(--fs-hero);
  font-weight: 900;
  line-height: 1;
  letter-spacing: 0;
}
.hero__sub {
  margin: 0 0 4px;
  color: rgba(255, 255, 255, 0.8);
  font-family: var(--font-head);
  font-size: var(--fs-hero-sub);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: 2.5px;
}
.hero__tag {
  margin: 0 0 48px;
  color: rgba(255, 255, 255, 0.6);
  font-size: var(--fs-text);
  line-height: 26px;
  transition: color 0.3s, opacity 1s ease;
}
/* Under the pointer the tagline goes white; the pointer is always over
   slide 1's copy (slide 2 takes no pointer), so both copies follow it. */
.hero:has(.hero__slide--a .hero__tag:hover) .hero__tag { color: var(--white); }

.hero__arrow {
  position: absolute;
  top: 275px;               /* y=400 on the page, centred */
  z-index: 3;
  display: none;
  align-items: center;
  justify-content: center;
  width: 45px;
  height: 60px;
  margin-top: -30px;
  padding: 0;
  border: 0;
  background: rgba(38, 42, 47, 0.4);
  color: var(--white);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s, transform 0.4s;
}
.hero__arrow--prev { left: 33px; transform: translateX(-10px); }
.hero__arrow--next { right: 33px; transform: translateX(10px); }
@media (min-width: 1200px) {
  .hero.nav-ready .hero__arrow { display: inline-flex; }
}
.hero:hover .hero__arrow,
.hero:has(:focus-visible) .hero__arrow { opacity: 1; transform: none; }
.hero:hover .hero__arrow[aria-disabled="true"],
.hero:has(:focus-visible) .hero__arrow[aria-disabled="true"] { opacity: 0.5; cursor: default; }

@media (min-width: 576px) and (max-width: 767px) {
  .hero__clip > .hero__title { margin-bottom: 4px; }
}
@media (max-width: 767px) {
  .hero { height: 475px; }
  .hero__stage { height: 600px; }
  .hero__slides { height: 600px; }
}
/* Below 576px the original's rem is 14.86px and its body size 13px; the
   text box loses its side padding and only the left column shows. */
@media (max-width: 575px) {
  .hero__stage .hero__col { flex-basis: 100%; }
  .hero__col--rev { display: none; }
  .hero__box { margin-top: 44.57px; padding: 44.57px 0 0; }
  .hero__clip > .hero__title { margin-bottom: 7.43px; }
  .hero__clip > .hero__sub { margin-bottom: 3.71px; }
  .hero__clip > .hero__tag { margin-bottom: 44.57px; }
}

/* The big grey logotype behind the about split: the original's 600px
   picture from the hero band's bottom edge (103px above this section, under
   the stage's overhang), 15px past the window's right edge — or the window's
   width plus 30px, from 15px left of it, on a narrower screen (measured
   2026-10-13 at 1512, 1024, 768 and 390). */
.bg-logo {
  position: absolute;
  top: -103px;
  right: -15px;
  z-index: -1;
  width: min(600px, calc(100vw + 30px));
  max-width: none;
  pointer-events: none;
}
/* About and the privacy policy: the grey bulb behind the intro, at its full
   600px and full strength, from the page's left edge and the banner band's
   bottom edge (103px above the section; page-banner.css) — the original's
   (measured 2026-10-13, client review: it had been half size at 60%). On a
   phone it is the screen's width plus 15px, cut at the edge, as there. */
.bg-logo--left { top: -103px; right: auto; left: 0; width: min(600px, calc(100vw + 15px)); max-width: none; }

/* ---- home: the about split ("We're here to help") ------------------------------
   The original's Porto row (measured 2026-10-13 at 1512, 1024, 768 and 390):
   90% of the 6.4vw-inset width, the services cards inside it and this row
   15px wider each side of them, 48px under them (46px below 576px).
   Pictures 5/12 and, one twelfth further right, the text 5/12 from 1200px;
   4/12 and 7/12 from 992px; below that the pictures 9/12 over the text,
   96px apart (89px below 576px). Each column keeps 15px gutters.
   The pictures: 1.png at the column's width with 35px under it, and 2.png
   on top of it, 117% of that width, from the same left edge, its foot 40px
   below 1.png's — so it all but covers it.
   The text: 48px in from the column's left and 96px down from 992px (48px
   above it below 992px); the outlined "AdLiBb" 190px below the column's top
   at its left edge, on a 42px line; tagline and paragraph 40px apart (Porto's
   pb-3 + mb-4: 37.14px below 576px); the button 5px in. 62px from the row
   to the rule (60px below 576px); from 1200px the row keeps 48px inside
   its foot and the gap is 110px. */
/* flow-root: the cards' negative top margin must not collapse through this
   section (it would move the section, and the grey bulb with it). */
.home-info { display: flow-root; padding-bottom: 0; }
.info-split {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  width: calc(0.9 * (100% - 12.8vw));
  margin: 48px auto 62px;
}
.info-split__media,
.info-split__text { position: relative; padding: 0 15px; }
.info-split__media { width: 75%; margin-bottom: 48px; padding-bottom: 48px; }
.info-split__text { width: 100%; padding-top: 48px; }
.info-split__art { position: relative; display: flow-root; }
.info-split__one { display: block; width: 100%; margin-bottom: 35px; }
.info-split__two { position: absolute; left: 0; bottom: -40px; z-index: 2; width: 117%; max-width: none; }
.watermark--info { top: 190px; left: 0; line-height: 42px; transform: none; }
.info-split__text .title { margin-bottom: 16px; }
.info-split__text .divider { display: block; margin: 0 0 24px; }
.info-split__text .lead,
.info-split__text .text { margin-bottom: 40px; }
.info-split__text .btn-row { margin: 0 0 37px 5px; }
@media (min-width: 992px) {
  .info-split__media { width: 33.3333%; margin-bottom: 0; padding-bottom: 0; }
  .info-split__text { width: 58.3333%; margin-left: 8.3333%; padding-top: 0; }
  .info-split__text > :not(.watermark, .divider) { padding-left: 48px; }
  .info-split__text .divider { margin-left: 48px; }
  .info-split__text .eyebrow { margin-top: 48px; padding-top: 48px; }
  .info-split__text .btn-row { margin-left: 53px; padding-left: 0; }
}
@media (min-width: 1200px) {
  .info-split { margin-bottom: 110px; padding-bottom: 48px; }
  .info-split__media { width: 41.6667%; }
  .info-split__text { width: 41.6667%; }
}
@media (max-width: 575px) {
  .info-split { width: calc(0.9 * (100% - 12.8vw) + 30px); margin: 46px auto 60px; }
  .info-split__media { margin-bottom: 44.57px; padding-bottom: 44.57px; }
  .info-split__text { padding-top: 44.57px; }
  .info-split__text .eyebrow { margin-bottom: 7.43px; }
  .info-split__text .title { margin-bottom: 14.86px; }
  .info-split__text .divider { margin-bottom: 18px; }
  .info-split__text .lead,
  .info-split__text .text { margin-bottom: 37.14px; }
}

/* "Does Your Website Convert?" uses the same row, with a transparent square
   in place of 1.png (the original's Blank-1000.png) under the poster. Its
   content starts 89px under the blue box (the original's sat under the box),
   and 23px under the rule comes the dark band. */
.dywc-info .info-split { margin-top: 89px; }
.info-split__spacer { display: block; aspect-ratio: 1; }
.dywc-band { margin-top: 22px; }
@media (max-width: 575px) { .dywc-info .info-split { margin-top: 75.29px; } }

/* ---- components/svc-card.css ---- */
/* ---- service cards -----------------------------------------------------------
   Measured: white, 1px rgba(0,0,0,.06) border, padding 64px 48px 72px, a 75px
   icon, title Overpass 26.6px weight 700 line-height 1, strapline 14px/26px
   #777, all centred. Hover: the card turns #2a2a2a and everything white.
   Three per view on the home page (a carousel whose cards overlap the hero's
   grey strip by 80px), a 3 x 2 grid on /service/. */
.svc-card {
  height: 100%;
  padding: 64px 48px 72px;
  border: 1px solid var(--card-line);
  background: var(--white);
  text-align: center;
  transition: background-color var(--transition), color var(--transition);
}
.svc-card__icon {
  width: 75px;
  height: 75px;
  margin: 0 auto 40px;
  fill: var(--ink);
  transition: fill var(--transition);
}
.svc-card__title {
  margin: 0 0 1rem;
  font-size: 26.6px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--ls-tight);
}
.svc-card__title a { color: var(--ink); transition: color var(--transition); }
.svc-card__text { margin: 0; }
.svc-card:hover { background: var(--dark); color: var(--white); }
.svc-card:hover .svc-card__icon { fill: var(--white); }
.svc-card:hover .svc-card__title a { color: var(--white); }

/* The home row: 1100px of cards pulled up over the hero's strip. */
/* 90% of the row inside the 6.4vw inset, less the gutters: 1100px at 1440,
   748 at 992, 573 at 768 — the original's cards measured 350 / 362 / 274. */
.svc-row {
  position: relative;
  z-index: 1;
  width: calc(0.9 * (100% - 12.8vw) - 30px);
  margin: -183px auto 0;
}
/* Below 992px the original's cards start 30px under the hero band (73px
   above this section's top, which the stage's 103px overhang pushes down),
   and below 768px 170px under it; below 576px they take the whole 90%, with
   no gutters (measured 2026-10-13: 830px at 768, 770px and 306px wide at 390). */
.svc-row .svc-card { height: auto; }
@media (max-width: 991px) { .svc-row { margin-top: -73px; } }
@media (max-width: 767px) { .svc-row { margin-top: 67px; } }
@media (max-width: 575px) {
  .svc-row { width: calc(0.9 * (100% - 12.8vw)); }
  /* Porto's rem padding at its 14.86px rem (measured at 390: 59.43px 44.57px
     66.86px, the title 14.86px above the text). */
  .svc-card { padding: 59.43px 44.57px 66.86px; }
  .svc-card__title { margin-bottom: 14.86px; }
}

/* /service/: three cards to the row from 1170px, two from 768px, one below,
   each its own height, 20px apart, as on the original (measured 2026-10-14
   at 1199, 1170, 1169, 1024, 991, 768, 767, 576 and 390; service.css has
   the rest). */
.svc-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}
@media (min-width: 768px) { .svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1170px) { .svc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.svc-grid .svc-card { height: auto; }

/* ---- components/carousel.css ---- */
/* ---- carousels -------------------------------------------------------------
   One mechanism for the three places the original used an Owl carousel with
   several items in view (home service cards, about team): a scroll-snapping
   track. Without JS it is a strip you can swipe or scroll; 30-carousel.js adds
   the dots (12px hollow circles, the active one filled — measured) and moves
   the track a page at a time. */
.carousel { position: relative; }
.carousel__track {
  --per-view: 3;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - (var(--per-view) - 1) * 25px) / var(--per-view));
  gap: 25px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
}
.carousel__track::-webkit-scrollbar { display: none; }
.carousel__track > * { scroll-snap-align: start; }
/* A card only partly in view (the home strip's fourth, About's third from
   768 to 991px) at half strength, as the original's Owl items outside the
   view were (opacity .5, measured 2026-10-20). 30-carousel.js marks them. */
.carousel__track > .is-out { opacity: 0.5; }
/* Each card its own height (data-auto-height sizes the track to the
   tallest one in view). */
.carousel[data-auto-height] .carousel__track { align-items: start; overflow-y: hidden; transition: height 0.3s; }
.carousel[data-per-view="2"] .carousel__track { --per-view: 2; }
@media (max-width: 1199px) { .carousel__track { --per-view: 2; } }
@media (max-width: 575px) { .carousel__track { --per-view: 1; } }

/* The original's dots sat 20px under the cards, 12px circles 5px down in a
   30px row. Here each is a 24px target (the original's were 20 x 22), so
   the row is 19px down with 7px under it: the circles land where the
   original's did and the row is as tall. */
.carousel__dots {
  display: flex;
  justify-content: center;
  margin-top: 19px;
  padding-bottom: 7px;
}
@media (max-width: 575px) { .carousel__dots { padding-bottom: 5px; } }
.carousel__dots[hidden] { display: none; }
.carousel__dot {
  width: 24px;
  height: 24px;
  padding: 6px;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.carousel__dot::before {
  content: "";
  display: block;
  width: 12px;
  height: 12px;
  border: 1px solid var(--dark);
  border-radius: 50%;
  transition: background-color var(--transition);
}
.carousel__dot.is-active::before,
.carousel__dot:hover::before { background: var(--dark); }

/* One-at-a-time slides: the testimonials (their arrows are in quotes.css),
   fading in as the original's did. Without JS every slide shows, stacked. */
.js [data-slides] > * { display: none; }
.js [data-slides] > .is-active { display: block; animation: slide-in 0.6s ease; }
@keyframes slide-in { from { opacity: 0; } to { opacity: 1; } }

/* About's team arrows: the original's grey 24px chevrons in 30px boxes,
   55px outside the cards from 992px (10px below), their top 10px above the
   cards' middle (measured 2026-10-13). */
.carousel__arrow {
  position: absolute;
  top: calc(50% - 20px);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: none;
  color: #aaaaaa;
  cursor: pointer;
}
.carousel__arrow--prev { left: -55px; }
.carousel__arrow--next { right: -55px; }
@media (max-width: 991px) {
  .carousel__arrow--prev { left: -10px; }
  .carousel__arrow--next { right: -10px; }
}

/* ---- components/process.css ---- */
/* ---- process strip (home: 01 RESEARCH / 02 WORK / 03 DELIVERY) --------------
   Matched to the original on 2026-10-13 (client review), measured at 1512,
   1440, 1024, 991, 768 and 390px:
   - the row is inset 6.4vw each side, with 19px above it;
   - two image panels, 400px tall, share what the box leaves (flex 1 1 0) and
     hold the illustration as a parallax layer: 180% of the panel's height,
     cover-sized from its top centre, moved by 30-carousel.js as the panel
     crosses the window (the original's skrollr parallax, speed 1.8);
   - the dark #2a2a2a box is 40vw wide (50vw at 991px and below), overlaps each
     panel by 70px, is only as tall as its text and is centred on the panels;
   - at 767px and below the panels go and the box fills the inset row.
   The step number is 4.5em weight 900 at 10% opacity, centred behind the word
   (1.35em weight 300, 4.5px tracking). Steps 2 and 3 are white, as on the
   original. */
.process {
  display: flex;
  align-items: center;
  padding: 19px 6.4vw 0;
}
.process__side {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  height: 400px;
  overflow: hidden;
}
.process__side--a { background: #c6ccce; }
.process__side--b { background: #b0aca1; }
.process__side img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  max-width: none;
  height: 180%;
  object-fit: cover;
  object-position: 50% 0;
}
.process__panel {
  position: relative;
  z-index: 2;
  flex: 0 0 40vw;
  min-width: 0;
  margin: 0 -70px;
  padding: 48px;
  background: var(--dark);
  color: var(--white);
}

/* One step at a time, sliding sideways (the original's carousel: 20px apart,
   0.25s), the box as tall as the step showing and easing to the next one's
   height over 0.5s (its autoHeight; 30-carousel.js sets the height). Without
   JS the three steps simply stack. */
.steps { position: relative; }
.js .steps__viewport {
  overflow: hidden;
  touch-action: pan-y;
  transition: height 0.5s ease-in-out;
}
.js .steps__track {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  transition: transform 0.25s ease;
}
.js .steps__track.is-dragging { transition: none; user-select: none; }
.js .step { flex: 0 0 100%; min-width: 0; }
.step { padding: 24px 0 16px; }
.step__head {
  position: relative;
  margin: 0 0 24px;
  color: var(--white);
  font-size: 1.35em;
  font-weight: 300;
  line-height: 42px;
  letter-spacing: var(--ls-tight);
}
.step__num {
  position: absolute;
  top: 50%;
  left: 0;
  font-size: 4.5em;
  font-weight: 900;
  opacity: 0.1;
  transform: translateY(-50%);
}
.step__word { position: relative; letter-spacing: 4.5px; }
.step p { margin: 0; color: var(--white); font-size: 1.1em; line-height: 26px; }
/* Step 1's text: the original set it at 40% white and full white under the
   pointer. 40% on #2a2a2a is 3.6:1, below WCAG AA for this size, so it rests
   at 60% (6.2:1) here; the hover is the original's. Its 48px right padding
   and 16px margin are the original's too — steps 2 and 3 had neither. */
.step:first-child p { opacity: 0.6; transition: opacity 0.3s; }
.step:first-child p:hover { opacity: 1; }
@media (min-width: 992px), (max-width: 767px) {
  .step:first-child p { margin-right: 16px; padding-right: 48px; }
}

/* The only arrow: "next", drawn as a line and a chevron, at the box's right
   edge. It fades in (and slides 10px left) while the pointer is over the
   steps or the keyboard is in them, at half strength once the last step is
   showing. Dragging or swiping moves either way; so do the arrow keys. */
.steps__next {
  position: absolute;
  top: 50%;
  right: -7px;
  z-index: 2;
  width: 35px;
  height: 45px;
  padding: 0;
  border: 0;
  background: rgba(38, 42, 47, 0.4);
  color: var(--white);
  cursor: pointer;
  opacity: 0;
  transform: translate(10px, -50%);
  transition: opacity 0.2s, transform 0.4s, background-color 0.3s;
}
.steps__next::before {
  content: "";
  position: absolute;
  top: 23px;
  left: 17px;
  width: 11px;
  height: 11px;
  border-top: 2px solid;
  border-left: 2px solid;
  transform: translate(-50%, -50%) rotate(135deg);
}
.steps__next::after {
  content: "";
  position: absolute;
  top: 22px;
  left: 10px;
  width: 25px;
  border-top: 2px solid;
  transform: translateX(-50%);
}
.steps:hover .steps__next,
.steps:has(:focus-visible) .steps__next { opacity: 1; transform: translate(0, -50%); }
.steps:hover .steps__next[aria-disabled="true"],
.steps:has(:focus-visible) .steps__next[aria-disabled="true"] { opacity: 0.5; cursor: default; }
.steps__next:hover,
.steps__next:focus-visible { background-color: #1e1e1e; }

@media (max-width: 991px) { .process__panel { flex-basis: 50vw; } }
@media (max-width: 767px) {
  .process__side { display: none; }
  .process__panel { flex-basis: 100%; margin: 0; }
}
/* Below 576px the original's rem is 14.86px, so its 3rem / 1.5rem / 1rem
   spacing shrinks with it, and its text runs on 20px lines. */
@media (max-width: 575px) {
  .process__panel { padding: 44.57px; }
  .step { padding: 22.29px 0 14.86px; }
  .step p { line-height: 20px; }
  .step:first-child p { margin-right: 14.86px; padding-right: 44.57px; }
}

/* The client logos above the strip: their first row 87px below the rule
   (83px below 576px) and the last one 64px above the strip (59.43px below
   576px) — plus the logos' own 3rem bottom margin below 992px, where they
   wrap (logos.css; measured 2026-10-13). */
.section--before-process { padding: 86px 0 64px; }
@media (max-width: 575px) { .section--before-process { padding: 82px 0 59.43px; } }

/* The section after the strip ("Web Consulting") starts 2.5rem below it on
   the original: 40px, 37px below 576px (measured 2026-10-13). */
.process + .section { padding-top: 40px; }
@media (max-width: 575px) { .process + .section { padding-top: 37.14px; } }

/* ---- components/logos.css ---- */
/* ---- client logo strip -------------------------------------------------------
   Five (home) or six (about) small square logos, each centred in a Porto
   column with 15px gutters: six columns to the row from 1200px, three from
   576px, one below — left-aligned, so home's five leave the sixth place
   empty. Rows 48px apart (44.57px below 576px; none under the last row from
   992px). The original capped the logos by position: the first 90px
   (--sm), the fifth 100px (--md), the sixth 110px (--lg), the rest 140px
   (measured 2026-10-13 at 1512, 1024 and 390). */
.logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin: 0 -15px;
  padding: 0;
  list-style: none;
}
.logos__item { width: 100%; margin-bottom: 48px; padding: 0 15px; }
@media (min-width: 576px) { .logos__item { width: 33.3333%; } }
@media (min-width: 992px) { .logos__item:nth-child(n+4) { margin-bottom: 0; } }
@media (min-width: 1200px) { .logos__item { width: 16.6667%; margin-bottom: 0; } }
@media (max-width: 575px) { .logos__item { margin-bottom: 44.57px; } }
.logos__item img,
.logos__item a { display: block; width: 100%; max-width: 140px; margin: 0 auto; }
.logos__item a img { max-width: 100%; }
.logos__item--sm img,
.logos__item--sm a { max-width: 90px; }
.logos__item--md img,
.logos__item--md a { max-width: 100px; }
.logos__item--lg img,
.logos__item--lg a { max-width: 110px; }
.logos__item a { display: block; transition: opacity var(--transition); }
.logos__item a:hover { opacity: 0.75; }

/* ---- image stack (about split, "Does Your Website Convert?") -------------- */
.img-stack { position: relative; padding-bottom: 60px; }
.img-stack > img:first-child { position: relative; z-index: 1; width: 100%; }
.img-stack > img + img {
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 2;
  width: 62%;
}
@media (min-width: 992px) { .img-stack > img + img { right: -12%; } }

/* ---- components/portfolio.css ---- */
/* ---- project cards --------------------------------------------------------------
   .pcard — the original's "thumb-info" card (home, Web Design Consulting, Our
   Work): the image at its own aspect ratio, with the caption over its
   lower-left corner at rest. Measured: title box rgba(33,37,41,.8), padding
   13px 21px 2px, max 90% wide, Poppins 17px/26px weight 600, -0.85px; the
   category chip #2a2a2a, 10.2px weight 600 uppercase, hanging 15px below the
   title box. Hover: a 25% dark wash, the image zooms to 110%, the title box
   goes black.

   The whole card is one link, as on the original. */
.pcard {
  position: relative;
  display: block;
  overflow: hidden;
  color: var(--white);
}
.pcard__media { display: block; overflow: hidden; }
.pcard__media img {
  width: 100%;
  transition: transform 0.6s ease;
}
.pcard__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(23, 23, 23, 0.25);
  opacity: 0;
  transition: opacity var(--transition);
}
/* The dark box holds the title AND the category chip (which hangs 15px out
   of its foot), 13% up from the picture's foot (measured 2026-10-13). */
.pcard__caption {
  position: absolute;
  left: 0;
  bottom: 13%;
  z-index: 2;
  max-width: 90%;
  padding: 13px 21px 2px;
  background: var(--thumb-title);
  line-height: 0;     /* no strut: the chip's -15px margin then pulls the box up, as there */
  transition: background-color var(--transition);
}
.pcard__title {
  display: block;
  font-size: 17px;
  font-weight: 600;
  line-height: 26px;
  letter-spacing: -0.85px;
}
.pcard__type {
  display: inline-block;
  margin: 8px -2px -15px 0;
  padding: 2px 12px;
  background: var(--dark);
  font-size: 10.2px;
  font-weight: 600;
  line-height: 23.46px;
  text-transform: uppercase;
}
.pcard:hover { color: var(--white); }
.pcard:hover .pcard__media img { transform: scale(1.1); }
.pcard:hover .pcard__media::after { opacity: 1; }
.pcard:hover .pcard__caption { background: #000000; }
/* The original's link box: 50px, #212529 at 80%, sliding in to the
   picture's top-right corner under the pointer. */
.pcard__icon {
  position: absolute;
  top: -100px;
  right: -100px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  border-radius: 0 0 0 4px;
  background: var(--ink);
  color: var(--white);
  opacity: 0.8;
  transition: 0.3s;
}
.pcard:hover .pcard__icon,
.pcard:focus-visible .pcard__icon { top: 0; right: 0; }

@media (max-width: 991px) {
  .pcard__title { font-size: 14px; }
  .pcard__type { font-size: 8.4px; line-height: 19.32px; }
}
@media (max-width: 575px) { .pcard__title { line-height: 20px; } }

/* Screenshots (home "Web Consulting", Web Design Consulting), as the
   original's (measured 2026-10-14 at 1512, 1024, 768, 700, 576 and 390): two
   masonry columns 30px apart, each card into the shortest column
   (36-masonry.js); one column below 768px. Without JavaScript, plain rows. */
.pcard-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 30px;
  align-items: start;
}
@media (max-width: 767px) { .pcard-grid { grid-template-columns: 1fr; } }
.js .pcard-grid[data-masonry] { position: relative; display: block; }
.js .pcard-grid[data-masonry] > .pcard { position: absolute; top: 0; left: 0; width: calc((100% - 30px) / 2); }
@media (max-width: 767px) { .js .pcard-grid[data-masonry] > .pcard { width: 100%; } }
/* From 576 to 991px the original's two grids sit 15px further in each side
   (6.5vw + 15px from the window). */
@media (min-width: 576px) and (max-width: 991px) {
  .pcard-grid,
  .pcard-mosaic { margin-right: 15px; margin-left: 15px; }
}

/* Four columns of square portraits; the fifth card is 2 x 2 (home). */
.pcard-mosaic {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-flow: dense;
  gap: 30px;
}
.pcard-mosaic .pcard__media img { aspect-ratio: 1; object-fit: cover; }
.pcard--big { grid-column: span 2; grid-row: span 2; }
@media (max-width: 767px) { .pcard-mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) {
  .pcard-mosaic { grid-template-columns: 1fr; }
  .pcard--big { grid-column: auto; grid-row: auto; }
}

/* ---- Our Work ------------------------------------------------------------------------
   The original's Porto masonry (measured 2026-10-13 at 1512, 1024, 768 and
   390), in Porto's container (.pwrap, layout.css); four columns, three below 992px, two below 768, one below 576; each card
   the column less 15px a side, 30px under it, dropped into the shortest
   column (35-masonry.js) so the first row fills left to right. Without
   JavaScript the cards sit in plain rows.

   The card is the screenshot alone. Under the pointer (or focus) it zooms to
   110%; a white caption slides up 100px over its foot (15px padding;
   Poppins 17px/17px weight 600, -0.05em, #222529; the categories 10.2px
   weight 600 uppercase #777 — 14px and 8.4px below 992); a 50px #212529 box
   at 80% with the link glyph slides in to the top-right corner. */
.ow-grid { display: flex; flex-wrap: wrap; align-items: flex-start; margin: 0 -15px; }
.ow-grid > .owcard { width: 25%; }
@media (max-width: 991px) { .ow-grid > .owcard { width: 33.3333%; } }
@media (max-width: 767px) { .ow-grid > .owcard { width: 50%; } }
@media (max-width: 575px) { .ow-grid > .owcard { width: 100%; } }
.js .ow-grid[data-masonry] { position: relative; display: block; }
.js .ow-grid[data-masonry] > .owcard { position: absolute; top: 0; left: 0; }

.owcard { display: block; padding: 0 15px 30px; color: var(--body); }
.owcard__media { position: relative; display: block; overflow: hidden; }
.owcard__media img { width: 100%; transition: transform 0.3s; }
.owcard__info {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 2;
  width: 100%;
  padding: 15px;
  background: var(--white);
  font-size: 17px;
  font-weight: 600;
  line-height: 26px;
  letter-spacing: -0.85px;
  opacity: 0;
  transform: translate3d(0, 100px, 0);
  transition: transform 0.2s ease-out, opacity 0.2s ease-out;
}
.owcard__title { display: block; color: var(--ink-soft); line-height: 1; }
.owcard__type {
  display: inline-block;
  color: var(--body);
  font-size: 10.2px;
  line-height: 23.46px;
  letter-spacing: normal;
  text-transform: uppercase;
}
.owcard__icon {
  position: absolute;
  top: -100px;
  right: -100px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  border-radius: 0 0 0 4px;
  background: var(--ink);
  color: var(--white);
  opacity: 0.8;
  transition: 0.3s;
}
.owcard:hover .owcard__media img,
.owcard:focus-visible .owcard__media img { transform: scale(1.1); }
.owcard:hover .owcard__info,
.owcard:focus-visible .owcard__info { opacity: 1; transform: none; }
.owcard:hover .owcard__icon,
.owcard:focus-visible .owcard__icon { top: 0; right: 0; }
@media (max-width: 991px) {
  .owcard__info { font-size: 14px; letter-spacing: -0.7px; }
  .owcard__type { font-size: 8.4px; line-height: 19.32px; }
}
@media (max-width: 575px) { .owcard__info { line-height: 20px; } }

/* Porto's "style 3" filter: centred, 0.8em uppercase #777 with 6px 12px
   padding, the current one #2a2a2a over a 3px rule; 2rem under it. */
.filter-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0 0 32px;
  font-size: 0.8em;
  text-transform: uppercase;
}
.filter-tabs a { display: inline-block; padding: 6px 12px; color: var(--body); }
.filter-tabs a.is-current { border-bottom: 3px solid var(--dark); color: var(--dark); }
@media (max-width: 575px) { .filter-tabs { margin-bottom: 29.71px; } }

/* ---- archive tiles (/projects/ and the category pages) ---------------------------
   The image alone at rest, at its own proportions; on hover or focus a
   rgba(33,37,41,.8) wash with the title and categories centred, and the image
   zooms. Three columns from 1170px, two from 768, one below; 20px gaps — the
   original's own breakpoints (measured 2026-10-13). Fixed counts, not
   auto-fill: auto-fill made four smaller columns from about 1490px wide (a
   MacBook's 1512), where the original keeps three. */
.tile-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}
@media (min-width: 768px) { .tile-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1170px) { .tile-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ptile {
  position: relative;
  display: block;
  overflow: hidden;
  color: var(--white);
}
.ptile img { width: 100%; transition: transform 0.6s ease, opacity 0.6s ease; }
.ptile__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(33, 37, 41, 0.8);
  text-align: center;
  opacity: 0;
  transition: opacity var(--transition);
}
/* The original's caption (measured 2026-10-13): the title Overpass 1.8em
   (25.2px) / 1.2 weight 700, -0.05em, left-aligned within a centred box; the
   categories 0.9em (12.6px) / 26px weight 600, uppercase, #969696. */
.ptile__title {
  font-family: var(--font-head);
  font-size: calc(var(--fs-body) * 1.8);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: var(--ls-tight);
  text-align: left;
  transform: translateY(-5px);
  transition: transform var(--transition);
}
.ptile__type { color: #969696; font-size: calc(var(--fs-body) * 0.9); font-weight: 600; line-height: 26px; text-transform: uppercase; }
.ptile:hover,
.ptile:focus-visible { color: var(--white); }
.ptile:hover img,
.ptile:focus-visible img { transform: scale(1.1); opacity: 0.9; }
.ptile:hover .ptile__overlay,
.ptile:focus-visible .ptile__overlay { opacity: 1; }
.ptile:hover .ptile__title,
.ptile:focus-visible .ptile__title { transform: none; }
/* Touch screens have no hover: show the caption, or the grid is unlabelled. */
@media (hover: none) {
  .ptile__overlay { top: auto; opacity: 1; background: var(--thumb-title); }
  .ptile__title { transform: none; }
}

/* The archive heading above the grid: 24px from the title to the hatched
   bar and 66px from the bar to the category filter (56px below 576px), as
   on the original (measured 2026-10-13). */
.section-head--archive { margin-bottom: 66px; }
/* 24px, not 8px: it collapses with the title's own 16px margin. */
.section-head--archive .divider { margin-top: 24px; }
@media (max-width: 575px) {
  .section-head--archive { margin-bottom: 56px; }
  .section-head--archive .divider { margin-top: 22.86px; }
}

/* The original set its "Load More..." in capitals with CSS, 60px below the
   last row (measured 2026-10-13). */
.tile-grid + .btn-row { margin-top: 60px; }
.btn[data-load-more] { text-transform: uppercase; }
/* Without JS every tile already shows, so the button would do nothing. */
html:not(.js) .btn-row:has([data-load-more]),
html:not(.js) [data-load-more] { display: none; }

/* About: three photos that link to their project pages. */
.photo-link { display: block; overflow: hidden; }
.photo-link img { width: 100%; transition: transform 0.6s ease, opacity var(--transition); }
.photo-link:hover img { transform: scale(1.05); opacity: 0.9; }

/* Hidden by 45-load-more.js until "Load More..." reveals it. */
.is-deferred { display: none; }

/* ---- category filter bar ------------------------------------------------------------
   Measured: centred, Poppins 14.4px weight 600, line-height 28px, uppercase,
   #2a2a2a on white; the current category underlined with 1px #2a2a2a. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0;   /* the items touch side by side and wrapped rows touch, as on the original */
  margin: 0 0 24px;
}
.filter-bar a {
  display: inline-block;
  padding: 6px 12px;
  border-bottom: 1px solid transparent;
  color: var(--dark);
  font-size: calc(var(--fs-body) * 1.0286);   /* 14.4px; 13.37px below 576 */
  font-weight: 600;
  line-height: 28px;
  text-transform: uppercase;
}
.filter-bar a:hover,
.filter-bar a.is-current { border-bottom-color: var(--dark); color: var(--dark); }

/* ---- components/cta.css ---- */
/* ---- the dark call-to-action band --------------------------------------------
   The original's (measured 2026-10-13 at 1512, 1024 and 390): #2a2a2a, the
   6.4vw-inset width, padding 75px 32px (69.65px 29.71px below 576px, at
   Porto's 14.86px rem). Inside, Porto columns with 15px gutters: from 1200px
   the text takes 9/12 and the button 3/12, side by side, all left-aligned;
   below that the text takes 8/12, centred, with 24px under it, and the
   button a full row — still at the LEFT, as the original's button container
   was. Eyebrow 16.8px weight 600 #777 on a 42px line, no gap under it; title
   Overpass 35px weight 900 white, -0.05em, 1.2 line-height. */
.cta-band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  margin: 0 calc(-1 * var(--gutter));
  padding: 75px 32px;
  background: var(--dark);
  text-align: center;
}
.cta-band__text { width: 100%; min-width: 0; margin-bottom: 24px; padding: 0 15px; }
.cta-band__action { width: 100%; margin: 0; padding: 0 15px; text-align: left; }
@media (min-width: 768px) { .cta-band__text { width: 66.6667%; } }
@media (min-width: 1200px) {
  .cta-band { text-align: left; }
  .cta-band__text { width: 75%; margin-bottom: 0; }
  .cta-band__action { width: 25%; }
}
.cta-band .eyebrow { margin: 0; color: var(--body); font-weight: 600; line-height: 42px; opacity: 1; }
.cta-band__title {
  margin: 0;
  color: var(--white);
  font-size: var(--fs-cta);
  font-weight: 900;
  line-height: 1.2;
  letter-spacing: var(--ls-tight);
}
@media (max-width: 575px) {
  .cta-band { margin: 0; padding: 69.65px 14.71px; }
  .cta-band__text { margin-bottom: 22.29px; }
}

/* ---- sidebars (service and project pages) ------------------------------------------ */
.side-card {
  padding: 48px 24px;
  border: 1px solid var(--card-line);
}
/* The project pages' card: the bulb at the card's full width, 35px of white
   under it inside the frame, the dark box 37px below (measured 2026-10-13). */
.side-card.side-card--logo { padding: 0 0 35px; }
.side-card--logo img { width: 100%; margin: 0 auto; }
.side-card--logo + .side-cta { margin-top: 37px; }

/* Overpass 21px weight 700, #2c2c2c; a 2px underline grows under the item
   hovered and stays under the current page's. */
.side-menu { margin: 0; padding: 0; list-style: none; }
.side-menu li { line-height: 24px; }
.side-menu li + li { margin-top: 22px; }
.side-menu a {
  position: relative;
  display: inline-block;
  padding: 0 0 4px;
  color: #2c2c2c;
  font-family: var(--font-head);
  font-size: 1.5em;
  font-weight: 700;
  line-height: 21px;
}
.side-menu a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background: var(--dark);
  transition: width var(--transition);
}
.side-menu a:hover::after,
.side-menu a.is-current::after { width: 100%; }

/* 34px below the card above it (measured 2026-10-13); its button sits at the
   left of the box under the centred title, as on the original. */
.side-cta {
  margin-top: 34px;
  padding: 4rem 3rem;
  background: var(--dark);
  text-align: center;
}
.side-cta__title {
  margin: 0 0 24px;
  padding-bottom: 16px;
  color: var(--white);
  font-size: var(--fs-h2);
  font-weight: 800;
  line-height: 1.4;
  letter-spacing: var(--ls-tight);
}
.side-cta p { margin: 0; text-align: left; }
/* Below 576px the boxes' rem padding shrinks with Porto's 14.86px rem
   (measured 2026-10-13 at 390: 357px and 407px tall). */
@media (max-width: 575px) {
  .side-card { padding: 44.57px 22.29px; }
  .side-cta { margin-top: 32.86px; padding: 59.43px 44.57px; }
  .side-cta__title { margin-bottom: 22.29px; padding-bottom: 14.86px; }
}

/* ---- components/faq.css ---- */
/* ---- FAQ block (home, /service/, "Does Your Website Convert?") ---------------------
   The original's Porto row (measured 2026-10-13 at 1512 and 1024): the intro
   4/12 and the questions 8/12 from 1200px, 5/12 and 7/12 from 992px, one
   above the other below (48px apart), 15px gutters. Each question a #f7f7f7
   bar, Overpass 16px/25px weight 700, -0.8px, padding 10px 16px, inside a
   4px #f7f7f7 frame with 4px corners and 5px between items; its chevron was
   drawn in the bar's own colour, so none shows. The answer padded 32px 32px
   32px 24px and no wider than 690px. <details> gives the open/close with no
   script. */
.faq-block {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  margin: 0 -15px;
}
.faq-block__intro,
.faq-block__list { position: relative; width: 100%; min-width: 0; padding: 0 15px; }
.faq-block__intro { margin-bottom: 48px; }
@media (min-width: 992px) {
  .faq-block__intro { width: 41.6667%; margin-bottom: 0; }
  .faq-block__list { width: 58.3333%; }
}
@media (min-width: 1200px) {
  .faq-block__intro { width: 33.3333%; }
  .faq-block__list { width: 66.6667%; }
}
@media (max-width: 575px) { .faq-block__intro { margin-bottom: 44.57px; } }
.faq-block__intro .watermark { top: 102px; left: -246px; line-height: 42px; transform: none; }
/* The intro's own spacing (measured 2026-10-13): 33px from the title to the
   hatched divider and 24px under it, 32px under each paragraph (Porto's
   pb-2 + mb-4), the button 5px in — 29px, 18px and 29.71px below 576px. */
.faq-block__intro .title { margin-bottom: 33px; }
.faq-block__intro .divider { display: block; margin-bottom: 24px; }
.faq-block__intro .lead,
.faq-block__intro .text { margin-bottom: 32px; }
.faq-block__intro .btn-row { margin-left: 5px; }
@media (max-width: 575px) {
  .faq-block__intro .title { margin-bottom: 29px; }
  .faq-block__intro .divider { margin-bottom: 18px; }
  .faq-block__intro .lead,
  .faq-block__intro .text { margin-bottom: 29.71px; }
}

.faq-list { display: grid; gap: 5px; }
.faq {
  border: 4px solid var(--grey-soft);
  border-radius: 4px;
}
.faq__q {
  position: relative;
  display: block;
  padding: 10px 16px;
  background: var(--grey-soft);
  color: var(--dark);
  font-family: var(--font-head);
  font-size: 1rem;
  font-weight: 700;
  line-height: 25px;
  letter-spacing: -0.8px;
  cursor: pointer;
  list-style: none;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__a { max-width: 690px; padding: 32px 32px 32px 24px; }
.faq__a p { margin: 0; }
.faq__a p + p { margin-top: 1em; }

/* ---- the FAQ page: Porto's default toggles (measured 2026-10-13 at 1512,
   1024, 768 and 390) ---------------------------------------------------------
   In Porto's container (.pwrap). The heading Overpass 30px/42px weight 900,
   -1.5px, "Questions" weight 700, 32px above the list (27.86px/40px below
   576px). Each question: 10px below the one above, a #f5f5f5 bar with a 3px
   #2a2a2a rule on its left, Poppins 15.4px/26px weight 600 #2a2a2a (14.3px/
   20px below 576px), padding 12px 20px 12px 15px, #fbfbfb under the
   pointer, and a small chevron pointing up at the right. Open: the bar
   #2a2a2a with white text, the chevron white and pointing down, the answer
   on the page below it with 10px above and below. All closed on load; any
   number open at once. The footer 40px after the last. */
.section--faqs { padding-bottom: 40px; }
.faqs-title {
  margin: 0 0 32px;
  color: var(--ink-soft);
  font-size: 30px;
  font-weight: 900;
  line-height: 42px;
  letter-spacing: -1.5px;
}
.faqs-title strong { font-weight: 700; }
.toggle { padding-bottom: 10px; }
.toggle__q {
  position: relative;
  display: block;
  padding: 12px 20px 12px 15px;
  border-left: 3px solid var(--dark);
  background: #f5f5f5;
  color: var(--dark);
  font-size: 1.1em;
  font-weight: 600;
  line-height: 26px;
  cursor: pointer;
  list-style: none;
  transition: 0.15s ease-out;
}
.toggle__q::-webkit-details-marker { display: none; }
.toggle__q:hover { background: #fbfbfb; }
.toggle__q::before {
  content: "";
  position: absolute;
  top: calc(50% + 2px);
  right: 14px;
  width: 8px;
  height: 8px;
  border-top: 1px solid;
  border-right: 1px solid;
  transform: translate3d(0, -50%, 0) rotate(-45deg);
  transition: transform 0.3s, top 0.3s;
}
.toggle[open] > .toggle__q { background: var(--dark); color: var(--white); }
.toggle[open] > .toggle__q::before { top: calc(50% - 6px); transform: rotate(135deg); }
.toggle__a { padding: 10px 0; }
@media (max-width: 575px) {
  .faqs-title { font-size: 27.86px; line-height: 40px; }
  .toggle__q { line-height: 20px; }
}

/* The answer pages: the answer as plain body text in Porto's container,
   paragraphs 20px apart (18.57px below 576px) — the original's (measured
   2026-10-13). With the section's 40px, the footer comes 60px after the
   last line, as there. */
.faq-content p { margin: 0 0 20px; }
@media (max-width: 575px) { .faq-content p { margin-bottom: 18.57px; } }

/* "Does Your Website Convert?": 96px from the band to the questions (89.14px
   below 576px); after them the original's row padding and margin and two
   100px empty spaces — 264px from the intro's button (or the list's own
   35px margin, below 992px, where the list comes last) to a faint rule on
   the footer's edge (measured 2026-10-13). */
.section--dywc-faq { padding: 96px 0 264px; }
.section--dywc-faq .faq-block__list { margin-bottom: 35px; }
@media (max-width: 575px) { .section--dywc-faq { padding: 89.14px 0 259.43px; } }

/* ---- components/quotes.css ---- */
/* ---- testimonials ------------------------------------------------------------------
   Matched to the original on 2026-10-13 (client review), measured from 1512
   down to 390px.

   The row is inset 6.4vw each side and the #2a2a2a box fills it. Over 991px
   the row starts at 40% of the page width and widens to 100% as it scrolls
   into view (the original's "scroll parallax"; 35-grow.js), with the box's
   content clipped at its edges while it is narrow. On the home page the box
   sits directly on the footer, which is the same colour, so the two read as
   one dark shape.

   Inside: 48px above and below; the heading block 48px from its neighbours
   with 16px more above it; the eyebrow white at 60%, the heading 38.5px
   weight 900 with -1px tracking; the quotes in a column 75% as wide as an
   inner block of 1440 / 960 / 720 / 540px by screen width (wider than the box
   at some widths, as on the original); each quote Overpass italic 300 at
   1.35em/1.6, white at 80% and full white under the pointer, with its quote
   mark at the top left; the name 16.8px bold white, the role 12.8px weight
   600 white at 60%. */
.quotes-row { margin: 0 auto; padding: 0 6.4vw; }
@media (min-width: 992px) { .js .quotes-row { transition: width 0.2s ease; } }

.quotes-box {
  overflow: hidden;
  padding: 48px 0;
  background: var(--dark);
  color: var(--white);
  text-align: center;
}
.quotes-box__inner {
  --qw: calc(100% + 30px);
  width: var(--qw);
  margin: 0 calc(50% - var(--qw) / 2);
}
@media (min-width: 576px) { .quotes-box__inner { --qw: max(100%, 540px); } }
@media (min-width: 768px) { .quotes-box__inner { --qw: max(100%, 720px); } }
@media (min-width: 992px) { .quotes-box__inner { --qw: 960px; } }
@media (min-width: 1200px) { .quotes-box__inner { --qw: 1440px; } }

.quotes-box__head {
  width: 91.6667%;
  margin: 48px auto;
  padding: 16px 15px 0;
}
@media (min-width: 768px) { .quotes-box__head { width: 100%; } }
.quotes-box__head .eyebrow { margin: 0 0 16px; }
.quotes-box__head .title { margin: 0; letter-spacing: -1px; }

.quotes {
  width: 75%;
  margin: 0 auto 26px;
  padding: 0 15px 16px;
}
.quotes__carousel { position: relative; display: flow-root; }
.quote { margin: 0 0 20px; }
.quote blockquote {
  position: relative;
  margin: 0;
  padding: 22px 20px;
}
.quote blockquote::before {
  content: "";
  position: absolute;
  top: 0;
  left: 10px;
  width: 19.6px;
  height: 22.4px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M0 216C0 149.7 53.7 96 120 96h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V216zm256 0c0-66.3 53.7-120 120-120h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H320c-35.3 0-64-28.7-64-64V216z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M0 216C0 149.7 53.7 96 120 96h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V216zm256 0c0-66.3 53.7-120 120-120h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H320c-35.3 0-64-28.7-64-64V216z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.quote blockquote p {
  margin: 0;
  padding: 0 16px;
  font-family: var(--font-head);
  font-size: 1.35em;
  font-style: italic;
  font-weight: 300;
  line-height: 1.6;
  opacity: 0.8;
  transition: opacity 0.3s;
}
.quote blockquote p:hover { opacity: 1; }
.quote figcaption { margin-top: 6px; line-height: 1.2; }
.quote figcaption strong {
  display: block;
  margin-bottom: 2px;
  color: var(--white);
  font-size: 16.8px;
  font-weight: 700;
}
.quote figcaption span {
  display: block;
  color: var(--white);
  font-size: 12.8px;
  font-weight: 600;
  opacity: 0.6;
}

/* About, from 768 to 991px: both quotes side by side, half the column each,
   top-aligned, and no arrows — the original's About carousel shows two items
   in that band (md: 2; one above and below it, and one at every width on the
   home page), and Owl hides its arrows when every item is in view (measured
   2026-10-20 at 768: quote text 179px wide at x 167 and 422). */
@media (min-width: 768px) and (max-width: 991px) {
  .js .quotes-row--pair [data-slides] { display: flex; align-items: flex-start; }
  .js .quotes-row--pair [data-slides] > * { display: block; flex: 0 0 50%; min-width: 0; animation: none; }
  .quotes-row--pair .slides-arrow { display: none; }
}

/* About: the original's spacing around the row (measured 2026-10-13) — 86px
   from the team's button above it (81px below 576px), 64px down to the
   client logos (59px), and from the logos to the footer 48px (44.43px below
   576px) — plus the logos' own 3rem bottom margin below 992px, where they
   wrap (logos.css). */
.section--before-quotes { padding-bottom: 86px; }
.section--after-quotes { padding: 64px 0 48px; }
@media (max-width: 575px) {
  .section--before-quotes { padding-bottom: 81px; }
  .section--after-quotes { padding: 59px 0 44.43px; }
}

/* The arrows (30-carousel.js): thin white chevrons 53px outside the quote,
   centred 15px above its middle; hidden until the pointer is in the quotes,
   then sliding 10px in. Keyboard focus shows them too; focus left by a click
   does not, so they go when the pointer leaves, as on the original. */
.slides-arrow {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-top: -30px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--white);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s, transform 0.4s;
}
.slides-arrow--prev { left: -53px; transform: translateX(-10px); }
.slides-arrow--next { right: -53px; transform: translateX(10px); }
.quotes:hover .slides-arrow,
.quotes:has(:focus-visible) .slides-arrow { opacity: 1; transform: none; }
.quotes:hover .slides-arrow[aria-disabled="true"],
.quotes:has(:focus-visible) .slides-arrow[aria-disabled="true"] { opacity: 0.5; cursor: default; }

@media (max-width: 991px) {
  .slides-arrow--prev { left: -33px; }
  .slides-arrow--next { right: -33px; }
}
/* Below 576px: the original's rem is 14.86px, the quote marks go, and the
   arrows sit 10px outside the quote. */
@media (max-width: 575px) {
  .quotes-box { padding: 44.57px 0; }
  .quotes-box__head { margin: 44.57px auto; padding-top: 14.86px; }
  .quotes-box__head .eyebrow { margin-bottom: 14.86px; }
  .quotes { padding-bottom: 14.86px; }
  .quote blockquote::before { display: none; }
  .quote blockquote p { padding: 0 14.86px; }
  .quote figcaption span { font-size: 11.89px; }
  .slides-arrow--prev { left: -10px; }
  .slides-arrow--next { right: -10px; }
}

/* ---- components/team.css ---- */
/* ---- team ----------------------------------------------------------------------------
   The original's member card (About and the Members archive; measured
   2026-10-13 at 1512, 1024 and 390): a 1px rgba(0,0,0,.06) frame; the square
   picture at the card's width, zooming to 110% under the pointer, with a
   30px #2a2a2a magnifier in its bottom-right corner that opens it; then,
   with 32px 32px 12px padding, the name in Overpass 21px/27px weight 800,
   -0.05em, #222529, the role in Overpass 15.4px/24px #777, 12px under it,
   and the note at 14px/26px weight 300 with 20px under it — Porto's rem
   padding and 19.5px name below 576px. */
.member-card { position: relative; border: 1px solid var(--card-line); background: var(--white); text-align: center; }
.member-card__media { position: relative; }
.member-card__photo { display: block; overflow: hidden; }
.member-card__photo img { width: 100%; transition: transform 0.3s; }
.member-card:hover .member-card__photo img { transform: scale(1.1); }
.member-card__zoom {
  position: absolute;
  right: 4px;
  bottom: 4px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--dark);
  color: var(--white);
  cursor: pointer;
}
.member-card__body { padding: 32px 32px 12px; }
.member-card__name {
  margin: 0 0 4px;
  font-size: 21px;
  font-weight: 800;
  line-height: 27px;
  letter-spacing: -0.05em;
}
.member-card__name a { color: var(--ink-soft); }
.member-card__role { margin: 0 0 12px; font-family: var(--font-head); font-size: 1.1em; line-height: 24px; }
.member-card .member-card__note { margin: 0 0 20px; font-weight: 300; line-height: 26px; }
@media (max-width: 575px) {
  .member-card__body { padding: 29.71px 29.71px 11.14px; }
  .member-card__name { font-size: 19.5px; line-height: 20.77px; }
  .member-card .member-card__note { margin-bottom: 18.57px; }
}

/* About's team row: the cards 7/12 from 1200px (6/12 from 992px), centred
   in what the text's 4/12 (5/12) leaves, one above the other below 992px,
   48px apart; the text right-aligned, its outlined "AdLiBb" 90px down. The
   carousel: two cards in view from 768px, one below, 20px apart, grey
   chevrons 55px outside it (10px below 992px), no dots. 96px from the rule
   above to the row (89.14px below 576px). */
.section--team { padding: 95px 0 64px; }
.team-row { display: flex; flex-wrap: wrap; margin: 0 -15px; }
.team-row__cards,
.team-row__text { position: relative; width: 100%; min-width: 0; padding: 0 15px; }
.team-row__cards { margin-bottom: 48px; }
.team-row__text { text-align: right; }
@media (min-width: 992px) {
  .team-row__cards { width: 50%; margin: 0 auto; }
  .team-row__text { width: 41.6667%; }
}
@media (min-width: 1200px) {
  .team-row__cards { width: 58.3333%; }
  .team-row__text { width: 33.3333%; }
}
.watermark--team { top: 90px; left: 15px; line-height: 42px; transform: none; }
.team-row__text .title { margin-bottom: 32px; }
.team-row__text .divider { display: block; margin: 0 0 33px auto; }
.team-row__text .text { margin-bottom: 40px; }
.team-row__text .btn-row { margin: 0 5px 22px 0; }
@media (max-width: 575px) {
  .section--team { padding: 88.14px 0 59.43px; }
  .team-row__cards { margin-bottom: 44.57px; }
  .team-row__text .title { margin-bottom: 29.72px; }
  .team-row__text .divider { margin-bottom: 27px; }
  .team-row__text .lead { margin-bottom: 22.29px; }
  .team-row__text .text { margin-bottom: 37.14px; }
}
.carousel--team { padding-bottom: 20px; }
.carousel--team .carousel__track {
  --per-view: 2;
  grid-auto-columns: calc((100% - 20px) / 2);
  gap: 20px;
  padding-bottom: 20px;
}
@media (max-width: 767px) {
  .carousel--team .carousel__track { --per-view: 1; grid-auto-columns: 100%; }
}

/* The Members archive: three cards to the row from 1200px, two from 768px,
   one below, 20px apart side by side and 40px between rows (measured
   2026-10-13). */
.member-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 40px 20px; align-items: start; }
@media (min-width: 768px) { .member-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .member-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* A member's page (measured 2026-10-13 at 1512, 1024 and 390): Porto's
   container; the picture 5/12 on the right from 768px (first and full width
   below), with no frame, the magnifier in its corner and 30px under it; the
   name again in Overpass 30px/42px weight 900 (the name itself 700), the role
   14px/27px weight 700 uppercase #2a2a2a, the note, in the 7/12 on the left.
   The bio 62px under the picture. The section starts 62px under the blue box
   (the original's 30px + 32px, which there sat under the box) and ends 40px
   under the bio. */
.section--member { padding: 62px 0 40px; }
.member-profile { display: flex; flex-wrap: wrap; margin: 0 -15px; }
.member-profile__photo,
.member-profile__text { position: relative; width: 100%; min-width: 0; padding: 0 15px; }
.member-profile__photo { margin-bottom: 24px; padding-bottom: 30px; }
.member-profile__photo img { width: 100%; }
.member-profile__photo .member-card__zoom { right: 19px; bottom: 34px; }
@media (min-width: 768px) {
  .member-profile__photo { order: 2; width: 41.6667%; }
  .member-profile__text { width: 58.3333%; }
}
@media (min-width: 992px) { .member-profile__photo { margin-bottom: 0; } }
.member-profile__name {
  margin: 0;
  color: var(--ink-soft);
  font-size: 30px;
  font-weight: 900;
  line-height: 42px;
  letter-spacing: -1.5px;
}
.member-profile__name strong { font-weight: 700; }
.member-profile__role {
  margin: 0 0 14px;
  color: var(--dark);
  font-family: var(--font-head);
  font-size: 14px;
  font-weight: 700;
  line-height: 27px;
  letter-spacing: -0.7px;
  text-transform: uppercase;
}
.member-profile .member-profile__note { margin: 0 0 20px; }
.member-profile__bio { margin-top: 32px; }
@media (max-width: 575px) {
  .section--member { padding-top: 59.71px; }
  .member-profile__photo { margin-bottom: 22.29px; }
  .member-profile__name { font-size: 27.86px; line-height: 40px; }
  .member-profile__role { font-size: 13px; line-height: 20.77px; }
  .member-profile .member-profile__note { margin-bottom: 18.57px; }
  .member-profile__bio { margin-top: 29.71px; }
}

/* ---- About: the intro's spacing (measured 2026-10-13) ---------------------------
   24px from the hatched divider to the lead; 40px above and below the three
   photographs (Porto's pb-3 + mb-4), which sit three across from 768px with
   30px gutters, one above another below that 24px apart; the last two
   paragraphs run on with no gap; 96px from the last to the rule. */
.section-head--about { margin-bottom: 0; }
.photo-row3 { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; margin: 40px 0; }
@media (min-width: 768px) { .photo-row3 { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 30px; } }
.photo-row3 img { width: 100%; }
.text--flush { margin-bottom: 0; }
.section--about-intro { padding-bottom: 96px; }
@media (max-width: 575px) { .section--about-intro { padding-bottom: 89.14px; } }
@media (max-width: 575px) {
  .photo-row3 { gap: 22.29px; margin: 37.14px 0; }
}

/* The Members archive: the cards 93px below the blue box (79px below 576px)
   and 122px above the footer (116px) — the original's (measured 2026-10-13). */
.section--members { padding: 93px 0 122px; }
@media (max-width: 575px) { .section--members { padding: 79px 0 116px; } }

/* ---- components/project.css ---- */
/* ---- project pages --------------------------------------------------------------------
   Measured (2026-10-13, the Larkin page at 1512): the text starts 177px
   under the banner band, as on the service pages; the subtitle Poppins
   21px/29.4px #777; the details padded 48px 24px with no frame, each a label
   14px weight 300 #777 over a value Overpass 21px weight 700 #212529 — the
   first 25.2px — 16px apart; paragraphs 15.4px/26px; the "Visit Site" button
   centred, 56px under the text and 20px above; 32px further down "Website Highlights", Overpass
   30px weight 900, -1.5px, typed out letter by letter; the screenshots in
   two columns 25px apart; 52.5px from the last to the footer (the photo
   galleries: 50px). The photos at a fixed 353px height, as the original
   cropped them. Below 992px the sidebar comes last, 40px after the photos
   or 32.5px after the screenshots, and ends 49px above the footer. */
.section--project { padding: 74px 0 40px; }
@media (max-width: 991px) { .section--project { padding-bottom: 49px; } }
@media (max-width: 575px) { .section--project { padding-top: 62.79px; } }
.project { min-width: 0; }
.project__sub { margin: 0 0 24px; font-size: 1.5em; line-height: 1.4; }

.project-meta {
  margin: 0;
  padding: 48px 24px;
}
.project-meta div + div { margin-top: 16px; }
.project-meta dt { font-size: 14px; font-weight: 300; line-height: 24px; }
.project-meta dd {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-head);
  font-size: 1.5em;
  font-weight: 700;
  line-height: 24px;
}
.project-meta div:first-child dd { font-size: 1.8em; }

/* Padding, not margins: the original's button sat in a row of its own, 32px
   below the text's 24px and 20px above the gallery row's own 32px. */
.project__visit { margin: 0; padding: 32px 0 20px; text-align: center; }

.type-heading {
  min-height: 37px;
  margin: 32px 0 29.5px;
  color: var(--ink-soft);
  font-size: 30px;
  font-weight: 900;
  line-height: 37px;
  letter-spacing: -1.5px;
  text-align: center;
}
.type-heading.is-typing::after {
  content: "";
  display: inline-block;
  width: 2px;
  height: 0.9em;
  margin-left: 2px;
  vertical-align: -0.1em;
  background: currentColor;
  animation: caret 0.8s steps(1) infinite;
}
@keyframes caret { 50% { opacity: 0; } }

.shots {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--shots-gap, 25px);
  align-items: start;
  /* A wider gap on the original also moved the first row down, and the
     footer, by half the difference. */
  padding: calc((var(--shots-gap, 25px) - 25px) / 2) 0;
}
/* Mathieu Lapensee Construction's screenshots were 29px apart on the
   original ("galleryGap" in projects.json; measured 2026-10-14). */
.shots--gap-29 { --shots-gap: 29px; }
@media (min-width: 992px) { .shots { margin-bottom: 12.5px; } }
.shots .gallery-item img { height: 353px; object-fit: cover; object-position: top; }
@media (max-width: 575px) { .shots { grid-template-columns: 1fr; } }

/* The photo projects' galleries: the original's Porto masonry (measured
   2026-10-13 on Besner Clan): each photo 353px tall at its own proportions
   with 10px around it, packed by 36-masonry.js on a 60-column grid to the
   highest place it fits (the leftmost on a tie) — so a narrow photo fills
   the gap beside a wide one higher up. Without JavaScript, or 1000px wide
   or less, one under another at the column's width; 768px or less at
   their own height. */
.photo-row { position: relative; display: flex; flex-wrap: wrap; margin: -10px -10px 10px; }
.photo-row .gallery-item { display: block; padding: 10px; }
.photo-row .gallery-item img { width: auto; height: 353px; max-width: 100%; object-fit: cover; }
.photo-row.is-packed { display: block; }
.photo-row.is-packed .gallery-item { position: absolute; top: 0; left: 0; }
@media (max-width: 991px) { .photo-row { margin-bottom: -2.5px; } }
@media (max-width: 1000px) {
  .photo-row .gallery-item { width: 100%; }
  .photo-row .gallery-item img { width: 100%; }
}
@media (max-width: 768px) {
  .photo-row .gallery-item img { height: auto; }
}

/* Below 576px (measured 2026-10-13 at 390): the screenshots and the photos
   run 5px wider than the text each side (320px at 390), the gallery heading 27.86px on a
   36px line, the subtitle 22.29px above the details; stacked below 992px,
   the sidebar starts 32.5px after the last screenshot; the details take
   Porto's rem padding and gaps. */
@media (max-width: 991px) { .section--project .with-sidebar { row-gap: 32.5px; } }

/* Space the original's page builder left on seven projects (measured
   2026-10-14; "originalSpace" in projects.json). "paragraphs": the text sat
   in a paragraph the browser could not nest, leaving an empty one above the
   subtitle and one under the gallery, 20px each (1.25rem: 18.57px below
   576px). "end-row": an empty 50px row under the gallery. Michael Madden's
   empty bordered box under its gallery is not copied (README). */
.project--paragraphs::before,
.project--paragraphs::after { content: ""; display: block; height: 20px; }
@media (max-width: 575px) {
  .project--paragraphs::before,
  .project--paragraphs::after { height: 18.57px; }
}
.project--end-row::after { content: ""; display: block; height: 50px; }
@media (max-width: 575px) {
  .shots { margin: 0 -5px; }
  .photo-row { margin: -10px -15px -2.5px; }
  .type-heading { min-height: 36px; font-size: 27.86px; line-height: 36px; }
  .project__sub { margin-bottom: 22.29px; }
  .project-meta { padding: 44.57px 22.29px; }
  .project-meta div + div { margin-top: 14.86px; }
}

/* ---- components/service.css ---- */
/* ---- service pages ----------------------------------------------------------------------
   The Font Awesome icon floats right, 75px, in the banner's blue; then the
   tagline in PT Serif and the body copy. Skills bars on /service/: a label
   and "100%" over a dark bar, the width animating in, as the original's did. */
/* The original's spacing, measured 2026-10-13 at 1512, 1024 and 390: the
   text starts 177px below the banner band (74px below the blue box; 62.79px
   below 576px, where Porto's rem is 14.86px), the tagline has 24px under it,
   the paragraph 40px (16px padding + 24px margin); the icon floats with no
   bottom margin, so the paragraph's second line runs under it, not beside. */
.section--svc { padding: 74px 0 52px; }
.svc-intro { margin-bottom: 40px; }
.svc-intro .lead { margin-bottom: 24px; }
.svc-icon {
  float: right;
  width: auto;
  height: 75px;
  margin: 0 0 0 24px;
  color: var(--blue);
}
/* Video Screen Casting's text sat in a paragraph the browser could not nest
   on the original (as on seven project pages, project.css): 20px more above
   the tagline and 8px more under the pictures; 18.57px and 6.43px below
   576px (measured 2026-10-14 at 1512, 1024 and 390). */
.svc-main--paragraphs::before { content: ""; display: block; height: 20px; }
.svc-main--paragraphs::after { content: ""; display: block; height: 8px; }
@media (max-width: 575px) {
  .svc-main--paragraphs::before { height: 18.57px; }
  .svc-main--paragraphs::after { height: 6.43px; }
}

/* Stacked below 992px: 80px from the last picture to the sidebar (Porto's
   3rem column margin, the column's 40px padding less the sidebar's -20px,
   and the picture's line), 48px under the sidebar. */
@media (max-width: 991px) {
  .section--svc { padding-bottom: 48px; }
  .section--svc .with-sidebar { row-gap: 80px; }
}
@media (max-width: 575px) {
  .section--svc { padding: 62.79px 0 50px; }
  .section--svc .with-sidebar { row-gap: 76px; }
  .svc-intro { margin-bottom: 37.14px; }
  .svc-intro .lead { margin-bottom: 22.29px; }
  /* 1.5rem at Porto's 14.86px rem: the float is 106.7px wide, as there
     (measured 2026-10-14; 24px wrapped Video Production's tagline a line
     longer). */
  .svc-icon { margin-left: 22.29px; }
}

@keyframes bar-in { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* The service pages' pictures: one under another at their own size, never
   wider than the column (so at its full width on a desktop), 24px under the
   first and none under the rest — the original's single images (measured
   2026-10-13: Graphic Design's logos 959px square at 1512, AlZon's at its
   own 946px). Not links, as there. */
.svc-images img { display: block; width: auto; max-width: 100%; height: auto; }
.svc-images img:first-child { margin-bottom: 24px; }
@media (max-width: 575px) { .svc-images img:first-child { margin-bottom: 22.29px; } }

/* ---- /service/ (measured 2026-10-13 at 1512) -------------------------------------
   The head and the six cards sit in a second 6.4vw inset, the outlined
   SERVICES at its left on a 42px line; the cards 20px apart, each its own
   height, 66px under the divider. 152px down to the skills row: CUSTOM
   SERVICES in 4/12 (5/12 below 1200px), its outlined IDEAS 187.2px, 102px
   down and 64px out to the left, "Design. Build. Better." 35px; one twelfth
   further, the bars in 7/12 (6/12): OUR SKILLS, then for each a 12.6px label,
   a 5px #d8d8d8 track filled #2a2a2a with 24px under it, and "100%" 15px in
   from its right end, sitting on the track; 23px under the last. The grid
   keeps its cards' 20px bottom margin. The band follows with no gap,
   then 95px down to the questions. */
.section--svc-archive { padding-bottom: 92px; }
.svc-archive { padding: 0 var(--wrap-inset); }
/* From 576 to 991px the original's head and cards sit 15px further in. */
@media (min-width: 576px) and (max-width: 991px) { .svc-archive { padding: 0 calc(var(--wrap-inset) + 15px); } }
.section-head--svc { margin-bottom: 66px; }
.section-head--svc .title { margin-bottom: 24px; }
.section-head--svc .divider { margin-bottom: 0; }
.watermark--svc { top: 0; left: 0; line-height: 42px; transform: none; }

.section--skills { padding: 80px 0 72px; }
.skills-row { display: flex; flex-wrap: wrap; margin: 0 -15px; }
.skills-row__text,
.skills-row__bars { position: relative; width: 100%; min-width: 0; padding: 0 15px; }
.skills-row__text { margin-bottom: 24px; }
@media (min-width: 992px) {
  .skills-row__text { width: 41.6667%; margin-bottom: 0; }
  .skills-row__bars { width: 50%; margin-left: 8.3333%; }
}
@media (min-width: 1200px) {
  .skills-row__text { width: 33.3333%; }
  .skills-row__bars { width: 58.3333%; }
}
.watermark--ideas { top: 102px; left: -64px; font-size: calc(var(--fs-body) * 13.371); line-height: 42px; transform: none; }
.title--md { font-size: var(--fs-cta); line-height: 42px; }
.skills-row__text .title { margin-bottom: 32px; }
.skills-row__text .divider { margin-bottom: 32px; }
.skills-row__text .lead { margin-bottom: 24px; }
.skills-title { margin-bottom: 24px; padding-bottom: 8px; }
.skills { margin: 0 0 23px; padding: 0; list-style: none; }
/* Stacked, below 992px, the original leaves 12px less under the bars. */
@media (max-width: 991px) { .skills { margin-bottom: 11px; } }
.skill { position: relative; display: block; padding: 8px 0 24px; }
.skill:first-child { padding-top: 0; }
.skill__label { display: block; color: var(--ink); font-size: 0.9em; line-height: 26px; }
.skill__track { position: relative; display: block; height: 5px; background: #d8d8d8; }
.skill__bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--pct, 100%);
  background: var(--dark);
  transform-origin: left;
  animation: bar-in 1.2s ease both;
}
.skill__value { position: absolute; right: 15px; bottom: 29px; color: var(--ink); font-size: 0.9em; line-height: 26px; }

.cta-flat .cta-band { padding: 73.85px 0; }
/* The questions' own margins, as there: 22px under the intro's button (from
   992px, where the two sit side by side; under the list when stacked), 35px
   under the list — whichever ends lower, then 47px (63px below 576px, where
   the list comes last) to the footer. */
.section--svc-faq { padding: 95px 0 47px; }
@media (min-width: 992px) { .section--svc-faq .faq-block__intro .btn-row { margin-bottom: 22px; } }
.section--svc-faq .faq-block__list { margin-bottom: 35px; }
/* Stacked from 576 to 991px the original's 22px comes under the list
   instead (measured 2026-10-20 at 768: the list 22px higher than with it
   under the button, the footer where it was). */
@media (min-width: 576px) and (max-width: 991px) { .section--svc-faq .faq-block__list { margin-bottom: 57px; } }
/* Here the lead sits 8px further under the divider than in the home page's
   block, with 8px less under it (measured 2026-10-20 at 1512, 1024, 768 and
   390: the text after it is where the home page's is). */
.section--svc-faq .faq-block__intro .divider { margin-bottom: 32px; }
.section--svc-faq .faq-block__intro .lead { margin-bottom: 24px; }
@media (max-width: 575px) {
  .section--svc-archive { padding-bottom: 86.86px; }
  .section--skills { padding: 74.28px 0 66.86px; }
  .skills-row__text { margin-bottom: 22.29px; }
  .section-head--svc { margin-bottom: 56px; }
  .section-head--svc .title { margin-bottom: 22.86px; }
  .title--md { line-height: 39px; }
  .skills-row__text .title { margin-bottom: 29.72px; }
  .skills-row__text .divider { margin-bottom: 25px; }
  .skills-title { margin-bottom: 22.29px; padding-bottom: 7.43px; }
  .skills-row__text .lead { margin-bottom: 22.29px; }
  .section--svc-faq { padding: 89.14px 0 63px; }
  .section--svc-faq .faq-block__intro .divider { margin-bottom: 25.43px; }
  .section--svc-faq .faq-block__intro .lead { margin-bottom: 22.29px; }
  .skill__label,
  .skill__value { line-height: 20px; }
  .cta-flat .cta-band { padding: 68.58px 0; }
  .cta-flat .cta-band__text,
  .cta-flat .cta-band__action { padding: 0; }
}

/* ---- components/gallery.css ---- */
/* ---- lightbox gallery -----------------------------------------------------------------------
   Every gallery photo is a button that opens the lightbox (40-gallery.js);
   without JS it is a plain image. The original's hover: a 65% dark wash with
   a zoom icon. */
.gallery-item {
  position: relative;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  overflow: hidden;
}
.gallery-item img { width: 100%; transition: opacity var(--transition); }
.gallery-item::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.65) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-4-4M11 8v6M8 11h6'/%3E%3C/svg%3E") center / 30px no-repeat;
  opacity: 0;
  transition: opacity var(--transition);
}
.gallery-item:hover::after,
.gallery-item:focus-visible::after { opacity: 1; }

/* The original's lightbox (Magnific Popup, measured 2026-10-14 at 1512 and
   390): a 0.8 dark overlay fading in over 0.3s; the photo with 40px above
   and below it, on a #444 box with a soft shadow, as tall as the window
   allows and centred; a thin white × in that top 40px at the photo's right
   edge; "1 of 18" in 12px #ccc just under the photo's bottom right; the
   arrows two outlined triangles at the window's edges, 0.65 strong, 1 under
   the pointer, three quarters the size below 901px. Magnific itself sizes
   the photo to the window; the original's stylesheet cancels that, so there
   the photo runs the full window width and its bottom is cut off — here it
   fits, as Magnific intends. A click on the photo shows the next one. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 8px;
  background: rgba(11, 11, 11, 0.8);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease-out, visibility 0s linear 0.3s;
}
.lightbox.is-open { opacity: 1; visibility: visible; transition: opacity 0.3s ease-out, visibility 0s; }
.lightbox__figure { position: relative; z-index: 0; max-width: 100%; margin: 0; line-height: 0; }
.lightbox__figure::after {
  content: "";
  position: absolute;
  top: 40px;
  right: 0;
  bottom: 40px;
  left: 0;
  z-index: -1;
  background: #444;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
}
.lightbox img {
  display: block;
  box-sizing: border-box;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100vh;
  max-height: 100dvh;
  margin: 0 auto;
  padding: 40px 0;
}
.lightbox:not(.is-single) img { cursor: pointer; }
.lightbox__bar { position: absolute; top: 100%; left: 0; width: 100%; margin-top: -36px; line-height: 18px; }
.lightbox__cap { display: block; padding-right: 36px; color: #f3f3f3; text-align: left; }
.lightbox__count { position: absolute; top: 0; right: 0; color: #ccc; font-size: 12px; white-space: nowrap; }
.lightbox__close,
.lightbox__prev,
.lightbox__next {
  position: absolute;
  padding: 0;
  border: 0;
  background: transparent;
  opacity: 0.65;
  cursor: pointer;
}
.lightbox__close:hover,
.lightbox__close:focus-visible,
.lightbox__prev:hover,
.lightbox__prev:focus-visible,
.lightbox__next:hover,
.lightbox__next:focus-visible { opacity: 1; }
.lightbox__close {
  top: 0;
  right: -6px;
  z-index: 1;
  width: 41px;
  height: 41px;
  color: var(--white);
  transform: rotate(45deg);
}
.lightbox__close::before,
.lightbox__close::after { content: ""; position: absolute; background: currentColor; }
.lightbox__close::before { top: 20px; left: 12px; width: 17px; height: 1px; }
.lightbox__close::after { top: 12px; left: 20px; width: 1px; height: 17px; }
.lightbox__prev,
.lightbox__next { top: 50%; width: 90px; height: 110px; margin-top: -55px; }
.lightbox__prev { left: 0; transform-origin: 0 50%; }
.lightbox__next { right: 0; transform-origin: 100% 50%; }
.lightbox__prev::before,
.lightbox__prev::after,
.lightbox__next::before,
.lightbox__next::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  margin-top: 35px;
  border: 3px inset transparent;
}
.lightbox__prev::before,
.lightbox__next::before { border-top-width: 21px; border-bottom-width: 21px; opacity: 0.7; }
.lightbox__prev::after,
.lightbox__next::after { top: 8px; border-top-width: 13px; border-bottom-width: 13px; }
.lightbox__prev::before { margin-left: 25px; border-right: 27px solid #3f3f3f; }
.lightbox__prev::after { margin-left: 31px; border-right: 17px solid #fff; }
.lightbox__next::before { margin-left: 35px; border-left: 27px solid #3f3f3f; }
.lightbox__next::after { margin-left: 39px; border-left: 17px solid #fff; }
@media (max-width: 900px) {
  .lightbox { padding: 0 6px; }
  .lightbox__prev,
  .lightbox__next { transform: scale(0.75); }
}

/* One picture on its own (a member card's magnifier): no arrows. */
.lightbox.is-single .lightbox__prev,
.lightbox.is-single .lightbox__next { display: none; }

/* ---- components/form.css ---- */
/* ---- contact page ----------------------------------------------------------------------------
   The original's (measured 2026-10-13 at 1512, 1024, 768 and 390). Two equal
   columns from 992px, one above the other below. The text starts 192px under
   the banner band (89px under the blue box; 75.29px below 576px, where
   Porto's rem is 14.86px) and the footer comes 96px after the taller column (89.14px).

   Left: the eyebrow, the title (24px under it), the hatched divider 8px lower
   and 32px above the lead — Poppins 21px/29.4px here, not PT Serif: the
   original's class was misspelt ("ccustom-font3"), so its serif never
   applied — then the paragraph (8px + 48px under it) and the details in
   three columns with 30px gutters: Work Inquiries; Address with Email under
   it; Business Hours — labels Poppins 15.4px weight 700, -0.77px, #212529.
   One under another below 992px, 24px apart (17px after Email), as there.

   Right: "Send a Message" 24px + 16px down, and the WPForms form: 15px above
   and below each field, labels 16px/19px bold 15px over their box, boxes 43px
   with 1px rgba(0,0,0,.25) and 3px corners, the medium ones 60% wide (all
   of it below 601px), "First" and "Last" side by side unless their 60% row
   is 260px or narrower, a grey triangle in the select, the #066aab Submit
   10px under the last field. */
.section--contact { padding: 89px 0 96px; }
.contact-grid {
  display: grid;
  gap: 0 30px;
  align-items: start;
}
@media (min-width: 992px) { .contact-grid { grid-template-columns: 1fr 1fr; } }
.contact-grid__intro,
.contact-grid__form { min-width: 0; }

.section-head--contact { margin-bottom: 0; }
/* 24px + the divider's own 8px: as one margin, since two would collapse. */
.section-head--contact .title { margin-bottom: 32px; }
.section-head--contact .divider { display: block; margin: 0 0 32px; }
/* 110px below the column's top and 221px left of its text, on a 42px line,
   as the original's (it is cut off at the window's left edge). */
.watermark--contact { top: 110px; left: -221px; line-height: 42px; transform: none; }
.contact-grid .lead { font-family: var(--font); }
.contact-grid .text { margin-bottom: 56px; }

.info-cols { display: flex; flex-wrap: wrap; margin: 0 -15px; }
.info-col { width: 100%; margin: 0; padding: 0 15px; }
@media (min-width: 992px) { .info-col { width: 33.3333%; } }
.info { margin: 0 0 24px; }
.info--last { margin-bottom: 17px; }
@media (max-width: 991px) { .info--top { margin-top: 24px; } }
.info dt {
  color: var(--ink);
  font-size: 1.1em;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.05em;
}
.info dd { margin: 0; font-size: 14px; line-height: 26px; }
.info a { color: var(--body); }
.info a:hover { color: var(--ink); }

.contact-grid__form .title--sm { margin: 24px 0 24px; padding-top: 16px; }
/* 48px under "Send a Message": the original's 24px + the form's own 24px,
   which did not collapse there. */
#contact-form { margin: 48px 0 24px; }

@media (max-width: 575px) {
  .section--contact { padding: 75.29px 0 89.14px; }
  .section-head--contact .eyebrow { margin-bottom: 7.43px; }
  .section-head--contact .title { margin-bottom: 29.72px; }
  .section-head--contact .divider { margin: 0 0 25px; }
  .contact-grid .lead { margin-bottom: 22.29px; }
  .contact-grid .text { margin-bottom: 51.99px; }
  .info { margin-bottom: 22.29px; }
  .info--last { margin-bottom: 17px; }
  .info--top { margin-top: 22.29px; }
  .contact-grid__form .title--sm { margin: 22.29px 0; padding-top: 14.86px; }
  #contact-form { margin-top: 46.29px; }
}

.field { margin: 0; padding: 15px 0; border: 0; }
.field > label,
.field > legend {
  display: block;
  margin: 0 0 15px;
  padding: 0;
  color: rgba(0, 0, 0, 0.85);
  font-size: 16px;
  font-weight: 700;
  line-height: 19px;
}
/* A fieldset draws its legend in its top border, above the 15px padding, so
   "Name" sat 15px higher than the original's (measured 2026-10-20 at 1512,
   1024, 768 and 390). Floated, the legend is laid out inside the padding like
   the other labels; the boxes under it do not move. */
.field > legend { float: left; width: 100%; }
.field > legend + * { clear: both; }
.field .req { color: #d63637; font-weight: 400; }
.field--medium input,
.field--medium select { max-width: 60%; }

/* The name row: 60% wide, its two halves 10px either side of the middle;
   stacked, 15px apart, when the row is 260px or narrower — WPForms' own
   container query. */
.form-row {
  display: flex;
  flex-wrap: wrap;
  max-width: 60%;
  container-type: inline-size;
}
.field__sub { width: 50%; padding: 0 10px; }
.field__sub:first-child { padding-left: 0; }
.field__sub:last-child { padding-right: 0; }
@container (max-width: 260px) {
  .field__sub { width: 100%; padding: 0; }
  .field__sub:not(:last-child) { margin-bottom: 15px; }
}
.field--name { min-width: 0; }
.field__sub label {
  display: block;
  margin-top: 5px;
  color: rgba(0, 0, 0, 0.55);
  font-size: 14px;
  line-height: 17px;
}
/* Below 601px every box is the full width, and each field keeps 1px clear
   on either side, as WPForms does. */
@media (max-width: 600px) {
  .field { padding-left: 1px; padding-right: 1px; }
  .form-row,
  .field--medium input,
  .field--medium select { max-width: 100%; }
}

.field input,
.field select,
.field textarea {
  display: block;
  width: 100%;
  padding: 0 14px;
  border: 1px solid rgba(0, 0, 0, 0.25);
  border-radius: 3px;
  background: var(--white);
  color: rgba(0, 0, 0, 0.7);
  font-family: inherit;
  /* 16px minimum: anything smaller makes iOS Safari zoom on focus. */
  font-size: 16px;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.field input,
.field select { height: 43px; }
/* The original's select: no native arrow, a small grey triangle drawn by
   two gradients 12-17px in from the right. */
.field select {
  padding-right: 24px;
  -webkit-appearance: none;
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(135deg, rgba(0, 0, 0, 0.25) 50%, transparent 50%);
  background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.field textarea { height: 120px; padding: 14px; line-height: 1.3; resize: vertical; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: #066aab;
  box-shadow: 0 0 0 1px #066aab;
  outline: none;
}

.form-submit {
  height: 41px;
  padding: 0 15px;
  border: 0;
  border-radius: 3px;
  background: #066aab;
  color: var(--white);
  font-size: 17px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color var(--transition);
}
.form-submit:hover { background: #055a91; }

/* The original's Submit sat 10px under the last field; here the Turnstile
   box comes first, 10px under the field, and Submit 10px under that. */
.form-actions { margin-top: 10px; }

.form-status {
  display: none;
  margin-top: 16px;
  padding: 12px 16px;
}
.form-status.is-ok { display: block; background: #e8f5ec; color: #1c6b3a; }
.form-status.is-err { display: block; background: #fdecea; color: #a32218; }

/* The honeypot's wrapper. A CLASS and never a style attribute: this template
   ships 'unsafe-inline' in style-src, but several sites built from it have
   since tightened that to a bare `style-src 'self'`, where an inline style is
   dropped by the browser and the field it was hiding becomes a visible
   "Company" box on every contact page. A class works under both.
   Positioned off-canvas rather than `display:none` — some bots skip what is
   displayed none, and the whole point is that they fill it. */
.form-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
/* A zero-size box, still displayed and still fillable: nothing a person can
   reach, and not a "tap target" to the responsive check. */
.form-hp input { width: 0; height: 0; padding: 0; border: 0; }

/* Turnstile renders its own iframe into this div, so the box is not ours to
   style — but its SIZE is ours to reserve. Without a reserved box the div is
   0px until api.js loads and then jumps to 300x65, shoving the submit button
   down the page just as someone reaches for it.

   300x65 is the "normal" widget, which is the default when data-size is not
   set: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/widget-configurations/
   If you ever set data-size="compact", this becomes 150x140. */
.cf-turnstile {
  min-height: 65px;
  margin: 10px 0 0;
}

/* ---- components/not-found.css ---- */
/* ---- 404 -----------------------------------------------------------------------------------
   The original's page (measured 2026-10-14 at 1512, 1024, 768 and 390):
   "404" in Overpass 140px/600 on a 140px line, -10px apart, #222529, with
   Font Awesome's file icon after it at the same size, its foot 0.125em
   under the line; 32px under it the sentence in 1.4em Poppins on a 36px
   line, #777; 110px from the sentence to the footer. From 992px the text
   sits in the container's second to seventh twelfths (690px at 1512, 450px
   at 1024); below, across it, 30px in from the window at 768. Below 576px
   the number and the icon are 100px. Two things differ on purpose: the
   original starts the number 33px up under the blue banner box, which
   covers its top (most of it on a phone), so here it starts below the box
   like every other page; and on a phone the original's text touches the
   window's left edge, so here it keeps the 6.4vw margin of the other pages.
   No Home button: the original has none. */
.section--404 { padding-bottom: 90px; }
.not-found { padding: 0 15px; }
@media (min-width: 992px) {
  .not-found { width: calc((100% + 30px) / 2); margin-left: calc((100% + 30px) / 12 - 15px); }
}
.not-found__title {
  margin: 0 0 32px;
  color: #222529;
  font-family: var(--font-head);
  font-size: 140px;
  font-weight: 600;
  line-height: 140px;
  letter-spacing: -10px;
}
.not-found__icon { display: inline-block; width: 0.75em; height: 1em; vertical-align: -0.125em; }
.not-found p { margin: 0 0 20px; font-size: 1.4em; line-height: 36px; }
@media (max-width: 575px) {
  .section--404 { padding-bottom: 40px; }
  .not-found { padding: 0 6.4vw; }
  .not-found__title { font-size: 100px; line-height: 100px; letter-spacing: normal; }
  .not-found p { margin-bottom: 18.57px; }
}

/* ---- components/footer.css ---- */
/* ---- footer ----------------------------------------------------------------
   Matched to the original on 2026-10-13 (client review), measured from 1512
   down to 390px. #2a2a2a, no top padding: the column headings sit on the
   footer's top edge, so on the home page the testimonials box above (the same
   colour) runs straight into it. Three centred columns, 25 / 50 / 25%, in the
   original's container: 1440px from 1500px wide, 1140 from 1170, 960 from
   992, the full width with 30px sides below that (20px below 576).
   Headings Overpass 18.9px/27px weight 800 white; the address three 24px
   lines 4px apart, #999; "OFFICE" 12.6px uppercase #999; the number Poppins
   22.68px bold white. Under them a 1px rule at 3% white, 64px, the 115px
   logo, 16px, the copyright line and 88px.

   One difference on purpose: the phone number is a tel: link — on the
   original it was plain text in an <h2>. */
.site-footer {
  padding: 0 0 88px;
  background: var(--dark);
  color: var(--muted);
  font-size: var(--fs-small);
  line-height: 26px;
  text-align: center;
}

.footer-wrap {
  width: 100%;
  margin: 0 auto;
  padding: 0 20px;
}
@media (min-width: 576px) { .footer-wrap { padding: 0 30px; } }
@media (min-width: 992px) { .footer-wrap { max-width: 960px; padding: 0 15px; } }
@media (min-width: 1170px) { .footer-wrap { max-width: 1140px; } }
@media (min-width: 1500px) { .footer-wrap { max-width: 1440px; } }

.footer-cols {
  display: flex;
  flex-wrap: wrap;
  margin: 0 -15px;
}
.footer-col {
  flex: 0 0 100%;
  min-width: 0;
  padding: 0 15px;
}
@media (min-width: 768px) {
  .footer-col { flex-basis: 25%; }
  .footer-col--contacts { flex-basis: 50%; }
}
.footer-col--address { padding-bottom: 20px; }
.footer-col--contacts { padding-bottom: 17px; }

.footer-col__title {
  margin: 0 0 20px;
  color: var(--white);
  font-size: 1.5em;
  font-weight: 800;
  line-height: 27px;
  letter-spacing: 0;
}
.footer-col--contacts .footer-col__title { margin-bottom: 10px; }
.footer-col--follow .footer-col__title { margin-bottom: 8px; }
.footer-col__text { margin: 0; line-height: 24px; }
.footer-col__text span { display: block; }
.footer-col__text span + span { margin-top: 4px; }
.footer-col__label {
  margin: 0 0 -1px;
  font-size: 12.6px;
  line-height: 24px;
  text-transform: uppercase;
}
.footer-phone {
  margin: 0;
  font-size: 22.68px;   /* the one size the original did not step down on phones */
  font-weight: 700;
  line-height: 24px;
}
/* The tel: link keeps its 28px tap height (utilities.css) without making
   the line taller than the original's 24px. */
.site-footer .footer-phone a { margin: -2px 0; color: var(--white); }
.footer-phone a:hover { color: var(--white); text-decoration: underline; }

.footer-social { display: flex; justify-content: center; gap: 4.5px; padding: 3.66px 0; }
.social-link--footer { width: 28px; height: 28px; }
/* At the footer's 12.8px the original's glyphs paint 14px and 12px tall. */
.social-link--footer svg { width: auto; height: 13.9px; }
.social-link--footer:hover { background: #151719; }

.footer-bottom {
  padding-top: 64px;
  border-top: 1px solid rgba(255, 255, 255, 0.03);
}
.footer-logo { display: block; width: 115px; margin: 0 auto 16px; }
.footer-logo img { width: 115px; }
.footer-copy { margin: 0; line-height: 26px; }

/* Below 576px the original's rem is 14.86px, so its rem-sized gaps shrink:
   1.25rem under the address heading and column, 0.25rem between its lines,
   4rem above the logo, 1rem under it, 5.5rem at the bottom. */
@media (max-width: 575px) {
  .site-footer { padding-bottom: 81.71px; }
  .footer-col--address { padding-bottom: 18.57px; }
  .footer-col--address .footer-col__title { margin-bottom: 18.57px; }
  .footer-col__text span + span { margin-top: 3.71px; }
  .footer-bottom { padding-top: 59.43px; }
  .footer-logo { margin-bottom: 14.86px; }
}

/* ---- utilities.css ---- */
/* ---- utilities, motion, print ------------------------------------------- */

/* Any phone link anywhere is a tap target, including one written directly into
   page content. Enforce the WCAG 2.2 minimum (24x24) globally so a bare
   `tel:` link can never ship too small to hit on a phone. */
a[href^="tel:"] {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
}

/* Back to top: the original's #topcontrol, 49x48, rgba(64,64,64,.75), square,
   10px from the right on the window's bottom edge, shown once the page is
   100px down; not below 768px (measured 2026-10-13). */
.to-top {
  position: fixed;
  right: 10px;
  bottom: 0;
  z-index: 900;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 49px;
  height: 48px;
  border: 0;
  border-radius: 0;
  background: rgba(64, 64, 64, 0.75);
  color: var(--white);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition), visibility 0s linear 0.3s;
}
.to-top.is-visible { opacity: 1; visibility: visible; transition: opacity var(--transition), visibility 0s; }
.to-top:hover { background: rgba(64, 64, 64, 0.95); }
@media (max-width: 767px) { .to-top { display: none; } }

/* Scroll reveal: the original's appear animations, 1s ease each —
   fadeIn, fadeInUp (30px), fadeInLeft / fadeInRight (40px), maskUp (both
   Porto's slide-up and a clip reveal).
   Hidden only when JS is present; 50-reveal.js adds .is-visible as each
   element scrolls in, and reveals everything after 2.5s whatever happens.
   The original also waited up to 2.1s before starting some of them; delays
   here are capped at 600ms so a heading is never blank for two seconds. */
.js .reveal { opacity: 0; }
/* opacity:1 here, not only in the keyframes: if animations are off (a
   screenshot tool, a browser setting) a revealed element must still show. */
.js .reveal.is-visible { opacity: 1; animation: var(--reveal) both; animation-name: fade-in; animation-delay: var(--delay, 0ms); }
.js .reveal[data-reveal="fade-up"].is-visible { animation-name: fade-in-up; }
.js .reveal[data-reveal="fade-left"].is-visible { animation-name: fade-in-left; }
.js .reveal[data-reveal="fade-right"].is-visible { animation-name: fade-in-right; }
.js .reveal[data-reveal="mask-up"] { overflow: hidden; }
.js .reveal[data-reveal="mask-up"].is-visible { animation-name: mask-up; }
/* Porto's own maskUp: the element rises from one height below into place,
   clipped by its parent (the home hero's stage columns). */
.js .reveal[data-reveal="slide-up"].is-visible { animation-name: slide-up; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade-in-up { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: none; } }
@keyframes fade-in-left { from { opacity: 0; transform: translateX(-40px); } to { opacity: 1; transform: none; } }
@keyframes fade-in-right { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
@keyframes slide-up { from { opacity: 1; transform: translateY(100%); } to { opacity: 1; transform: none; } }
@keyframes mask-up { from { opacity: 1; clip-path: inset(100% 0 0 0); } to { opacity: 1; clip-path: inset(0 0 0 0); } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .js .reveal { opacity: 1; }
}

@media print {
  .header-wrap,
  .site-footer,
  .to-top,
  .skip-link { display: none; }

  body { color: #000; background: #fff; }
  .section { padding: 1rem 0; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.75em; }
}
