/* ==========================================================================
   MEI VENTURES — High-End AI Landing Page Design System
   ========================================================================== */

:root {
  /* Color Palette */
  --bg-primary: #060608;
  --bg-secondary: #0d0d10;
  --bg-card: rgba(18, 18, 22, 0.7);
  --bg-card-border: rgba(255, 255, 255, 0.08);
  --bg-card-border-hover: rgba(255, 255, 255, 0.22);
  
  --accent-red: #ff2a00;
  --accent-red-glow: rgba(255, 42, 0, 0.45);
  --accent-crimson: #ff3b14;
  --accent-orange: #ff6a00;

  --text-primary: #ffffff;
  --text-secondary: #909099;
  --text-muted: #5e5e66;
  --text-inverse: #08080a;

  /* Typography */
  --font-display: 'Inter Tight', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-accent: 'Syne', sans-serif;

  /* Transitions */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out-smooth: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Base Reset & Smooth Scroll */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  background-color: var(--bg-primary);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body {
  background-color: var(--bg-primary);
  min-height: 100vh;
  position: relative;
  overflow-x: hidden;
  line-height: 1.5;
}

body.is-loading {
  overflow: hidden;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  max-width: 100%;
  display: block;
  user-select: none;
}

button {
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

/* ==========================================================================
   PRELOADER
   ========================================================================== */
.preloader {
  position: fixed;
  inset: 0;
  /* Pure black, matched to the video's own background rather than the site's
     --bg-primary (#060608). Sampling the clip's corners at several timestamps
     returns 0,0,0 throughout, so a 6,6,8 backdrop left the video's edges
     visible as a slightly lighter rectangle. This applies to the intro overlay
     only; the page behind it keeps the site background. */
  background: #000;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 0.9s must stay in step with FADE_LEAD in script.js, which starts the fade
     that far before the video ends so the two finish together. */
  transition: opacity 0.9s var(--ease-in-out-smooth), visibility 0.9s;
}

/* Driven by a class rather than inline styles so the fade and the
   pointer-events release happen in one place. */
.preloader.is-hiding {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* Centred and capped rather than filling the screen.

   Full-bleed `cover` had two costs. It cropped hard on anything that is not
   16:9 -- a portrait phone showed only ~25% of the frame width, cutting most
   of the logo animation out of view. And it stretched the 1920px source across
   a 2x-DPR desktop, needing 3840px and upscaling 2x, which softened it.

   Capping the box at 900px means the widest it is ever drawn is 1800 device
   pixels on a 2x display -- just under the source's own 1920, so it is always
   downscaled and never blurred. `contain` keeps the whole frame visible at
   every viewport. The letterbox around it is the same near-black as the
   overlay, so it reads as space rather than as bars. */
.preloader-video {
  width: min(86vw, 900px);
  height: auto;
  max-height: 80vh;
  object-fit: contain;
  display: block;
  pointer-events: none;
}

/* Anyone who asks for reduced motion gets the page, not a 5-second film. */
@media (prefers-reduced-motion: reduce) {
  .preloader { transition-duration: 0.2s; }
}

/* Video and bar as one centred column, so they stay together at any viewport
   and fade out as a single unit with the overlay. */
.preloader-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.preloader-progress-bar {
  width: min(60vw, 220px);
  height: 2px;
  margin-top: 30px;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 3px;
  overflow: hidden;
}

/* Scaled, not resized.

   Animating `width` re-runs layout on every update, and the value was only
   being refreshed on the video's `timeupdate` event -- which fires roughly 4
   times a second, so the bar visibly stepped. This is now a full-width element
   squashed with scaleX and driven once per animation frame from the video
   clock: transform is composited on the GPU, so it never touches layout. */
.preloader-progress-fill {
  width: 100%;
  height: 100%;
  background: #ffffff;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
  transform: scaleX(0);
  transform-origin: left center;
  will-change: transform;
}

/* ==========================================================================
   FIXED SITE HEADER
   ========================================================================== */
.site-header {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 100;
  padding: 24px 48px;
  pointer-events: none;
}

/* Grid, not flex + space-between. Space-between spaces the three items evenly
   from EACH OTHER, so the nav lands at the midpoint of the leftover gap and
   drifts by half the difference between the logo and button widths -- it sat
   28.9px left of centre, visibly off against the centred hero text. A centre
   column of `auto` between two equal `1fr` rails pins the nav to the true
   centre no matter how wide the logo or button get. */
.header-inner {
  max-width: 1600px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  pointer-events: auto;
}

.header-logo {
  justify-self: start;
}

.btn-connect {
  justify-self: end;
}

.header-logo {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  /* It reloads the page now, so it needs the affordance of a control. No hover
     scaling -- the mark itself stays static, as before. */
  cursor: pointer;
}

.header-logo:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.6);
  outline-offset: 6px;
  border-radius: 4px;
}

.nav-logo-img {
  /* Matched to the rendered height of a nav link (21.6px) so the mark reads at
     the same scale as Home / About / Products. */
  height: 22px;
  width: auto;
}

.main-nav {
  display: flex;
  align-items: center;
  gap: 36px;
}

.nav-link {
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.75);
  transition: color 0.2s ease;
}

