/* =========================================================
   Robotface — design tokens
   Colors/breakpoints/spacing pulled from the previous Gatsby
   build's compiled stylesheet so this rebuild matches the
   current look.
   ========================================================= */

/* The original registers only these two cuts of Maison Neue -- weight 500
   pointing at the "Book" file and weight 700 pointing at the "Medium" file
   (not a typo: their "Medium" is what's bound to 700). Any CSS elsewhere
   asking for other weights (100, 900, etc.) has nothing exact to match, so
   the browser falls back to whichever of these two is closest -- which is
   exactly what the original does too. Registering our extra Light/Demi/Bold
   files under their "expected" numbers broke that fallback and rendered
   visibly heavier text than the real site everywhere but the literal 500/700
   cases. */
@font-face {
  font-family: "Maison Neue";
  src: url("/assets/fonts/maison-neue-book.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Maison Neue";
  src: url("/assets/fonts/maison-neue-medium-italic.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Maison Neue";
  src: url("/assets/fonts/maison-neue-medium.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Maison Neue Mono";
  src: url("/assets/fonts/maison-neue-mono.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Maison Neue Mono";
  src: url("/assets/fonts/maison-neue-mono-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

:root {
  --color-black: #000000;
  --color-white: #ffffff;
  --color-accent: #ff4da1;
  --color-accent-hover: #5fd98f;
  --color-cream: #fcfaf2;
  --color-grey-light: #f7f7f7;
  --color-grey: #cfd0ce;
  --color-text: #262939; /* body copy, headings -- the original uses this dark
                             navy-grey for content text, reserving pure black
                             for nav links and UI chrome (buttons, backgrounds) */

  --font-heading: "Heebo", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-body: "Maison Neue", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;

  --container-max: 1280px;
  --header-height-mobile: 60px;
  --header-height-desktop: 100px;

  /* breakpoints (used in comments; media queries are hard values below) */
}

/* =========================================================
   Reset + base
   ========================================================= */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: var(--header-height-mobile);
  overflow-x: clip;
}
/* Fragment links can target sections on the current page or arrive from
   another page. Reserve the fixed header's height in both cases so the
   target begins below the navigation rather than underneath it. */
[id] { scroll-margin-top: var(--header-height-mobile); }
@media (min-width: 1000px) {
  html { scroll-padding-top: var(--header-height-desktop); }
  [id] { scroll-margin-top: var(--header-height-desktop); }
}
body {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px; /* browser default (16px) dropped 1pt, as a floor for any
                       body text below that doesn't set its own size */
  color: var(--color-text);
  background: var(--color-white);
  line-height: 1.5;
  overflow-x: clip;
}
/* Opted-in pages only (see snapScrollPaths in base.njk), desktop widths
   only: each major section snaps fully into view as the user scrolls,
   matching the homepage's full-page behaviour. Mobile always scrolls
   normally -- full-page snap is disorienting on touch. */
@media (min-width: 1000px) {
  html:has(body.snap-scroll) { scroll-snap-type: y mandatory; }
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4, h5 { font-family: var(--font-heading); font-weight: 700; letter-spacing: .15px; margin: 0 0 0.5em; line-height: 1.15; }
p { margin: 0 0 1em; }
ul { margin: 0; padding: 0; list-style: none; }
button { font-family: inherit; cursor: pointer; }
.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; left: 0; top: -60px; background: var(--color-black);
  color: var(--color-white); padding: 12px 20px; z-index: 100; transition: top .2s ease;
}
.skip-link:focus { top: 0; }

main { display: block; }

.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 20px;
  width: 100%;
}

.btn {
  display: inline-block;
  background: var(--color-accent);
  color: var(--color-white);
  font-family: var(--font-heading);
  font-weight: 900;
  font-size: 12px;
  text-transform: uppercase;
  padding: 10px 16px;
  border-radius: 2px;
  border: 2px solid var(--color-accent);
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
@media (min-width: 1000px) { .btn { font-size: 16px; padding: 13px 24px; } }
/* the compare-table's per-product button stays small (11px) at every
   width; elsewhere .btn--fancy just uses the regular .btn sizing */
.compare-table .btn--fancy { font-size: 11px; padding: 8px 24px; }
.btn:hover, .btn:active { background: var(--color-accent-hover); color: var(--color-white); border-color: var(--color-accent-hover); }
.btn--outline { background: transparent; color: var(--color-white); border-color: var(--color-white); }
.btn--outline:hover { background: var(--color-white); color: var(--color-black); }

/* =========================================================
   Header / primary nav
   ========================================================= */
.header {
  position: fixed;
  top: 0; left: 0;
  width: 100%;
  z-index: 100;
  background: var(--color-white);
  box-shadow: 0 1px 0 rgba(0,0,0,.06);
  transition: background .3s ease, transform .3s ease;
}
/* pages that open on a full-bleed dark video hero start with a transparent,
   white-on-video header instead, until the user scrolls past it (.header--scrolled) */
.has-hero .header:not(.header--scrolled) { background: transparent; box-shadow: none; }
.has-hero .header:not(.header--scrolled) nav.primary-nav a { color: var(--color-white); }
.has-hero .header:not(.header--scrolled) .hamburger .lines,
.has-hero .header:not(.header--scrolled) .hamburger .lines::before,
.has-hero .header:not(.header--scrolled) .hamburger .lines::after { background: var(--color-white); }
.has-hero .header:not(.header--scrolled) .logo img.logo-mark { filter: none; }

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-height-mobile);
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 20px;
  position: relative;
}
@media (min-width: 1000px) { .header__inner { height: var(--header-height-desktop); padding: 20px; } }

.header .logo { display: block; margin-top: 4px; }
.header .logo img { width: 130px; height: auto; display: block; }
@media (min-width: 813px) { .header .logo img { width: 190px; } }
.header .logo img.logo-mark { filter: brightness(0) saturate(100%); transition: filter .2s ease; }

.header nav.primary-nav > ul {
  display: none;
}
@media (min-width: 813px) {
  .header nav.primary-nav > ul {
    display: flex;
    justify-content: space-between;
    max-width: 600px;
    position: absolute;
    right: 20px;
    width: 100%;
  }
}
@media (min-width: 1000px) { .header nav.primary-nav > ul { max-width: 700px; } }
.header nav.primary-nav > ul > li { position: relative; }
.header nav.primary-nav a {
  color: var(--color-black);
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 700;
  line-height: 18px;
  white-space: nowrap;
  position: relative;
}
.header nav.primary-nav a::after {
  content: "";
  position: absolute; left: 0; bottom: -2px;
  width: 100%; height: 2px; background: currentColor;
  transform: scaleX(0); transform-origin: right;
  transition: transform .25s ease;
}
.header nav.primary-nav a:hover::after,
.header nav.primary-nav a[aria-current="page"]::after { transform: scaleX(1); transform-origin: left; }

.header nav.primary-nav .submenu {
  display: block;
  position: absolute;
  top: 100%; left: -12px;
  width: max-content;
  padding: 10px 12px;
  background: var(--color-white);
  box-shadow: 0 12px 24px rgba(0,0,0,.12);
  opacity: 0; visibility: hidden;
  transition: opacity .3s ease, visibility .3s ease;
}
/* while the header is transparent over a hero video, keep the dropdown
   transparent too; once scrolled (or on pages with no hero at all, where
   the header is always opaque) it gets its white card background back */
.has-hero .header:not(.header--scrolled) nav.primary-nav .submenu {
  background: transparent;
  box-shadow: none;
}
.header nav.primary-nav .submenu li { display: block; text-align: left; width: 100%; }
.header nav.primary-nav > ul > li:hover > .submenu,
.header nav.primary-nav > ul > li:focus-within > .submenu { opacity: 1; visibility: visible; transform: translateY(0); }

/* mobile hamburger */
.hamburger {
  display: block;
  background: transparent; border: none; padding: 4px; z-index: 110;
  width: 30px; height: 24px; position: relative;
}
@media (min-width: 813px) { .hamburger { display: none; } }
.hamburger .lines,
.hamburger .lines::before,
.hamburger .lines::after {
  display: block; position: absolute; left: 0;
  width: 26px; height: 2px; background: var(--color-black);
  transition: transform .25s ease, opacity .25s ease, background .2s ease;
}
.hamburger .lines { top: 11px; }
.hamburger .lines::before { content: ""; top: -8px; }
.hamburger .lines::after { content: ""; top: 8px; }
.hamburger.active .lines { background: transparent; }
.hamburger.active .lines::before { transform: translateY(8px) rotate(45deg); background: var(--color-black); }
.hamburger.active .lines::after { transform: translateY(-8px) rotate(-45deg); background: var(--color-black); }

@media (max-width: 812px) {
  nav.primary-nav {
    position: fixed;
    top: 0; right: 0;
    height: 100vh;
    width: min(320px, 84vw);
    background: var(--color-white);
    padding: 90px 28px 40px;
    overflow-y: auto;
    transform: translateX(100%);
    transition: transform .3s ease;
    box-shadow: -8px 0 30px rgba(0,0,0,.15);
  }
  nav.primary-nav.is-open { transform: translateX(0); }
  nav.primary-nav > ul { display: block !important; }
  nav.primary-nav > ul > li { border-bottom: 1px solid var(--color-grey-light); position: relative; }
  nav.primary-nav a { color: var(--color-black) !important; display: block; padding: 12px 0; }
  nav.primary-nav > ul > li:has(> .submenu) > a::after {
    content: "";
    position: absolute; right: 4px; top: 18px;
    width: 8px; height: 8px;
    border-right: 2px solid var(--color-black); border-bottom: 2px solid var(--color-black);
    transform: rotate(45deg);
    transition: transform .2s ease;
  }
  nav.primary-nav > ul > li.submenu-open > a::after { transform: rotate(-135deg); top: 22px; }
  nav.primary-nav .submenu {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; width: auto; padding: 0 0 8px 14px; display: none;
  }
  nav.primary-nav li.submenu-open > .submenu { display: block; }
  .nav-backdrop {
    position: fixed; inset: 0; background: rgba(0,0,0,.4);
    opacity: 0; visibility: hidden; transition: opacity .3s ease, visibility .3s ease;
    z-index: 90;
  }
  .nav-backdrop.is-open { opacity: 1; visibility: visible; }
}

/* =========================================================
   Video banner (full-bleed hero)
   ========================================================= */
.video-banner {
  position: relative;
  background: var(--color-black);
  height: 100svh;
  display: flex;
  overflow: hidden;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.video-banner video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.video-banner::after {
  content: "";
  position: absolute; inset: 0;
  background: rgba(0,0,0,.25);
}
.video-banner__inner {
  position: relative; z-index: 2;
  width: 100%; max-width: var(--container-max);
  margin: 0 auto;
}
.video-banner__inner .content {
  position: absolute;
  left: 20px; bottom: 30%;
  width: 70%;
  z-index: 10;
}
@media (min-width: 567px) { .video-banner__inner .content { bottom: 20%; } }
@media (min-width: 813px) {
  .video-banner__inner .content { bottom: 222px; max-width: 560px; padding-left: 15px; width: 50%; }
}
.video-banner__inner h1 { color: var(--color-white); font-size: 32px; font-weight: 900; margin-bottom: 26px; }
.video-banner__inner p { color: var(--color-white); font-size: 17px; font-weight: 500; }
@media (min-width: 567px) { .video-banner__inner p { font-size: 21px; } }
@media (min-width: 813px) { .video-banner__inner p { font-size: 25px; } }
@media (min-width: 1000px) { .video-banner__inner h1 { font-size: 52px; line-height: 1.3; } }

/* =========================================================
   Features
   ========================================================= */
.features { background: var(--color-white); }
/* On snap-scroll pages this section (and its .features--studio gallery
   variant) fills the viewport -- below the fixed header, not under it --
   and snaps into place like the homepage sections do. main.js lands the
   scroll a header's-height short of this section's real top so its
   content clears the header instead of starting underneath it. */
@media (min-width: 1000px) {
  body.snap-scroll .features {
    min-height: calc(100vh - var(--header-height-desktop)); box-sizing: border-box;
    display: flex; flex-direction: column; justify-content: center;
    scroll-snap-align: start; scroll-snap-stop: always;
    scroll-margin-top: var(--header-height-desktop);
  }
}
.features__inner { margin: 0 auto; padding: 80px 20px; width: 100%; }
@media (min-width: 1000px) {
  .features__inner { display: flex; flex-wrap: wrap; justify-content: space-between; max-width: 1100px; }
}
.features__inner .content { max-width: 630px; padding: 24px 0; width: 100%; }
@media (min-width: 1000px) { .features__inner .content { padding: 0; width: 60%; } }
/* with no features-list sidebar (e.g. FAQ pages, once their stray leftover
   icon+caption is removed), let the content stretch across the full row
   instead of sitting in a 60%-wide column with a bare gap beside it */
.features__inner:not(:has(.features-list)) .content { max-width: none; }
@media (min-width: 1000px) { .features__inner:not(:has(.features-list)) .content { width: 100%; } }
.features__inner .content h1,
.features__inner .content h2 { font-size: 26px; line-height: 32px; }
@media (min-width: 1000px) { .features__inner .content h1, .features__inner .content h2 { font-size: 33px; line-height: 38px; } }
.features__inner .content p { font-size: 13px; line-height: 20px; margin: 0 0 25px; }
@media (min-width: 1000px) { .features__inner .content p { font-size: 15px; line-height: 25px; } }
.features__inner .content p:last-of-type { margin-bottom: 35px; }
@media (min-width: 1000px) { .features__inner .content p:last-of-type { margin-bottom: 50px; } }
.features__inner .content a.btn { margin-bottom: 35px; }
@media (min-width: 567px) { .features__inner .content a.btn { margin-bottom: 0; } }
.features__inner .content a.pdf-link { display: inline-block; margin-top: 16px; font-weight: 700; text-decoration: underline; }

/* buttonWithFeatures: the CTA sits under the icon list (right column) instead
   of under the copy -- used on /studios/ for the Producers Pack download. */
.features-list__btn { display: inline-block; margin-top: 24px; }

/* features--with-stream: this block carries a "recent work" strip nested at
   its foot (studios Producers Pack). On the snap-scroll desktop layout the
   copy rides at the top of the ~full-height section and the strip is pushed
   to its bottom edge; the strip itself is never a snap stop of its own. */
.features--with-stream .video-stream--embedded { background: var(--color-cream); }
.features--with-stream .video-stream--embedded .video-stream__inner { padding-top: 8px; }
.features--with-stream .video-stream--embedded .video-stream__inner h2 { font-size: 20px; margin-bottom: 12px; }
.features--with-stream .video-stream--embedded .video-stream__viewport { padding: 16px 0 28px; }
@media (min-width: 1000px) {
  body.snap-scroll .features--with-stream { justify-content: space-between; }
  .features--with-stream .features__inner { padding-bottom: 24px; }
}

/* =========================================================
   Pages repeater — each item is its own near-full-viewport
   section: media fills the left half, text the right half.
   On the homepage these snap fully into view one at a time
   as you scroll (see "Homepage scroll-snap" below); on other
   pages they just sit in normal document flow.
   ========================================================= */
.repeater-section { position: relative; scroll-snap-align: start; scroll-snap-stop: always; }
.repeater-section.full-section--white .content { background: var(--color-white); }
.repeater-section.full-section--beige .content { background: var(--color-cream); }

.repeater__item { position: relative; }
@media (min-width: 1000px) { .repeater__item { display: flex; min-height: 100vh; } }

.repeater__item__media { position: relative; overflow: hidden; height: 56vw; max-height: 420px; background: #111; }
.repeater__item__media video,
.repeater__item__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (min-width: 1000px) {
  .repeater__item__media {
    position: absolute; top: 0; left: 0; bottom: 0;
    width: 50%; height: auto; max-height: none;
  }
  /* Only on snap-scroll pages does this section ever land locked flush to
     y=0 under the fixed header, with no way to scroll further and reveal
     what's hidden behind it -- there the media needs the same top clearance
     the text column already gets. On ordinary in-flow pages (/contact/,
     /product/, /new-contact-page/) the section just sits wherever normal
     scrolling put it, so that same offset only pushed the media down out of
     line with the text column beside it -- scope it to snap-scroll pages. */
  body.snap-scroll .repeater__item__media { top: var(--header-height-desktop); }
}

.repeater__item .content { padding: 40px 24px; }
@media (min-width: 1000px) {
  .repeater__item .content {
    margin-left: 50%; width: 50%; min-height: 100vh;
    display: flex; align-items: center; padding: 100px 0 60px;
  }
}
.repeater__item .content__inner { max-width: 640px; }
@media (min-width: 1000px) { .repeater__item .content__inner { padding: 0 80px; } }

/* font-weight:100 is not a typo -- Heebo has no weight below 700 registered
   (see base.njk), so this deliberately falls back to Bold, matching the
   original site's own (accidental but consistent) rendering. */
.repeater__item .tagline { font-family: var(--font-heading); font-size: 16px; font-weight: 100; margin: 0 0 16px; }
@media (min-width: 1000px) { .repeater__item .tagline { font-size: 18px; } }

.repeater__item h3 { font-family: var(--font-heading); font-weight: 100; font-size: 24px; margin: 0 0 24px; }
@media (min-width: 813px) { .repeater__item h3 { font-size: 36px; } }
@media (min-width: 1240px) { .repeater__item h3 { font-size: 40px; } }

.repeater__item .content > .content__inner > p { font-size: 13px; margin: 0 0 30px; }
@media (min-width: 1000px) { .repeater__item .content > .content__inner > p { font-size: 17px; margin-bottom: 40px; } }

/* --double variant: two "details" (name/role/phone) stacked in the text half */
.repeater__item--double .details { margin-bottom: 24px; }
.repeater__item--double .details h3 { font-size: 24px; margin-bottom: 10px; }
@media (min-width: 813px) { .repeater__item--double .details h3 { font-size: 36px; margin-bottom: 25px; } }
@media (min-width: 1240px) { .repeater__item--double .details h3 { font-size: 40px; margin-bottom: 30px; } }
.repeater__item--double .details p { font-size: 11px; margin: 0 0 16px; }
@media (min-width: 813px) { .repeater__item--double .details p { font-size: 17px; margin-bottom: 40px; } }

/* =========================================================
   Video content (embedded explainer video)
   ========================================================= */
.video-content { background: var(--color-white); padding: 70px 0; }
@media (min-width: 1000px) {
  body.snap-scroll .video-content {
    min-height: calc(100vh - var(--header-height-desktop)); box-sizing: border-box;
    display: flex; flex-direction: column; justify-content: center;
    scroll-snap-align: start; scroll-snap-stop: always;
    scroll-margin-top: var(--header-height-desktop);
  }
}
.video-content__inner { display: flex; flex-direction: column; gap: 32px; }
@media (min-width: 1000px) { .video-content__inner { flex-direction: row; align-items: center; } }
.video-content__inner__description { flex: 1; }
.video-content__inner__description p { margin: 0 0 26px; }
/* aspect-ratio, not the old padding-top-percent hack -- that percentage
   resolves against the flex row's full width (both columns combined), not
   this column's own ~half share, so it rendered roughly 2x too tall and
   cropped the widescreen source down to a zoomed-in portrait sliver. */
.video-content__video { flex: 1; position: relative; aspect-ratio: 16 / 9; background: #000; }
.video-content__video iframe,
.video-content__video video {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  object-fit: cover; /* crops to fill the 16:9 box instead of letterboxing a mismatched clip */
}
.video-content__play {
  position: absolute; inset: 0; margin: auto;
  width: 56px; height: 56px; padding: 0; border: 0; background: transparent; cursor: pointer;
}
@media (min-width: 1000px) { .video-content__play { width: 88px; height: 88px; } }
.video-content__play svg { width: 100%; height: 100%; display: block; }
.video-content__video.is-playing .video-content__play { display: none; }

/* =========================================================
   Project slider / gallery (case studies)
   ========================================================= */
.project-slider, .project-gallery { background: var(--color-cream); scroll-margin-top: var(--header-height-mobile); }
/* On every snap-scroll page, Project Slider ("Recent Projects") -- or its
   video-stream replacement -- gets one clean locked landing when scrolled
   into -- everything after its own content is a standard scroll (see
   main.js). */
body.snap-scroll .project-slider, body.snap-scroll .video-stream:not(.video-stream--embedded) { scroll-snap-align: start; }
@media (min-width: 1000px) { .project-slider, .project-gallery { scroll-margin-top: var(--header-height-desktop); } }
.project-slider__inner, .project-gallery__inner { padding: 60px 0 70px; }
.project-slider__inner h2, .project-gallery__inner h2 { font-size: 26px; margin-bottom: 24px; }

.project-track {
  display: flex;
  width: 100%;
  min-width: 0;
  gap: 18px;
  overflow-x: auto;
  padding-bottom: 12px;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.project-track::-webkit-scrollbar { height: 6px; }
.project-track::-webkit-scrollbar-thumb { background: var(--color-grey); border-radius: 3px; }

.project-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
}
.project-grid .project-card { width: calc(50% - 15px); margin: 0 30px 30px 0; }
.project-grid .project-card:nth-child(2n) { margin-right: 0; }
@media (min-width: 567px) {
  .project-grid .project-card { width: calc(25% - 40px); margin: 0 40px 40px 0; }
  .project-grid .project-card:nth-child(2n) { margin-right: 40px; }
  .project-grid .project-card:nth-child(4n) { margin-right: 0; }
}

.project-track .project-card-wrap { flex: 0 0 220px; scroll-snap-align: start; }

.project-card {
  background: transparent;
  cursor: pointer;
  border: none;
  text-align: left;
  padding: 0;
  display: block;
}
.project-card__media { position: relative; overflow: hidden; background: #111; }
.project-card__media img { display: block; width: 100%; height: auto; margin-bottom: 10px; object-fit: cover; transition: transform .4s ease; }
@media (min-width: 1000px) { .project-card__media img { max-height: 356px; } }
.project-card:hover .project-card__media img { transform: scale(1.03); }
.project-card__play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.15);
}
.project-card__play svg { width: 46px; height: 46px; }
.project-card__title { display: block; padding: 0; margin: 0; font-family: var(--font-body); font-weight: 500; font-size: 13px; }
@media (min-width: 1000px) { .project-card__title { font-size: 15px; } }

/* lightbox / video modal */
.video-modal {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(0,0,0,.9);
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 32px;
  padding: 24px;
}
.video-modal[hidden] { display: none; }
/* .video-modal__inner and .video-modal__player are plain wrappers (no size
   of their own -- flex items shrink-wrap their content by default) so the
   video/iframe's own intrinsic aspect ratio, not a fixed 16:9 box, decides
   the shape: a square or portrait clip is never pillarboxed/letterboxed
   against a widescreen frame. openModal() sets that real ratio inline per
   video (from the same build-time-probed dimensions the video stream tiles
   use); the aspect-ratio below is only the fallback for the rare case it's
   not known (e.g. a legacy Vimeo embed). */
.video-modal__inner { position: relative; }
.video-modal__inner iframe,
.video-modal__inner video {
  display: block; width: auto; height: auto;
  max-width: min(1000px, 90vw); max-height: calc(100vh - 120px);
  aspect-ratio: 16 / 9;
  border: 0; background: #000;
}
.video-modal__close {
  position: absolute; top: -44px; right: 0; background: transparent; border: none;
  color: var(--color-white); font-size: 32px; line-height: 1; padding: 6px;
}
/* A side panel, not text crammed below the video: the gap above is what
   keeps it off the video's edge, and every field in here (currently just
   the title -- description/credits land the same way later) is a plain
   block-level child, so they automatically share this same left edge with
   no per-field indent needed. .video-modal's own align-items:center then
   centers this whole stack, as one unit, against the video's height --
   not each field individually. Wraps below the video on narrow viewports
   where there's no room beside it. */
.video-modal__info {
  display: flex; flex-direction: column; gap: 6px;
  max-width: 320px; color: var(--color-white);
}
.video-modal__caption { margin: 0; font-size: 16px; font-weight: 700; }

/* =========================================================
   Video stream -- an auto-scrolling, self-looping row of project videos.
   Every tile shares one fixed height; width comes purely from the
   aspect-ratio set inline per item (from that video's own poster image),
   so a square clip and a widescreen TVC sit side by side undistorted.
   The row is duplicated once in the markup and the track animates exactly
   -50% of its own (doubled) width, which is a seamless loop for free --
   no JS width bookkeeping needed for the loop itself.
   ========================================================= */
.video-stream { background: var(--color-cream); overflow: hidden; }
.video-stream__inner { padding: 60px 0 0; }
.video-stream__inner h2 { font-size: 26px; margin-bottom: 24px; }
.video-stream__viewport { overflow: hidden; padding: 20px 0 60px; }
/* the drift is a transform applied by JS every frame, not a CSS @keyframes
   loop -- see main.js -- so hovering a tile still sliding in from the right
   can be caught up into full view faster, then held there, and pausing
   generally can hold at whatever position hover found it at rather than
   only ever at a CSS-animation-frame boundary */
.video-stream__track { display: flex; align-items: flex-start; gap: 0; width: max-content; }
/* width comes from --tile-w-mobile/--tile-w-desktop (set inline per tile,
   see VideoStream.njk and buildVideoTile() in main.js) rather than the CSS
   aspect-ratio property -- it needs to be computed from the image area's
   height alone (this height minus the caption strip below), not the tile's
   full height, or the image ends up proportionally wider than the source
   video and object-fit:cover crops its top and bottom to compensate. */
.video-stream__item { flex-shrink: 0; height: 232px; width: var(--tile-w-mobile, auto); }
@media (min-width: 1000px) { .video-stream__item { height: 316px; width: var(--tile-w-desktop, auto); } }
/* the title sits as a normal row below the media (not an overlay), so the
   card is a column flexbox: media takes whatever's left after the title's
   own natural height, keeping every tile's *total* height the same fixed
   row height regardless of title length. It stays part of the same moving
   .video-stream__item, so it scrolls together with its thumbnail exactly
   like everything else in the row -- nothing pins it in place. */
.video-stream__item .project-card { height: 100%; position: relative; display: flex; flex-direction: column; }
.video-stream__item .project-card__media { position: relative; flex: 1 1 auto; min-height: 0; }
.video-stream__item .project-card__media img { width: 100%; height: 100%; object-fit: cover; max-height: none; margin-bottom: 0; }
.video-stream__item .project-card__preview { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1; }
.video-stream__item .project-card.is-previewing .project-card__play { opacity: 0; }
/* no color/shadow override here -- it inherits the same title styling used
   everywhere else on the site (.project-card__title further up), so it
   reads as normal site text rather than a photo-overlay caption */
/* a fixed height, not "however many lines this title actually needs" -- a
   2-line title otherwise steals extra flex space from the image at the
   exact moment it wraps, shrinking that one tile's image and shifting it
   relative to its neighbours. Reserving room for 2 lines always, with
   line-clamp as a hard backstop, means the image's height never depends on
   any particular title's length. */
.video-stream__item .project-card__title {
  flex: 0 0 48px; padding-top: 8px; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
@media (min-width: 1000px) { .video-stream__item .project-card__title { flex-basis: 54px; } }
@media (prefers-reduced-motion: reduce) {
  /* main.js checks this too and never starts the drift at all; this just
     turns the now-static track into a manually-scrollable strip */
  .video-stream__viewport { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* =========================================================
   Banner (simple image strip)
   ========================================================= */
.banner__inner img { width: 100%; height: 300px; object-fit: cover; }

/* =========================================================
   Clients / logo strip
   ========================================================= */
.clients { background: var(--color-white); padding: 50px 0; text-align: center; }
.clients h2 { font-size: 20px; margin-bottom: 30px; }
.clients p { font-size: 11px; margin: 0 0 26px; }
@media (min-width: 1000px) { .clients p { font-size: 15px; } }
.clients__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  align-items: center; justify-items: center;
  column-gap: 36px; row-gap: 27px;
}
/* fixed-size box (not just a max-height) so every logo reads as the same
   size regardless of how much internal padding its source file has --
   object-fit scales each mark to fit without cropping or stretching */
.clients__grid img { display: block; height: 46px; width: 100%; max-width: 130px; object-fit: contain; filter: grayscale(1); opacity: .75; }

/* =========================================================
   Compare table
   ========================================================= */
.compare-table { background: var(--color-white); padding: 60px 0; }
@media (min-width: 1000px) { .compare-table { padding: 90px 0 75px; } }
.compare-table__inner { margin: 0 auto; max-width: 650px; padding: 0 20px; width: 100%; }
.compare-table h2 { font-size: 33px; text-align: center; margin: -5px 0 30px; }
@media (min-width: 1000px) { .compare-table h2 { font-size: 43px; } }
.compare-table__scroll { margin: 0 auto; max-width: 1100px; overflow-x: auto; padding: 0 20px; width: 100%; }
.compare-table__matrix { border-collapse: collapse; display: none; table-layout: fixed; width: 100%; }
@media (min-width: 1000px) { .compare-table__matrix { display: table; } }
.compare-table__matrix th, .compare-table__matrix td { line-height: 1.3; padding: 13px 16px; vertical-align: middle; }
.compare-table__matrix thead th { background: var(--color-white); font-family: var(--font-heading); font-size: 16px; text-align: center; }
.compare-table__matrix thead th:first-child { text-align: left; width: 28%; }
/* height:auto is required here, not decorative -- these <img> tags carry
   HTML width/height attributes (for the browser's layout-shift prevention),
   which the UA stylesheet maps into an implicit height. That competes with
   aspect-ratio: per spec, aspect-ratio only fills in a dimension that's
   genuinely auto, so without this, the attribute silently wins and the
   image renders at its raw natural height (e.g. 922px) squeezed into
   whatever narrow column width:100% gives it, instead of the intended
   210:160 crop. */
.compare-table__matrix thead img { aspect-ratio: 210 / 160; border-radius: 8px; display: block; height: auto; margin: 0 auto 12px; object-fit: cover; width: 100%; }
.compare-table__matrix thead th > span { display: block; margin-bottom: 12px; }
.compare-table__matrix tbody tr:not(.compare-table__section-row):nth-child(even) { background: var(--color-grey-light); }
.compare-table__matrix tbody tr:not(.compare-table__section-row):nth-child(odd) { background: var(--color-white); }
.compare-table__matrix tbody th[scope="row"] { font-size: 12px; font-weight: 400; text-align: left; }
.compare-table__matrix tbody td { font-family: var(--font-heading); font-size: 13px; font-weight: 700; text-align: center; }
.compare-table__matrix .compare-table__section-row { background: var(--color-white); }
.compare-table__matrix .compare-table__section-row th { font-family: var(--font-heading); font-size: 13px; font-weight: 700; padding: 30px 0 10px; text-align: left; }
.compare-table__items { display: none; }
@media (min-width: 1000px) {
  .compare-table__items {
    display: flex; flex-wrap: nowrap; align-items: flex-start;
    max-width: var(--container-max); margin: 0 auto; padding: 0 20px; gap: 20px;
  }
}
.compare-table__item { text-align: center; flex: 1 1 0; min-width: 220px; }
.compare-table__item img { aspect-ratio: 210 / 160; border-radius: 8px; display: block; height: auto; object-fit: cover; width: 100%; }
.compare-table__item h4 { font-family: var(--font-heading); font-size: 16px; font-weight: 700; line-height: 22px; margin: 12px 0; }
.compare-table__item .btn { margin-bottom: 10px; }
.compare-table__features { margin: 0 0 40px; }
.compare-table__features h5 { background: var(--color-white); font-family: var(--font-heading); font-size: 12px; height: 20px; margin: 0 0 10px; }
.compare-table__features ul { list-style: none; margin: 0; padding: 0; }
.compare-table__features ul li { background: var(--color-grey-light); margin: 0; padding: 10px 0; text-align: center; }
.compare-table__features ul li:nth-child(2n) { background: var(--color-white); }
.compare-table__features ul li span { display: block; margin: 0; }
.compare-table__features ul li span:first-of-type { font-size: 11px; line-height: 1.2; opacity: .7; }
.compare-table__features ul li span:last-of-type { font-family: var(--font-heading); font-size: 13px; font-weight: 700; line-height: 1.2; }

/* mobile: shared label column + one value column per product, instead of
   the desktop's independent per-product stacked cards */
.compare-table__mobile { display: block; padding: 0 20px; }
@media (min-width: 1000px) { .compare-table__mobile { display: none; } }
.compare-table__mobile-images { display: flex; gap: 10px; margin-bottom: 20px; }
.compare-table__mobile-images img { aspect-ratio: 210 / 160; border-radius: 8px; display: block; flex: 1 1 0; height: auto; object-fit: cover; width: 100%; }
.compare-table__mobile-titles {
  border-top: 1px solid var(--color-grey-light); border-bottom: 1px solid var(--color-grey-light);
  display: flex; justify-content: flex-end; margin-bottom: 20px;
}
.compare-table__mobile-title { padding: 8px 0; text-align: center; width: calc(60% / var(--compare-products, 3)); }
.compare-table__mobile-title a { color: var(--color-accent); font-family: var(--font-heading); font-size: 13px; font-weight: 700; }
.compare-table__mobile-features { margin: 0 0 24px; }
.compare-table__mobile-features h5 { font-family: var(--font-heading); font-size: 13px; font-weight: 700; margin: 0 0 10px; }
.compare-table__mobile-feature { display: flex; }
.compare-table__mobile-feature ul { list-style: none; margin: 0; padding: 0; width: calc(60% / var(--compare-products, 3)); }
.compare-table__mobile-feature ul:first-child { width: 40%; }
.compare-table__mobile-feature ul li { background: var(--color-grey-light); font-size: 11px; line-height: 1.3; padding: 10px 4px; text-align: center; }
.compare-table__mobile-feature ul:first-child li { padding-left: 0; text-align: left; }
.compare-table__mobile-feature ul li:nth-child(2n) { background: var(--color-white); }

.eyebrow { font-family: var(--font-heading); font-weight: 700; text-transform: uppercase; letter-spacing: .08em; font-size: 13px; color: var(--color-accent); }

/* =========================================================
   Studio block ("features features--studio" on the original --
   a click-a-thumbnail-to-swap-the-hero-image gallery, shared by
   the robot product pages (BOLT, BOLT Jr+, Cinebot Mini) and Studios)
   ========================================================= */
.features--studio .features__inner { max-width: 1280px; padding: 30px 0 0; }
@media (min-width: 1000px) { .features--studio .features__inner { padding: 80px 20px; } }
/* the gallery and content+features-list halves render as two adjacent
   <section>s (see Studio.njk) so each can snap/fill independently on
   snap-scroll pages -- a modest gap at their shared edge keeps them
   reading as two distinct sections (the photo grid, then the write-up)
   rather than one merged block, while still nowhere near the full
   80px section padding stacked on both sides */
.features--studio-gallery .features__inner { padding-bottom: 40px; }
.features--studio-content .features__inner { padding-top: 40px; }
.features--studio .features__inner .content { padding: 0 20px; }
@media (min-width: 1000px) { .features--studio .features__inner .content { padding: 0; } }
.features--studio .features__inner .features-list { padding: 0 20px; }
@media (min-width: 1000px) { .features--studio .features__inner .features-list { padding: 0; } }

/* Desktop: main image across two-thirds of the row, thumbnails in a fixed-height
   grid filling the remaining third. .gallery gets a deterministic height via
   aspect-ratio -- derived from the main column's own width-driven height -- and
   every other box below it (including on snap-scroll pages, where a separate
   viewport-height override plus a flex-centred "contain" main image previously
   made the whole chain hard to reason about and caused the caption to render
   outside the image and the two columns to drift out of alignment) is just a
   plain, unambiguous percentage of that one known height. Mobile keeps the
   original stacked arrangement (full-width photo, scroll strip of thumbnails
   below it). */
.gallery { margin-bottom: 20px; width: 100%; }
@media (min-width: 1000px) {
  .gallery { display: flex; align-items: stretch; gap: 20px; aspect-ratio: 2073 / 922; }
}

.gallery__main { margin-bottom: 2px; padding: 0 10px; position: relative; width: 100%; }
@media (min-width: 1000px) { .gallery__main { width: 66.6667%; height: 100%; margin-bottom: 0; padding: 0; flex-shrink: 0; } }
.gallery__main img { margin: 0; width: 100%; display: block; aspect-ratio: 1382 / 922; object-fit: cover; }
@media (min-width: 1000px) { .gallery__main img { height: 100%; } }
.gallery__main h4 {
  position: absolute; bottom: 30px; left: 30px;
  color: var(--color-white); font-family: var(--font-heading);
  font-size: 25px; line-height: 30px; margin: 0;
  /* a soft dark halo rather than a hard offset shadow, so the white caption
     stays legible over light backgrounds (e.g. a grey studio product shot)
     without looking like a heavy drop shadow over darker photos */
  text-shadow: 0 1px 3px rgba(0,0,0,.65), 0 2px 12px rgba(0,0,0,.4);
}
@media (min-width: 1000px) { .gallery__main h4 { bottom: 40px; left: 40px; font-size: 32px; line-height: 40px; } }

.gallery__items { display: flex; flex-wrap: nowrap; overflow-x: scroll; padding-left: 10px; -webkit-overflow-scrolling: touch; }
.gallery__items img { height: auto; flex-shrink: 0; width: 35%; margin-right: 2.6667%; margin-bottom: 2.6667%; cursor: pointer; }
@media (min-width: 1000px) {
  /* a grid with a fixed row count (--gallery-rows, set per-page in Studio.njk),
     given 100% of .gallery's aspect-ratio-derived height (see above) divided
     evenly across those rows -- so the last row's bottom edge always lands
     exactly on the main image's bottom edge, not just approximately. Three
     even columns at 33.3333% width times that height-driven row count works
     out to very close to square given the 1382:922 main-image ratio this
     column width was chosen against, without needing to force a 1:1
     aspect-ratio (which fought the exact-height-match requirement instead). */
  .gallery__items {
    width: 33.3333%; overflow-x: visible; padding-left: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(var(--gallery-rows, 3), 1fr);
    gap: 12px;
    height: 100%;
  }
  .gallery__items img {
    width: 100%; height: 100%; margin: 0; aspect-ratio: auto; object-fit: cover;
  }
}

.features--studio .content h3 { font-size: 30px; line-height: 38px; font-weight: 700; margin: 0 0 16px; }
@media (min-width: 1000px) { .features--studio .content h3 { margin-bottom: 26px; } }

.features-list { width: 100%; }
@media (min-width: 1000px) { .features__inner .features-list { width: 30%; } }
.features-list h5 { font-family: var(--font-body); font-size: 14px; font-weight: 500; margin: 0 0 35px; }
@media (min-width: 1000px) { .features-list h5 { font-size: 16px; } }
.features-list ul { margin-left: 0; list-style: none; padding: 0; }
.features-list ul li.features-item { display: flex; align-items: flex-start; font-size: 13px; margin-bottom: 11px; }
@media (min-width: 1000px) { .features-list ul li.features-item { margin-bottom: 15px; } }
.features-list ul li.features-item p { font-size: 13px; margin: 0; }
@media (min-width: 1000px) { .features-list ul li.features-item p { font-size: 15px; } }
.features-list ul li.features-item img { height: auto; width: 30px; margin: -3px 28px 0 0; flex-shrink: 0; }

/* =========================================================
   FAQ accordion (see the Q&A regrouping in main.js)
   ========================================================= */
.faq-item { border-bottom: 1px solid var(--color-grey-light); margin: 0; padding: 0; }
.faq-item summary {
  cursor: pointer; list-style: none;
  font-size: 16px; font-weight: 700; line-height: 1.3;
  padding: 9px 0 9px 32px; position: relative;
}
@media (min-width: 1000px) { .faq-item summary { font-size: 18px; } }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+"; color: var(--color-accent); font-size: 22px; font-weight: 400; line-height: 1;
  position: absolute; left: 4px; top: 9px;
}
.faq-item[open] summary::after { content: "\2212"; }
.faq-item p:last-child { margin-bottom: 0; }
.faq-answer { padding: 0 0 9px 32px; }
.faq-answer p:first-child { margin-top: 0; }
.faq-list .faq-answer p:last-child { margin-bottom: 0; }
.faq-list .content { width: 100%; max-width: 980px; }
/* An intro Features block feeding straight into a FaqList accordion (e.g. Terms &
   Conditions) would otherwise stack two 80px section paddings, plus the intro's own
   last-paragraph margin, on top of each other -- zero both out so the gap above the
   first group matches .faq-group's own margin-top, same as every group after it. */
.features:has(+ .faq-list) .features__inner { padding-bottom: 0; }
.features:has(+ .faq-list) .content p:last-of-type { margin-bottom: 0; }
.features + .faq-list .features__inner { padding-top: 0; }
.faq-group { margin-top: 24px; }
.faq-group > h3 { font-size: 25px; line-height: 1.2; margin: 0 0 6px; }
.faq-group > p { margin-bottom: 10px !important; }
.faq-answer table { border-collapse: collapse; margin: 4px 0 10px; width: 100%; }
.faq-answer th, .faq-answer td { border-bottom: 1px solid var(--color-grey-light); padding: 8px 12px; text-align: left; vertical-align: top; }
.faq-answer th:first-child, .faq-answer td:first-child { padding-left: 0; }
.faq-answer th { font-weight: 700; }
@media (max-width: 566px) {
  .faq-answer { overflow-x: auto; }
  .faq-answer table { min-width: 520px; }
}

/* Related service links keep important topic clusters connected for visitors and crawlers. */
.related-links { padding-top: 64px; padding-bottom: 64px; }
.related-links h2 { margin-bottom: 20px; }
.related-links ul { display: flex; flex-wrap: wrap; gap: 10px 24px; list-style: none; margin: 0 0 28px; padding: 0; }
.related-links li { margin: 0; }
.related-links li a { text-decoration: underline; text-underline-offset: 3px; }

.breadcrumbs { padding-top: 86px; padding-bottom: 14px; }
.has-hero .breadcrumbs { position: absolute; left: 0; right: 0; color: #fff; z-index: 4; }
.breadcrumbs ol { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0; }
.breadcrumbs li { font-size: 12px; margin: 0; }
.breadcrumbs li:not(:last-child)::after { content: "/"; margin-left: 6px; opacity: .65; }
.breadcrumbs a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }


/* =========================================================
   Contact form + map
   ========================================================= */
.contact-form { background: var(--color-white); padding: 60px 0 20px; position: relative; }
/* Only the homepage treats the contact form as a snap stop -- see the
   Project Slider comment above. */
body.home .contact-form { scroll-snap-align: start; }
@media (min-width: 1000px) { body.home .contact-form { scroll-margin-top: var(--header-height-desktop); } }
.contact-form__inner { display: flex; flex-direction: column; gap: 40px; max-width: 1020px; padding: 0 24px; }
.contact-form form { margin: 0; max-width: 400px; width: 100%; }
.contact-form .info { display: flex; flex-direction: column; justify-content: space-between; }
.contact-form .info h3 { font-size: 24px; font-weight: 700; color: var(--color-black); margin: 0 0 40px; }
.contact-socials { align-items: center; display: flex; gap: 24px; margin: 0; }
.contact-socials a { align-items: center; display: flex; height: 22px; justify-content: center; width: 22px; }
.contact-socials svg { fill: none; height: 20px; stroke: currentColor; stroke-width: 2; width: 22px; }
.contact-socials .social-icon-fill { fill: currentColor; stroke: none; }
.contact-socials .social-icon-play { fill: var(--color-white); stroke: none; }
.contact-socials__imdb { background: var(--color-black); border-radius: 2px; color: var(--color-white); font-family: Arial, sans-serif; font-size: 8px; font-weight: 900; letter-spacing: -.4px; line-height: 1; width: 25px !important; }
.contact-socials a:hover { color: var(--color-accent); }
.contact-socials__imdb:hover { background: var(--color-accent); color: var(--color-white) !important; }
.contact-form label.visually-hidden { display: block; }
.contact-form input {
  background: transparent; border: 0; border-bottom: 1px solid var(--color-black);
  border-radius: 0; box-shadow: none; font-family: var(--font-body); font-size: 16px;
  margin: 0 0 24px; outline: none; padding: 0 0 8px; width: 100%;
}
.contact-form input:focus { border-bottom-color: var(--color-accent); }
.contact-form input::placeholder { color: var(--color-black); opacity: 1; }
.contact-form form .btn { min-width: 100px; width: auto; }
.form-status { font-size: 13px; margin-top: 10px; }
.form-status[data-state="success"] { color: #0a7d3c; }
.form-status[data-state="error"] { color: #c0392b; }
/* SES-Lambda contact form (see CONTACT_FORM_SETUP.md). */
.contact-form form.contact .form-status { width: 100%; margin: 12px 0 0; min-height: 1.2em; font-size: 14px; }
.contact-form form.contact .form-status.is-error { color: #c0392b; }

/* "Message sent" popup -- centred over the page, closed by the visitor. The
   form itself is left reset in place underneath, ready for another note. */
.contact-modal {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, .6);
  animation: contact-modal-fade .2s ease both;
}
.contact-modal[hidden] { display: none; }
.contact-modal__card {
  position: relative;
  width: 100%; max-width: 400px;
  padding: 44px 32px 32px;
  background: var(--color-cream);
  color: var(--color-text);
  text-align: center;
  border-radius: 4px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .35);
  animation: contact-modal-pop .22s ease both;
}
.contact-modal__close {
  position: absolute; top: 6px; right: 12px;
  padding: 6px; border: 0; background: transparent;
  font-size: 28px; line-height: 1; color: var(--color-text); cursor: pointer;
}
.contact-modal__title { margin: 0 0 8px; font-size: 22px; }
.contact-modal__text { margin: 0 0 24px; font-size: 15px; }
.contact-modal__ok { cursor: pointer; }
@keyframes contact-modal-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes contact-modal-pop {
  from { opacity: 0; transform: translateY(10px) scale(.97); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .contact-modal, .contact-modal__card { animation: none; }
}
@media (min-width: 567px) {
  .contact-form__inner { flex-direction: row; justify-content: space-between; }
  .contact-form .info { margin-right: 30px; }
}
@media (min-width: 813px) {
  .contact-form .info { margin-right: 0; max-width: 510px; width: 47%; }
  .contact-form .info h3 { font-size: 40px; }
}
@media (min-width: 1000px) {
  .contact-form { align-items: center; display: flex; justify-content: center; min-height: 80vh; }
  .contact-form .info h3 { line-height: 50px; margin-bottom: 0; }
  .contact-form input { font-size: 14px; margin-bottom: 38px; }
}
@media (min-width: 1240px) { .contact-form__inner { padding: 25px 0; } }

/* Map left / text right, matching heights -- same "media out of flow,
   content sets the row height" technique as .repeater__item (see above),
   just without that block's snap-scroll header-clearance case: this section
   is never a snap stop (not in main.js's snapSelector), so the media never
   needs to start anywhere but flush with the text column beside it. */
.contact-map { position: relative; background: var(--color-cream); }
.contact-map__media { position: relative; overflow: hidden; height: 320px; background: var(--color-grey-light); }
.contact-map__media iframe { width: 100%; height: 100%; border: 0; display: block; }
.contact-map__text { padding: 40px 24px; }
.contact-map__text-inner { max-width: 480px; }
.contact-map__text h2 { font-size: 26px; margin: 0 0 16px; }
.contact-map__address { font-weight: 700; font-size: 15px; margin: 0 0 16px; }
.contact-map__text p { font-size: 13px; line-height: 20px; margin: 0; }
@media (min-width: 1000px) {
  .contact-map { display: flex; min-height: 480px; }
  .contact-map__media {
    position: absolute; top: 0; left: 0; bottom: 0;
    width: 50%; height: auto;
  }
  .contact-map__text {
    margin-left: 50%; width: 50%; box-sizing: border-box;
    display: flex; align-items: center; padding: 60px 80px;
  }
  .contact-map__text h2 { font-size: 33px; }
  .contact-map__address { font-size: 16px; }
  .contact-map__text p { font-size: 15px; line-height: 24px; }
}

/* =========================================================
   Footer
   ========================================================= */
.footer { background: var(--color-black); color: var(--color-white); }
.footer__inner {
  max-width: var(--container-max); margin: 0 auto; padding: 28px 20px 30px;
  display: flex; flex-direction: column; gap: 24px;
}
@media (min-width: 813px) { .footer__inner { flex-direction: row; align-items: center; justify-content: space-between; } }
.footer .logo { width: 154px; height: auto; margin-bottom: 10px; filter: brightness(0) saturate(100%) invert(100%); }
.footer p { font-size: 12px; font-weight: 500; margin-bottom: 40px; max-width: 400px; opacity: .85; }
@media (min-width: 813px) { .footer p { margin-bottom: 0; } }
.footer ul li { font-size: 13px; margin-bottom: 6px; }
.footer ul li a { text-decoration: underline; }
.footer .footer-legal { font-size: 11px; opacity: .6; margin-top: 10px; }
.footer .footer-legal a { text-decoration: underline; }

/* =========================================================
   404 / misc
   ========================================================= */
.error-404 { padding: 160px 20px 100px; text-align: center; }
.content-placeholder { padding: 140px 20px 100px; }