.nav-link:hover {
  color: #ffffff;
}

.btn-connect {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: #ffffff;
  font-family: var(--font-body);
  /* Same type size and weight as the nav links; padding trimmed so the pill
     sits closer to their height instead of towering over them. */
  font-size: 0.9rem;
  font-weight: 500;
  padding: 6px 18px;
  border-radius: 100px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: background 0.25s ease, border-color 0.25s ease, transform 0.25s var(--ease-out-expo);
}

.btn-connect:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.3);
  transform: translateY(-2px);
}

/* ==========================================================================
   PAGE WRAPPER & MAIN SECTIONS
   ========================================================================== */
.page-wrapper {
  position: relative;
  z-index: 10;
  /* No bottom padding: the footer is the last thing on the page, and padding
     here left 100px of empty space below it at full scroll. */
}

/* ==========================================================================
   HERO SECTION
   ========================================================================== */
.hero-section {
  position: relative;
  width: 100%;
  min-height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 140px 48px 80px 48px;
}

.hero-bg-media {
  position: absolute;
  inset: 0;
}

.hero-bg-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 75% 20%;
  opacity: 0.55;
  transform: scale(1.02);
  transition: transform 1.4s var(--ease-out-expo);
}

.hero-bg-gradient {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(6, 6, 8, 0.2) 0%, rgba(6, 6, 8, 0.55) 75%, rgba(6, 6, 8, 0.9) 100%),
    linear-gradient(90deg, rgba(6, 6, 8, 0.85) 0%, rgba(6, 6, 8, 0.35) 45%, rgba(6, 6, 8, 0.1) 100%);
  pointer-events: none;
}

.hero-content {
  position: relative;
  z-index: 2;
  max-width: 1600px;
  margin: 0 auto;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero-title {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 4.4vw, 3.6rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: #ffffff;
  max-width: 700px;
}

.hero-desc {
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.6);
  /* Wide enough for the second line to stay whole. At 500px the line after the
     <br> overflowed and dropped "Technology." onto a third line. */
  max-width: 660px;
  margin-top: 24px;
}

/* Blinking caret for the typed-out hero description. `steps(1, end)` gives a
   hard on/off blink rather than a fade. The script locks the paragraph's box to
   its finished size first, so the line below never reflows while typing. */
.hero-caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin-left: 3px;
  /* Cancels its own 5px advance so the caret can never be what pushes a full
     line over the wrap point -- without this it dropped to a line of its own
     once the last line filled, growing the block from two lines to three. */
  margin-right: -5px;
  background: currentColor;
  vertical-align: text-bottom;
  animation: heroCaretBlink 1s steps(1, end) infinite;
}

@keyframes heroCaretBlink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-caret { animation: none; }
}

.hero-cta-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 36px;
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: #ffffff;
  color: #08080a;
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 600;
  padding: 14px 24px;
  border-radius: 100px;
  transition: transform 0.3s var(--ease-out-expo), box-shadow 0.3s ease;
}

.btn-primary svg {
  width: 13px;
  height: 13px;
  transition: transform 0.25s ease;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 30px rgba(255, 255, 255, 0.2);
}

.btn-primary:hover svg {
  transform: translate(2px, -2px);
}

.btn-secondary {
  display: inline-flex;
  align-items: center;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: #ffffff;
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 600;
  padding: 14px 24px;
  border-radius: 100px;
  transition: background 0.25s ease, border-color 0.25s ease, transform 0.3s var(--ease-out-expo);
}

.btn-secondary:hover {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.35);
  transform: translateY(-2px);
}

/* ==========================================================================
   TRUSTED-BY BAR
   ========================================================================== */
.trust-section {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  padding: 40px 48px;
}

.trust-container {
  max-width: 1600px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
}

.trust-label {
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}

.trust-logos {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 24px;
  column-gap: 22px;
}

.trust-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* Sized to its own content, NOT an equal share of the bar.
     With `flex: 1 1 0` every item got an identical box, but the marks inside
     differ in width by more than 2x -- so a wide one (Tailwind.CSS) sat flush
     against its box edges while a narrow one (R3F) left 36px of slack on each
     side. The eye reads the gap between the visible marks, so those gaps
     ranged 31px to 79px despite the boxes being perfectly equal. Letting each
     box hug its content means box gap == visual gap, and space-between then
     makes every one of them identical. */
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.65);
}

/* Below roughly 1250px the row no longer fits on one line, and space-between
   is the wrong tool once it wraps: it stretches a partial last row across the
   full width, so three leftover items sat 169px apart. Centring with a fixed
   column-gap keeps every gap identical on every row. */
@media (max-width: 1250px) {
  .trust-logos {
    justify-content: center;
    column-gap: 34px;
  }
}

/* Every mark is normalised to a common optical height; width follows each
   mark's own aspect ratio so nothing gets squashed into a forced square. */
.trust-icon {
  height: 18px;
  width: auto;
  flex-shrink: 0;
  /* Each viewBox bounds its artwork exactly, so the SVG root's default
     overflow:hidden shaves the anti-aliased outer edge and flattens curves
     (visible on React's ellipse tips). Let the fringe render instead of
     padding the viewBox, which would shrink the mark. */
  overflow: visible;
}

.trust-icon-img {
  object-fit: contain;
}

/* Optical size normalisation.

   Equal box heights do NOT give equal-looking marks: a wide mark at 18px tall
   reads much larger than a square one, and marks with slack in their artwork
   (Next.js) or a wide aspect (TypeScript, Tailwind) draw short inside the box.

   So each height below is derived from the mark's MEASURED drawn ink, scaled so
   that sqrt(inkWidth x inkHeight) -- the geometric mean, i.e. equal visual area
   -- lands on ~17.8px for every logo. Re-measure before changing these. */
.trust-icon-react    { height: 16.9px; }
.trust-icon-nextjs   { height: 21.1px; }
.trust-icon-ts       { height: 14.4px; }
.trust-icon-tailwind { height: 13.9px; }
.trust-icon-gsap     { height: 18.9px; }
.trust-icon-threejs  { height: 17.9px; }
.trust-icon-r3f      { height: 19.5px; }
.trust-icon-supabase { height: 18.2px; }
.trust-icon-stripe   { height: 18px; }
.trust-icon-resend   { height: 17.8px; }
.trust-icon-vercel   { height: 16.9px; }

/* Even out the gap between each mark and its label. The flex `gap` is uniform,
   but visible ink does not always reach the edge of its box: the Next.js logo
   fades to zero opacity, leaving ~1.9px of dead space and a visibly wider gap
   than its neighbours. Every other mark already sits within ~0.9px of 8px,
   which is below the noise floor of subpixel rendering -- correcting those
   individually measured WORSE, so this deliberately fixes only the outlier. */
.trust-icon-nextjs { margin-right: -1.85px; }

/* ==========================================================================
   HIGHLIGHTS ROW (3 COLUMN)
   ========================================================================== */
/* Trust bar + highlights share one viewport-tall column. The trust bar keeps
   its natural height and the highlights row absorbs whatever is left, so with
   the trust bar at the top of the frame the highlights fill the screen. */
.viewport-block {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.highlights-section {
  padding: 90px 48px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  flex: 1;
  display: flex;
  align-items: center;
}

.highlights-container {
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 56px;
}

.highlight-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.highlight-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  margin-bottom: 20px;
}

.highlight-icon svg {
  width: 20px;
  height: 20px;
  stroke-width: 1.75;
}

.highlight-title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 600;
  color: #ffffff;
  margin-bottom: 10px;
}

.highlight-desc {
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 400;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.5);
  max-width: 340px;
  margin-left: auto;
  margin-right: auto;
}

/* ==========================================================================
   WHAT WE DO / CAPABILITIES SECTION
   ========================================================================== */
/* Fills the screen when its top is at the top of the frame. Padding is inside
   the 100vh thanks to the global border-box, and min-height (not height) lets
   the section grow past the viewport if the content ever needs more room. */
.services-section {
  padding: 100px 48px 120px 48px;
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
}

.services-container {
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
  position: relative;
}

/* Section Header */
.services-header-row {
  display: grid;
  /* 520px, not 420px: the paragraph needs at least 480px to hold two lines, and
     below that it broke to three. The extra 40px is slack for copy edits. */
  grid-template-columns: 1fr 520px;
  gap: 48px;
  align-items: center;
  margin-bottom: 64px;
}

.services-eyebrow {
  display: block;
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  margin-bottom: 18px;
}

.services-statement {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 3vw, 2.8rem);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: #ffffff;
}

.services-desc {
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 400;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.5);
  text-align: right;
}

/* 4-Column Bento Grid */
.bento-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  position: relative;
  z-index: 5;
}

/* Individual Bento Card */
.bento-card {
  position: relative;
  height: 280px;
  border-radius: 20px;
  overflow: hidden;
  background: var(--bg-card);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.6);
  transition: box-shadow 0.4s ease, border-color 0.3s;
  /* Keep the card on its own composited layer permanently. Otherwise the layer
     is created when the tilt transform is applied and destroyed when it is
     removed, and the background photo is re-rasterised on both -- which reads
     as a flicker / momentary quality change on hover. */
  will-change: transform;
}

.bento-card:hover {
  transform: translateY(-8px);
  border-color: rgba(255, 255, 255, 0.25);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.8), 0 0 30px rgba(255, 255, 255, 0.15);
}

/* Photographic card background. Sits under .card-inner (z-index 2), with a
   scrim on ::after that deepens toward the bottom, where the title and copy
   are, so text contrast holds regardless of the photo. */
.card-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  opacity: 0.55;
  transition: opacity 0.45s var(--ease-out-expo);
  /* Stabilises the image's raster inside the card's 3D layer, so it is not
     re-sampled as the tilt changes. */
  backface-visibility: hidden;
}

/* Shows the whole image instead of filling the card. Use on artwork that reads
   as a composition (the product-design sketches) where `cover` would crop the
   sides -- at 3:2 in a 1.14:1 card, cover hides ~24% of it. The resulting bands
   are invisible because these images have black edges. */
.card-bg-fit {
  object-fit: contain;
  /* Fills the letterbox bands with the same black as the artwork's own
     background. Painting it on the <img> (rather than the card) means the bands
     pass through the identical opacity and scrim as the image, so they match
     exactly instead of showing the card's lighter grey through the gap. */
  background-color: #000;
}

.bento-card.has-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 1;
  background: linear-gradient(
    180deg,
    rgba(8, 8, 10, 0.3) 0%,
    rgba(8, 8, 10, 0.72) 55%,
    rgba(8, 8, 10, 0.94) 100%
  );
  transition: opacity 0.45s var(--ease-out-expo);
}

/* On hover both layers of the film lift -- the image goes to full strength and
   the scrim fades out -- exposing the bare photo. Both transition back on exit.
   These live on .card-bg / ::after rather than the card itself, so the inline
   `transition: none` the tilt handler sets on .bento-card cannot cancel them. */
.bento-card.has-bg:hover .card-bg {
  opacity: 1;
}

.bento-card.has-bg:hover::after {
  opacity: 0;
}

/* The icon and copy fade out with the film, leaving only the photograph, and
   fade back in with it on exit. Same duration and easing as the two film
   layers so all three read as one movement rather than three. */
.bento-card.has-bg:hover .card-inner {
  opacity: 0;
}

/* Card Inner Content */
.card-inner {
  position: relative;
  z-index: 2;
  height: 100%;
  padding: 32px 28px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* Keeps the title and copy at the bottom now that the icon -- whose
     `margin-bottom: auto` used to do that job -- is commented out. Harmless if
     the icon comes back: an auto margin claims free space before
     justify-content is applied, so it would take over again. */
  justify-content: flex-end;
  transition: opacity 0.45s var(--ease-out-expo);
}

.card-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  margin-bottom: auto;
}

.card-icon svg {
  width: 18px;
  height: 18px;
  stroke-width: 1.75;
}

.card-title {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: #ffffff;
  margin-top: 24px;
  margin-bottom: 8px;
}

.card-desc {
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 400;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.5);
  /* Reserve two lines. The text block is anchored to the bottom of the card, so
     a one-line description would let its title sit lower than the others --
     this keeps all four titles on a shared baseline whatever the copy says.
     2 x 1.5 line-height at 0.85rem = 2.55rem. */
  min-height: 2.55rem;
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
.site-footer {
  padding: 80px 48px 40px 48px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  background: #060608;
  position: relative;
  z-index: 10;
}

.footer-container {
  max-width: 1600px;
  margin: 0 auto;
}

.footer-top {
  margin-bottom: 64px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.footer-sub {
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: rgba(255, 255, 255, 0.5);
  text-transform: uppercase;
  display: block;
  margin-bottom: 16px;
}

.footer-heading {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 3.6vw, 3rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #ffffff;
  margin-bottom: 32px;
  max-width: 700px;
}

.footer-email-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: #ffffff;
  color: #08080a;
  padding: 14px 26px;
  border-radius: 100px;
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 600;
  transition: transform 0.3s var(--ease-out-expo), box-shadow 0.3s;
}

.footer-email-btn svg {
  width: 13px;
  height: 13px;
  transition: transform 0.25s ease;
}

.footer-email-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 30px rgba(255, 255, 255, 0.2);
}

.footer-email-btn:hover svg {
  transform: translate(2px, -2px);
}

.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 32px;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  flex-wrap: wrap;
  gap: 20px;
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: 16px;
}

.footer-logo-img {
  height: 22px;
  width: auto;
}

.copyright-text {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

.footer-socials {
  display: flex;
  gap: 24px;
}

.footer-socials a {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  transition: color 0.2s;
}

.footer-socials a:hover {
  color: #ffffff;
}

/* ==========================================================================
   RESPONSIVE BREAKPOINTS
   ========================================================================== */
@media (max-width: 1200px) {
  .site-header {
    padding: 20px 32px;
  }
  .hero-section {
    padding-left: 32px;
    padding-right: 32px;
  }
  .trust-section, .highlights-section, .services-section, .site-footer {
    padding-left: 32px;
    padding-right: 32px;
  }
  .main-nav {
    gap: 22px;
  }
  .highlights-container {
    gap: 36px;
  }
  .services-header-row {
    grid-template-columns: 1fr;
    align-items: start;
  }
  .bento-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }
  .bento-card {
    height: 260px;
  }
}

/* Header below the desktop breakpoint.

   The nav used to be hidden outright here, which lost Home/About/Products and
   also mis-seated the CTA: with only two children left, grid auto-placement
   dropped "Let's Connect" into the middle `auto` column instead of the right
   rail, so it sat centred on screen.

   Two explicit rows fix both. Logo and CTA share the top row at opposite
   edges, the nav gets its own centred row beneath. Named areas mean placement
   no longer depends on how many children happen to be present. Desktop above
   900px is untouched. */
/* The nav used to be `display: none` here, which lost Home/About/Products and
   also mis-seated the CTA: with only two children left, grid auto-placement
   dropped "Let's Connect" into the middle `auto` column, so it sat centred on
   screen instead of flush right. Keeping all three children restores the
   desktop 1fr/auto/1fr behaviour — logo left, nav centred, CTA right — on one
   row. Sizes are trimmed further down so it fits a phone. */
@media (max-width: 900px) {
  .main-nav {
    display: flex;
    gap: 18px;
  }
}

@media (max-width: 860px) {
  .site-header {
    padding: 16px 20px;
  }
  .hero-section {
    padding: 150px 20px 80px 20px;
  }
  .trust-section, .highlights-section, .services-section, .site-footer {
    padding-left: 20px;
    padding-right: 20px;
  }
  .trust-logos {
    justify-content: center;
  }
  .highlights-container {
    grid-template-columns: 1fr;
    gap: 40px;
  }
  .bento-grid {
    grid-template-columns: 1fr;
  }
  .bento-card {
    height: auto;
    min-height: 220px;
  }
  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ==========================================================================
   MOBILE — landing page
   Touch ergonomics and legibility only; desktop rules are untouched.
   ========================================================================== */
@media (max-width: 860px) {
  /* Footer link rows were 18px tall. Padding grows the hit area to the 44px
     minimum without altering the type size or spacing rhythm. */
  .footer-socials { gap: 4px 22px; flex-wrap: wrap; }

  .footer-socials a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* 11.5px is below comfortable reading size on a phone. */
  .copyright-text { font-size: 0.8rem; }


  /* The desktop arrangement -- brand left, links right, one line -- needs about
     640px of room. It cannot be reproduced on a phone at a legible size, so the
     block centres instead of left-aligning: stacked and centred reads as
     intentional, whereas the logo sitting left of a two-line copyright line
     made the text look pushed off to the right.

     The logo moves above the copyright rather than beside it. Beside it, the
     copyright had only ~293px of the 344px row and wrapped; stacked, it clears
     one line on its own from 384px up. */
  .footer-bottom {
    align-items: center;
    text-align: center;
  }

  .footer-brand {
    flex-direction: column;
    gap: 12px;
  }

  .footer-socials { justify-content: center; }

  /* Everything on the header shrinks just enough to keep logo, nav and CTA on
     a single row at phone widths, while each stays a 44px touch target. */
  .header-inner { gap: 10px; }
  .nav-logo-img { height: 18px; }
  .main-nav     { gap: 14px; }
  .nav-link     { font-size: 0.82rem; }

  /* The pill used to carry `min-height: 44px` so it was its own touch target,
     but that made it 44px tall against an 18px logo mark beside it -- far
     taller than the desktop pill is relative to its own nav (35.6px against
     21.6px of text). 5px of block padding around an 18px line box gives ~30px,
     which restores that proportion.

     The 44px target does not go away, it just stops being the visible box: the
     pseudo-element below extends the hit area 7px past each edge, exactly as
     the copy buttons do. */
  .btn-connect {
    min-height: 0;
    font-size: 0.78rem;
    padding: 5px 13px;
    position: relative;
  }

  .btn-connect::after {
    content: '';
    position: absolute;
    inset: -8px 0;            /* inset is measured from the PADDING box, so the
                                 1px border costs a pixel each side: the real
                                 reach is 7px, giving 30 + 14 = 44px. Verified
                                 by hit-testing, not arithmetic. */
  }

  .nav-link {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* The logo doubles as the reload control, so it needs a real hit area too. */
  .header-logo { min-height: 44px; }
}

/* "Let's Connect" was breaking onto two lines on every phone width, which also
   inflated the pill from 44px to 58px tall.

   The cause was the grid, not the type size. `1fr auto 1fr` forces both outer
   rails to the SAME width, and the button is wider than the logo, so the rail
   was sized by the logo and the button got squeezed until its text wrapped.

   The label is what gives, not the layout: `1fr auto 1fr` is kept so the nav
   stays centred on the PAGE, and below 440px the CTA drops to "Connect", which
   is narrow enough to sit inside the rail the centred nav leaves behind.
   449px is the crossover, measured rather than estimated: the full label needs
   a 111.5px rail, and from 450px up the grid provides it with the nav exactly
   on centre. Between 441 and 449 it very nearly does -- the nav lands up to
   2.6px off -- so the short label covers that band too. */
@media (max-width: 860px) {
  .btn-connect { white-space: nowrap; }
}

/* Only one label is ever in the layout, so desktop renders exactly as before. */
.cta-label-short { display: none; }

@media (max-width: 449px) {
  .cta-label-full  { display: none; }
  .cta-label-short { display: inline; }
}

/* Narrowest phones. Everything above still fits at 400px; below it the row is
   genuinely full, so the type and padding come down together. */
@media (max-width: 400px) {
  .site-header { padding: 16px 14px; }
  .main-nav    { gap: 11px; }
  .nav-link    { font-size: 0.8rem; }
  .btn-connect { font-size: 0.75rem; padding-inline: 11px; }
}

/* 320px (iPhone SE 1st gen and equivalents) is the floor we support. Three nav
   links plus a two-word CTA plus the mark is 320px of content in ~292px of
   room, so the last ~28px comes off the type and the gaps. */
@media (max-width: 360px) {
  .site-header  { padding: 16px 10px; }
  .main-nav     { gap: 7px; }
  .nav-link     { font-size: 0.73rem; }
  .nav-logo-img { height: 16px; }
  .btn-connect  { font-size: 0.7rem; padding-inline: 9px; }

  /* The smaller type here leaves a 28.8px pill rather than 30px, so it needs
     one more pixel each side to clear 44: 28.8 + 2 x (9 - 1) = 44.8. */
  .btn-connect::after { inset: -9px 0; }
}
