/* ==========================================================================
   EKA METALFORM INDIA — Homepage styles
   Light "Steel & Teal" design system. Mobile-first. Vanilla CSS only.
   ========================================================================== */

/* ---------- Design tokens ---------- */
:root {
  --bg: #FBF8F5;          /* barely-warm off-white canvas */
  --surface: #FFFFFF;     /* cards stay clean white to pop on the warm canvas */
  --panel: #F4EEE9;       /* warm panel tone for alternating sections */
  --border: #E7DED7;      /* warm hairline border */
  --ink: #1E1416;         /* near-black with a warm/maroon undertone */
  --body: #4A3F42;        /* warm dark grey body text */
  --muted: #8A7B7E;       /* muted warm grey */
  --accent: #7A1F2B;      /* MAROON — primary: buttons, links, numbers, active states */
  --accent-hover: #641722;/* darker maroon for hover */
  --accent-soft: #F3E4E6; /* soft maroon wash for active backgrounds/badges */
  --gold: #B08433;        /* GOLD — sparingly: logo, one stat, thin accent lines */
  --gold-soft: #F5ECD9;   /* faint gold wash if needed */
  --radius: 14px;
  --radius-sm: 10px;
  --maxw: 1200px;

  /* Shadows */
  --shadow-sm: 0 1px 2px rgba(30, 20, 22, .06);
  --shadow-lg: 0 1px 2px rgba(30, 20, 22, .06), 0 10px 30px rgba(30, 20, 22, .06);
  --shadow-hover: 0 2px 4px rgba(30, 20, 22, .08), 0 18px 40px rgba(30, 20, 22, .12);

  /* Type families */
  /* Single font family site-wide: Inter for both headings and body.
     Hierarchy comes from weight + tighter spacing/line-height on headings. */
  --font-head: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;

  /* Layout */
  --header-h: 68px;
  --gutter: clamp(16px, 4vw, 28px);
}

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

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

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

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: clamp(16px, 1rem + 0.15vw, 18px);
  line-height: 1.65;
  color: var(--body);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--font-head);
  color: var(--ink);
  line-height: 1.1;             /* tighter so headings stay punchy in Inter */
  margin: 0 0 .5em;
  font-weight: 700;
  letter-spacing: -0.02em;
}

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

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); text-decoration: underline; }

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

ul { margin: 0; padding: 0; list-style: none; }

button { font-family: inherit; font-size: inherit; cursor: pointer; }

:focus-visible {
  outline: 3px solid var(--accent-hover);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Skip link */
.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--accent);
  color: #fff;
  padding: 12px 18px;
  z-index: 200;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus { left: 0; text-decoration: none; }

/* ---------- Layout helpers ---------- */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: clamp(56px, 9vw, 104px); }
.section--panel { background: var(--panel); }
.section--ink { background: var(--ink); color: #CDC3BF; }

.section-head { max-width: 720px; margin-bottom: clamp(32px, 5vw, 52px); }
.section-head--center { margin-inline: auto; text-align: center; }

.eyebrow {
  font-family: var(--font-body);
  text-transform: uppercase;
  letter-spacing: .12em;
  font-size: .78rem;
  font-weight: 600;
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  gap: .55em;
  margin-bottom: .9rem;
}
.eyebrow .num { color: var(--accent); font-variant-numeric: tabular-nums; }
.section--ink .eyebrow { color: var(--gold); }   /* light gold reads on dark; maroon would not */

.h2 { font-size: clamp(1.7rem, 1.2rem + 2.2vw, 2.6rem); }
.lead { font-size: clamp(1.05rem, 1rem + 0.4vw, 1.2rem); color: var(--body); }
.section--ink .h2 { color: #fff; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5em;
  min-height: 48px;
  padding: 12px 22px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: .98rem;
  border: 1.5px solid transparent;
  text-decoration: none;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease, transform .18s ease, box-shadow .18s ease;
  white-space: nowrap;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--accent); color: #fff; box-shadow: var(--shadow-sm); }
.btn--primary:hover { background: var(--accent-hover); color: #fff; }

.btn--outline {
  background: transparent;
  border-color: var(--border);
  color: var(--ink);
}
.btn--outline:hover { border-color: var(--accent); color: var(--accent); }

/* Ghost-on-glass (hero) */
.btn--glass {
  background: rgba(255, 255, 255, .1);
  border-color: rgba(255, 255, 255, .55);
  color: #fff;
  backdrop-filter: blur(4px);
}
.btn--glass:hover { background: rgba(255, 255, 255, .2); color: #fff; border-color: #fff; }

.btn--lg { min-height: 52px; padding: 14px 28px; font-size: 1.02rem; }
.btn--block { width: 100%; }

/* ==========================================================================
   HEADER
   ========================================================================== */
/* Header is transparent over the hero at the top, solid once scrolled
   (or when the mobile menu is open). Smooth ~0.3s transition between states. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background-color: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .3s ease, box-shadow .3s ease, border-color .3s ease;
}
/* Faint top-down dark scrim so light text stays readable on bright video frames */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(20, 13, 15, .5) 0%, rgba(20, 13, 15, 0) 100%);
  transition: opacity .3s ease;
}
/* Solid state: scrolled past the hero, OR mobile menu open */
.site-header.is-scrolled,
body.nav-open .site-header {
  background-color: rgba(251, 248, 245, .96);
  backdrop-filter: blur(10px);
  border-bottom-color: var(--border);
  box-shadow: var(--shadow-sm);
}
.site-header.is-scrolled::before,
body.nav-open .site-header::before { opacity: 0; }

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

.brand {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.12rem;
  color: var(--ink);
  letter-spacing: -0.01em;
  text-decoration: none;
  margin-right: auto;
}
.brand:hover { text-decoration: none; color: var(--ink); }
.brand img { width: 34px; height: 34px; }

/* Header logo: two stacked images that cross-fade between the header states.
   --dark shows on the solid (scrolled / menu-open) cream header; it sits in
   normal flow and sizes the link. --light shows on the transparent header over
   the dark hero video; it is overlaid and fades in/out. Both preloaded = no flicker. */
.brand .brand__logo { display: block; width: auto; height: 38px; transition: opacity .3s ease; }
.brand .brand__logo--light { position: absolute; top: 0; left: 0; }
.brand .brand__logo--dark { opacity: 0; }   /* default = transparent header -> show light */
.brand .brand__logo--light { opacity: 1; }
.site-header.is-scrolled .brand__logo--dark,
body.nav-open .site-header .brand__logo--dark { opacity: 1; }
.site-header.is-scrolled .brand__logo--light,
body.nav-open .site-header .brand__logo--light { opacity: 0; }
@media (max-width: 640px) { .brand .brand__logo { height: 30px; } }
.brand .brand-sub { color: var(--muted); font-weight: 500; font-size: .72rem; letter-spacing: .04em; }
.brand b { color: var(--gold); }   /* gold wordmark accent (brand mark — contrast-exempt) */

/* Primary nav — roomy gap now that the desktop list is short */
.nav { display: flex; align-items: center; gap: 28px; }
.nav a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 6px 12px;
  border-radius: 8px;
  color: var(--body);
  font-weight: 500;
  font-size: .94rem;
}
.nav a:hover { background: var(--accent-soft); color: var(--accent); text-decoration: none; }

.header-cta { display: inline-flex; align-items: center; gap: 8px; }

/* Hamburger */
.nav-toggle {
  display: none;
  width: 46px;
  height: 46px;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 10px;
  align-items: center;
  justify-content: center;
  color: var(--ink);
}
.nav-toggle .bars { position: relative; width: 20px; height: 14px; }
.nav-toggle .bars span {
  position: absolute; left: 0; right: 0; height: 2px; background: currentColor; border-radius: 2px;
  transition: transform .22s ease, opacity .22s ease, top .22s ease;
}
.nav-toggle .bars span:nth-child(1) { top: 0; }
.nav-toggle .bars span:nth-child(2) { top: 6px; }
.nav-toggle .bars span:nth-child(3) { top: 12px; }
.nav-toggle[aria-expanded="true"] .bars span:nth-child(1) { top: 6px; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .bars span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .bars span:nth-child(3) { top: 6px; transform: rotate(-45deg); }

/* ---- Header text colors: light over the transparent hero, dark when solid ---- */
.site-header .brand,
.site-header .brand .brand-sub,
.site-header .nav-toggle { transition: color .3s ease, border-color .3s ease, background-color .3s ease; }
.site-header .nav a { transition: color .3s ease, background-color .2s ease; }

/* Transparent (top of page) — light/white */
.site-header .brand { color: #fff; }
.site-header .brand:hover { color: #fff; }
.site-header .brand .brand-sub { color: rgba(255, 255, 255, .72); }
.site-header .nav a { color: rgba(255, 255, 255, .92); }
.site-header .nav a:hover { background: rgba(255, 255, 255, .14); color: #fff; }
.site-header .nav-toggle { color: #fff; border-color: rgba(255, 255, 255, .45); background: rgba(255, 255, 255, .08); }

/* Solid (scrolled or menu open) — dark/ink on the cream background */
.site-header.is-scrolled .brand,
body.nav-open .site-header .brand { color: var(--ink); }
.site-header.is-scrolled .brand:hover,
body.nav-open .site-header .brand:hover { color: var(--ink); }
.site-header.is-scrolled .brand .brand-sub,
body.nav-open .site-header .brand .brand-sub { color: var(--muted); }
.site-header.is-scrolled .nav a,
body.nav-open .site-header .nav a { color: var(--body); }
.site-header.is-scrolled .nav a:hover,
body.nav-open .site-header .nav a:hover { background: var(--accent-soft); color: var(--accent); }
.site-header.is-scrolled .nav-toggle,
body.nav-open .site-header .nav-toggle { color: var(--ink); border-color: var(--border); background: var(--surface); }

/* ==========================================================================
   HERO
   ========================================================================== */
.hero {
  position: relative;
  min-height: 88vh;
  display: flex;
  flex-direction: column;
  justify-content: center;   /* vertical centering */
  align-items: center;       /* horizontal centering */
  text-align: center;
  margin-top: calc(-1 * var(--header-h));   /* slide up behind the transparent header */
  padding-block: clamp(64px, 12vh, 120px);
  padding-top: calc(clamp(64px, 12vh, 120px) + var(--header-h)); /* keep content clear of the header */
  isolation: isolate;
  overflow: hidden;          /* clip the scaled-up video so nothing spills out */
  color: #fff;
}
/* Looping background video. Scaled up slightly so the bottom-right watermark
   pushes off-screen (clipped by the hero's overflow:hidden). */
.hero__video {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* The watermark sits ~10% in from the right / ~15% up from the bottom — not in
     the extreme corner — so a center scale can't reach it. Anchor to the top-left
     and scale up so the bottom-right (watermark) is pushed off and clipped. */
  transform: scale(1.28);
  transform-origin: top left;
}
/* Full-bleed hero background photo — poster/fallback behind the video
   (reduced-motion, no video support, or while the video buffers). */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -3;
  background-image:
    url("../assets/home/hero/hero-bg.webp"),
    url("../assets/home/hero/hero-bg.png"),
    linear-gradient(125deg, #1a1113 0%, #3a1d23 45%, #7A1F2B 100%);
  background-size: cover, cover, cover;
  background-position: center, center, center;
  background-repeat: no-repeat, no-repeat, no-repeat;
  overflow: hidden;
}
/* Reduced motion: don't show/play the video — fall back to the poster image */
@media (prefers-reduced-motion: reduce) {
  .hero__video { display: none; }
}
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Lighter top-to-bottom scrim: darker where the upper-center text sits,
     lighter toward the lower-left so the machinery + blue spark show through. */
  background: linear-gradient(rgba(22, 14, 16, 0.55), rgba(22, 14, 16, 0.35));
}
/* Centered hero content block, constrained and middle-aligned */
.hero__inner {
  max-width: 900px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* Eyebrow as a centered label chip */
.hero .eyebrow {
  color: #E3C88E;
  border: 1px solid rgba(255, 255, 255, .25);
  background: rgba(255, 255, 255, .07);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  padding: 7px 16px;
  border-radius: 999px;
  margin-bottom: 1.3rem;
}
.hero h1 {
  color: #fff;
  font-size: clamp(2.05rem, 1.3rem + 4.2vw, 3.7rem);
  margin-bottom: .5em;
  max-width: min(26ch, 100%); /* wraps to 2 balanced lines on desktop; never exceeds viewport */
  text-wrap: balance;
}
.hero h1 .accent { color: #E3C88E; }
.hero__sub {
  font-size: clamp(1.05rem, 1rem + 0.5vw, 1.28rem);
  color: #E4DAD4;
  max-width: min(640px, 100%);
  margin-inline: auto;
  margin-bottom: 1.8rem;
  font-weight: 400;   /* explicit base so the <strong> process words read heavier */
}
/* Process words only. Same colour, weight alone carries the emphasis. */
.hero__sub strong { font-weight: 700; }
.hero__sub-short { display: none; }   /* desktop uses the full paragraph; mobile swaps below */
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;   /* centered button row */
  gap: 14px;
}
/* Stats row inside the hero — white/light on the dark background, hairline above */
.hero__stats {
  width: 100%;
  max-width: 720px;
  margin: 0;
  margin-top: 38px;
  padding: 30px 0 0;
  border-top: 1px solid rgba(255, 255, 255, .18);
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 22px 16px;
}
.hero__stat { text-align: center; }
.hero__stat-num {
  display: block;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(1.55rem, 1.1rem + 1.7vw, 2.25rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: #fff;
}
/* ONE highlighted stat in gold (the precision differentiator) — gold reads on the dark hero */
.hero__stat:last-child .hero__stat-num { color: var(--gold); }
.hero__stat-label {
  display: block;
  margin-top: 7px;
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .68);
}

/* ----------------------------------------------------------------
   Cinematic intro reveal (runs once on load).
   ~0.5s of video + scrim only, then content fades/rises in sequence.
   Gated behind .js so the content is ALWAYS visible if JS never runs.
   ---------------------------------------------------------------- */
.js .hero__inner > * { opacity: 0; }   /* hidden pre-reveal — only when JS is present */

@keyframes heroRise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes heroFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes heroRiseY {
  from { transform: translateY(20px); }
  to   { transform: translateY(0); }
}

/* JS adds .is-revealed after the ~0.5s video-only beat */
.hero.is-revealed .hero__inner > * {
  animation: heroRise .6s ease-out both;   /* 'both' keeps opacity:0 during the delay, 1 after */
}
.hero.is-revealed .hero__inner > :nth-child(1) { animation-delay: 0s; }    /* eyebrow */
.hero.is-revealed .hero__inner > :nth-child(2) { animation-delay: .15s; }  /* H1 */
.hero.is-revealed .hero__inner > :nth-child(3) { animation-delay: .30s; }  /* subtext */
.hero.is-revealed .hero__inner > :nth-child(4) { animation-delay: .45s; }  /* buttons */
.hero.is-revealed .hero__inner > :nth-child(5) { animation-delay: .60s; }  /* stats row */

/* Stats: divider + row fade in together, the 4 numbers rise one-by-one */
.hero.is-revealed .hero__stats { animation-name: heroFade; }   /* opacity only (divider fades) */
.hero.is-revealed .hero__stat { animation: heroRiseY .6s ease-out both; }
.hero.is-revealed .hero__stat:nth-child(1) { animation-delay: .60s; }
.hero.is-revealed .hero__stat:nth-child(2) { animation-delay: .70s; }
.hero.is-revealed .hero__stat:nth-child(3) { animation-delay: .80s; }
.hero.is-revealed .hero__stat:nth-child(4) { animation-delay: .90s; }

/* Reduced motion: no intro — everything visible instantly, no animation */
@media (prefers-reduced-motion: reduce) {
  .js .hero__inner > * { opacity: 1; }
  .hero.is-revealed .hero__inner > *,
  .hero.is-revealed .hero__stat { animation: none; }
}

/* ----------------------------------------------------------------
   Hero → light section transition: a soft gradient strip that fades
   the dark hero into the warm --bg, with a few faint gold embers
   drifting up. Overlaps the hero's bottom so the section below is
   unmoved.  Decorative only — pointer-events:none.
   ---------------------------------------------------------------- */
.hero-transition {
  position: relative;
  height: 120px;
  margin-top: -120px;          /* overlap the bottom of the hero; section below stays put */
  z-index: 3;
  pointer-events: none;
  overflow: hidden;
  background: linear-gradient(to bottom,
    transparent 0%,
    rgba(251, 248, 245, .5) 58%,
    var(--bg) 100%);
}
.embers { position: absolute; inset: 0; }
.embers span {
  position: absolute;
  bottom: 14px;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--gold);
  opacity: 0;
  filter: blur(.4px);
  animation: ember-rise 11s ease-in-out infinite;
  will-change: transform, opacity;
}
@keyframes ember-rise {
  0%   { transform: translateY(0) scale(.7); opacity: 0; }
  18%  { opacity: .26; }
  80%  { opacity: .14; }
  100% { transform: translateY(-86px) scale(1); opacity: 0; }
}
/* Scatter the 12 embers: per-particle x, size, delay, duration */
.embers span:nth-child(1)  { left: 7%;  animation-duration: 12s;   animation-delay: 0s;    }
.embers span:nth-child(2)  { left: 16%; animation-duration: 10s;   animation-delay: -3s;   width: 2px; height: 2px; }
.embers span:nth-child(3)  { left: 24%; animation-duration: 13s;   animation-delay: -6s;   }
.embers span:nth-child(4)  { left: 33%; animation-duration: 11s;   animation-delay: -1.5s; width: 2px; height: 2px; }
.embers span:nth-child(5)  { left: 41%; animation-duration: 14s;   animation-delay: -8s;   }
.embers span:nth-child(6)  { left: 49%; animation-duration: 10.5s; animation-delay: -4.5s; width: 4px; height: 4px; }
.embers span:nth-child(7)  { left: 58%; animation-duration: 12.5s; animation-delay: -2s;   }
.embers span:nth-child(8)  { left: 66%; animation-duration: 11.5s; animation-delay: -7s;   width: 2px; height: 2px; }
.embers span:nth-child(9)  { left: 74%; animation-duration: 13.5s; animation-delay: -5s;   }
.embers span:nth-child(10) { left: 82%; animation-duration: 10s;   animation-delay: -9s;   width: 2px; height: 2px; }
.embers span:nth-child(11) { left: 90%; animation-duration: 12s;   animation-delay: -3.5s; }
.embers span:nth-child(12) { left: 95%; animation-duration: 13s;   animation-delay: -6.5s; width: 2px; height: 2px; }
/* Reduced motion: keep the gradient fade, drop the particles entirely */
@media (prefers-reduced-motion: reduce) {
  .embers { display: none; }
}
/* Mobile: thin out the embers (keep ~6) — pure CSS, negligible cost */
@media (max-width: 640px) {
  .embers span:nth-child(2n) { display: none; }
}

/* On narrow screens a 'cover' crop loses the sides — bias the photo left so the
   lower-left machinery/laser spark stays visible. (gradient layer stays centered) */
@media (max-width: 640px) {
  .hero__media { background-position: 30% center, center; }
}

/* Same idea for the video: centre-cropping a 16:9 clip into a tall viewport pushes the
   cutting head (which sits ~23% across the source frame) off toward the left edge.
   Biasing the crop left brings the head and spark stream back toward the middle.
   Desktop keeps the default centre framing. The watermark is clipped by the
   scale(1.28) on .hero__video, which is a vertical clip, so a horizontal shift
   here cannot expose it. */
@media (max-width: 768px) {
  .hero__video { object-position: 20% center; }
}

/* ---- MOBILE hero (<=640px): clear the fixed header, tighten the rhythm,
        swap to short subtext, and blend the bottom cleanly (no seam). ---- */
@media (max-width: 640px) {
  .hero {
    /* (1) start content below the transparent/fixed header, with breathing room */
    padding-top: calc(var(--header-h) + 24px);
    padding-bottom: 64px;
  }
  /* (3) tighter, centered rhythm */
  .hero .eyebrow { margin-bottom: 1rem; }
  .hero h1 { font-size: clamp(1.7rem, 1.1rem + 2.7vw, 2.1rem); margin-bottom: .4em; } /* 3 lines */
  .hero__sub { margin-bottom: 1.3rem; }
  .hero__sub-full { display: none; }
  .hero__sub-short { display: inline; }   /* (3) shorter copy on mobile */
  .hero__cta { gap: 12px; }
  .hero__stats { grid-template-columns: repeat(2, 1fr); gap: 20px 16px; max-width: 360px; margin-top: 24px; padding-top: 20px; }

  /* (2) Remove the stray seam: the transition strip overlaps the stats on the
     taller mobile hero. Drop it and fade the hero's own bottom into --bg. */
  .hero-transition { display: none; }
  .hero::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 64px;
    z-index: -1;                 /* behind the content, above video+scrim */
    background: linear-gradient(to bottom, transparent, var(--bg));
    pointer-events: none;
  }
}

/* Stack the CTAs on small screens */
@media (max-width: 480px) {
  .hero__cta { flex-direction: column; align-items: stretch; width: 100%; max-width: 340px; }
  .hero__cta .btn { width: 100%; }
}

/* ==========================================================================
   OVERVIEW
   ========================================================================== */
.overview__grid {
  display: grid;
  gap: clamp(28px, 5vw, 56px);
  align-items: center;
}
.overview__pills { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 1.4rem; }
.pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 999px;
  padding: 8px 14px;
  font-size: .86rem;
  font-weight: 600;
}
.pill svg { flex: none; }

/* Supplier name cards — understated text blocks (NOT logos), maroon/ink tones */
.suppliers { margin-top: 1.6rem; }
.suppliers__label {
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 .7rem;
}
.suppliers__list {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  list-style: none;
  padding: 0;
  margin: 0;
}
.supplier {
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 9px 15px;
  font-weight: 600;
  font-size: .92rem;
  color: var(--ink);
  background: #fff;
}

/* Contained 4:3 card — the container controls the box height */
.overview__media {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  border: 1px solid var(--border);
}
/* Image fills the 4:3 card (height:100% overrides the height attribute so it can't stretch taller) */
.overview__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Two-image auto cross-fade. Same mechanics as .card__media--slides: every image
   is stacked and transparent, and only .is-active is shown. Image 1 carries
   is-active in the markup, so no-JS leaves it visible rather than blank. */
.overview__media--slides img {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .6s ease;
}
.overview__media--slides img.is-active { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .overview__media--slides img { transition: none; }
}

/* ==========================================================================
   PLACEHOLDER IMAGE BLOCKS (CSS-only, captioned)
   ========================================================================== */
.ph {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  background:
    repeating-linear-gradient(45deg, rgba(122, 31, 43,.05) 0 12px, transparent 12px 24px),
    linear-gradient(135deg, #F1E9E3, #E7DED7);
  color: #8A7B7E;
  overflow: hidden;
}
.ph::before {
  /* corner brackets — reads as a framed "image to be supplied" */
  content: "";
  position: absolute;
  inset: 12px;
  border: 1px dashed rgba(122, 31, 43, .35);
  border-radius: 8px;
  pointer-events: none;
}
.ph__label {
  position: relative;
  z-index: 1;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: .82rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #574247;
  padding: 6px 12px;
  background: rgba(255, 255, 255, .72);
  border-radius: 8px;
  max-width: 86%;
}
.ph--4x3 { aspect-ratio: 4 / 3; }
.ph--16x9 { aspect-ratio: 16 / 9; }
.ph--1x1 { aspect-ratio: 1 / 1; }

/* ==========================================================================
   CARD GRIDS (capabilities / industries)
   ========================================================================== */
.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(18px, 3vw, 26px);
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
  display: flex;
  flex-direction: column;
}
.card:hover, .card:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--shadow-hover);
  border-color: #D8C9C0;
}
.card__media { aspect-ratio: 4 / 3; }
/* Real card image fills the 4:3 box; card's overflow:hidden keeps the rounded corners */
.card__media img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* --- Multi-image card media (used on the Assemblies card only) -------------
   All slides are absolutely positioned in the same 4:3 box, so swapping one
   for the next causes no layout shift and every photo crops identically. --- */
.card__media--slides { position: relative; }
.card__media--slides img {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .6s ease;
}
.card__media--slides img.is-active { opacity: 1; }

/* Dots sit over the bottom of the image; JS injects them, so no-JS shows none */
.slide-dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 10px;
  z-index: 1;
  display: flex;
  justify-content: center;
  gap: 8px;
}
.slide-dots__dot {
  /* Padded hit area (>=24px) around a small visual dot — tappable on touch */
  appearance: none;
  border: 0;
  padding: 9px 8px;
  background: none;
  cursor: pointer;
  line-height: 0;
}
.slide-dots__dot::before {
  content: "";
  display: block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--muted);
  /* White ring + soft shadow so the dots read on light and dark photos alike */
  box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .9), 0 1px 3px rgba(30, 20, 22, .35);
  transition: background-color .25s ease, transform .25s ease;
}
.slide-dots__dot[aria-current="true"]::before {
  background: var(--accent);
  transform: scale(1.3);
}
.slide-dots__dot:hover::before { background: var(--ink); }
.slide-dots__dot[aria-current="true"]:hover::before { background: var(--accent); }
.slide-dots__dot:focus-visible { outline: 3px solid #fff; outline-offset: -2px; border-radius: 4px; }

@media (prefers-reduced-motion: reduce) {
  .card__media--slides img { transition: none; }
  .slide-dots__dot::before { transition: none; }
}

.card__body { padding: 20px 20px 22px; }
.card__title {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 1.16rem;
  margin-bottom: .35rem;
}
.card__title .idx {
  font-size: .8rem;
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.card__desc { color: var(--body); font-size: .96rem; margin: 0; }

/* ==========================================================================
   INDUSTRIES ICON GRID (icon-tile + name; 4 / 3 / 2 columns)
   Flex-wrap + justify-center so the odd 11th tile centres in the last row.
   Capped width keeps the cards square-ish rather than sprawling.
   ========================================================================== */
.ind-grid {
  --ind-gap: 16px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--ind-gap);
  max-width: 940px;
  margin-inline: auto;
  list-style: none;
  padding: 0;
}
.ind-tile {
  flex: 0 0 calc((100% - var(--ind-gap)) / 2);       /* mobile: 2 up */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: clamp(22px, 3vw, 28px) 14px;
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.ind-tile:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-hover);
  border-color: var(--accent);
}
/* Icon sits in a soft-maroon square that becomes the card's focal point */
.ind-tile__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  transition: background .2s ease, color .2s ease;
}
.ind-tile:hover .ind-tile__icon { background: var(--accent); color: #fff; }
.ind-tile__icon svg { display: block; width: 24px; height: 24px; }
.ind-tile__name {
  font-weight: 600;
  font-size: .95rem;
  line-height: 1.3;
  color: var(--ink);
}
@media (min-width: 641px)  { .ind-tile { flex-basis: calc((100% - 2 * var(--ind-gap)) / 3); } }  /* tablet: 3 up */
@media (min-width: 1025px) { .ind-tile { flex-basis: calc((100% - 3 * var(--ind-gap)) / 4); } }  /* desktop: 4 up */

/* ==========================================================================
   INFRASTRUCTURE — interactive image swap
   ========================================================================== */
/* MOBILE (<=1024px): plain stacked flow — head, image, list.
   Spacing kept identical to the original: section-head's own margin-bottom
   sits above the image; this margin sits above the list. */
.infra__layout { display: block; }
.infra__media { margin-bottom: clamp(20px, 4vw, 36px); }
.infra__stage {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  background: #FFFFFF;   /* white product shots: letterbox area blends into the image */
  aspect-ratio: 4 / 3;
}
.infra__img {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .45s ease;
}
.infra__img.is-active { opacity: 1; }
/* White-background product shots: contain, never crop. Stage is 4:3 and so are the
   images, so this fits edge to edge with no letterbox. */
.infra__img img { width: 100%; height: 100%; object-fit: contain; display: block; }
@media (prefers-reduced-motion: reduce) {
  .infra__img { transition: none; }
}
.infra__list { display: flex; flex-direction: column; gap: 10px; }
.infra__item {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  min-height: 64px;
  color: var(--ink);
  transition: border-color .18s ease, background-color .18s ease, transform .18s ease;
}
.infra__item:hover { border-color: #D8C9C0; }
.infra__item[aria-selected="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.infra__item .dot {
  flex: none;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--border);
  transition: background-color .18s ease, box-shadow .18s ease;
}
.infra__item[aria-selected="true"] .dot {
  background: var(--accent);
  box-shadow: 0 0 0 4px rgba(122, 31, 43, .18);
}
.infra__item .txt { display: flex; flex-direction: column; }
.infra__item .name { font-weight: 600; font-size: 1rem; }
.infra__item .spec { color: var(--muted); font-size: .85rem; }
.infra__item[aria-selected="true"] .spec { color: var(--accent); }

/* ==========================================================================
   PROCESS — horizontal stepper
   ========================================================================== */
/* Timeline node sizing — shared across breakpoints */
:root { --node: 44px; }

/* ==========================================================================
   PROCESS: A SINGLE CONTINUOUS RAIL
   ==========================================================================
   No cards. The copy sits directly on the section background, so each column
   gets the full width instead of losing 40px to card padding.

   ZERO-GAP GUARANTEE, the thing that was broken before: the rail is not one
   measured element. Every step draws the segment from ITS OWN node centre to
   the NEXT node centre (.step::after), so segment n always begins exactly
   where segment n-1 ended. Segments cannot drift apart or skip, because none
   of this is measured in JS. The faint full-width rail behind them is a single
   pseudo-element on the track.

   Node centres are at 50% of each equal grid column, and every step starts on
   the same grid row, so all five node centres share one y. Rail-to-node
   alignment is structural, not computed: it cannot be off by a pixel.
   ========================================================================== */
.process__track {
  --pgap: 30px;                  /* must match the grid gap: segments span column + gap */
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--pgap);
  list-style: none;
  margin: 0;
  padding: 0 0 0 calc(var(--node) + 20px);   /* left rail for the nodes */
}

/* VERTICAL: the faint rail is drawn per step, exactly like the maroon one, so
   it starts at node 1 and stops at node 5 instead of trailing past the last
   node to the bottom of the copy. The track-level rail is only used for the
   horizontal layout, where the brief calls for a full-container-width rail. */
.process__track::before { content: none; }
.step::before {
  content: "";
  position: absolute;
  pointer-events: none;
  background: var(--accent);
  opacity: .18;
  left: calc(-1 * (var(--node) + 20px) + var(--node) / 2 - 1px);
  top: calc(var(--node) / 2);
  width: 2px;
  height: calc(100% + var(--pgap));
}
.step:last-child::before { content: none; }

.step {
  position: relative;            /* no card: no background, border, radius or shadow */
  min-height: var(--node);
}

/* The drawn segment from this node to the next. Last step has none. */
.step::after {
  content: "";
  position: absolute;
  pointer-events: none;
  background: var(--accent);
  /* Centre the segment on the node centre. The node sits at
     left: -(node + 20px) from the step, so its centre is at
     -(node + 20px) + node/2; back off 1px for the 2px width. */
  left: calc(-1 * (var(--node) + 20px) + var(--node) / 2 - 1px);
  top: calc(var(--node) / 2);
  width: 2px;
  height: 0;                     /* animates to the full segment length */
}
.step:last-child::after { content: none; }

.step__num {
  position: absolute;
  left: calc(-1 * (var(--node) + 20px));
  top: 0;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--node); height: var(--node);
  border-radius: 50%;
  /* NO-JS / REDUCED-MOTION DEFAULT: filled. Nothing is ever blank. */
  background: var(--accent);
  border: 2px solid var(--accent);
  color: #fff;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.05rem;
  font-variant-numeric: tabular-nums;
}
.step h3 { font-size: 1.08rem; margin-bottom: .3rem; color: var(--ink); }
.step p  { font-size: .92rem; color: var(--body); margin: 0; }
.step__timing { font-size: .8rem; font-weight: 600; color: var(--muted); margin: .55rem 0 0; }
.step__timing:empty { margin: 0; }

/* ---------- the one sequence ----------------------------------------------
   Per-step start times come from :nth-child, so no JS measures or schedules
   anything. JS only adds .is-drawn once, on scroll in.
     segment n : starts at --t, runs 350ms  -> node n+1 fills exactly as it lands
     node      : fills at --t
     title     : --t + 120ms
     body      : --t + 200ms
   Last node lands at 1400ms, its body finishes near 2000ms. Under 2.5s.        */
.js .step:nth-child(1) { --t: 0ms; }
.js .step:nth-child(2) { --t: 350ms; }
.js .step:nth-child(3) { --t: 700ms; }
.js .step:nth-child(4) { --t: 1050ms; }
.js .step:nth-child(5) { --t: 1400ms; }

.js .step__num {
  background: transparent;
  color: var(--accent);
  transition: background-color .25s ease-out, color .25s ease-out;
  transition-delay: var(--t);
}
.js .step h3,
.js .step > p {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .4s ease-out, transform .4s ease-out;
}
.js .step h3    { transition-delay: calc(var(--t) + 120ms); }
.js .step > p   { transition-delay: calc(var(--t) + 200ms); }
.js .step::after { transition: height .35s linear, width .35s linear; transition-delay: var(--t); }

.process__track.is-drawn .step__num { background: var(--accent); color: #fff; }
.process__track.is-drawn .step h3,
.process__track.is-drawn .step > p { opacity: 1; transform: none; }
/* vertical: segment reaches the next node centre = this step's height + the gap */
.process__track.is-drawn .step::after { height: calc(100% + var(--pgap)); }

@media (prefers-reduced-motion: reduce) {
  /* Final state instantly, no motion at all. */
  .js .step__num { background: var(--accent); color: #fff; transition: none; }
  .js .step h3,
  .js .step > p { opacity: 1; transform: none; transition: none; }
  .js .step::after { transition: none; }
}

/* ==========================================================================
   PROCESS: HORIZONTAL RAIL at 1100px and up
   ==========================================================================
   1100px, not 900px. At 900 the container is about 846px and five columns land
   near 150px each, which wraps the body copy every two or three words. 1100
   is the first width where a column clears 190px. Between 900 and 1100 the
   vertical layout is used instead, which reads properly at any width.
   ========================================================================== */
@media (min-width: 1100px) {
  .process__track {
    --pgap: 24px;
    grid-template-columns: repeat(5, 1fr);
    align-items: start;
    padding: 0;
    column-gap: var(--pgap);
  }
  /* HORIZONTAL: the faint rail is built from the same per-step segments as the
     vertical layout, so it begins at node 1's centre and ends at node 5's
     centre. No track-level rail, therefore no overshoot past either end and
     nothing to fade out. Faint and drawn segments share one geometry, so they
     cannot disagree. */
  .process__track::before { content: none; }
  .step { min-height: 0; padding-top: calc(var(--node) + 18px); }
  /* Node CENTRED over its column. Left aligning it to the text start makes the
     rail one whole column short on the right (it would end 22px into column 5
     while the text block runs to the column's far edge), which reads as the
     block sitting left of centre. Centring the node puts the rail's midpoint on
     the container's midpoint, so rail and text share one centre line. */
  .step__num { left: 50%; top: 0; transform: translateX(-50%); }
  .step::before,
  .step::after {
    left: 50%;                           /* on the node centre */
    top: calc(var(--node) / 2 - 1px);
    height: 2px;
  }
  .step::before { content: ""; width: calc(100% + var(--pgap)); }
  .step::after  { width: 0; }
  .step:last-child::before,
  .step:last-child::after { content: none; }
  .process__track.is-drawn .step::after { width: calc(100% + var(--pgap)); height: 2px; }
}

/* ==========================================================================
   CASE STUDIES
   ========================================================================== */
.cases__grid { display: grid; grid-template-columns: 1fr; gap: clamp(18px, 3vw, 26px); }
.case {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform .2s ease, box-shadow .2s ease;
}
.case:hover { transform: translateY(-4px); box-shadow: var(--shadow-hover); }
.case__media { aspect-ratio: 16 / 9; }
/* Real case photo fills the 16:9 box; card's overflow:hidden keeps the rounded corners */
.case__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Generous, even padding; breathing room between image and content */
.case__body { padding: 30px; display: flex; flex-direction: column; gap: 16px; }
.case__tag {
  align-self: flex-start;
  font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--accent); background: var(--accent-soft);
  padding: 4px 10px; border-radius: 999px;
}
.case h3 { font-size: 1.15rem; margin: 0; }
/* Roomy rhythm between Challenge / Solution / Outcome blocks */
.case dl { margin: 0; display: flex; flex-direction: column; gap: 20px; }
.case dt {
  font-size: .72rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 8px;
}
.case dd { margin: 0; font-size: .94rem; line-height: 1.55; color: var(--body); }
/* Outcome block = the payoff: hairline divider above + larger bold highlight */
.case dl > div:last-child {
  border-top: 1px solid var(--border);
  padding-top: 20px;
}
.case dd.is-outcome {
  font-size: 1.12rem;
  line-height: 1.4;
  font-weight: 700;
  color: var(--ink);
}

/* ==========================================================================
   TESTIMONIALS
   ========================================================================== */
.quotes__grid { display: grid; grid-template-columns: 1fr; gap: clamp(18px, 3vw, 26px); }
.quote {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px 26px;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.quote__mark { color: var(--accent); opacity: .35; }
.quote blockquote { margin: 0; font-size: 1.08rem; color: var(--ink); line-height: 1.55; }
.quote__who { display: flex; align-items: center; gap: 12px; margin-top: auto; }
.quote__avatar {
  width: 46px; height: 46px; border-radius: 50%; flex: none;
  background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-head); font-weight: 700;
}
.quote__name { font-weight: 600; color: var(--ink); font-size: .96rem; }
.quote__role { color: var(--muted); font-size: .85rem; }

/* ==========================================================================
   RFQ FORM
   ========================================================================== */
/* RFQ section runs tighter than the default rhythm so it fits ~1 viewport */
#contact.section { padding-block: clamp(40px, 6vw, 72px); }

.rfq__layout { display: grid; grid-template-columns: 1fr; gap: clamp(24px, 4vw, 44px); }
.rfq__intro .lead { margin-bottom: 1.1rem; }
.rfq__assure { display: grid; gap: 16px; margin-top: 1.2rem; }
.rfq__assure li { display: flex; gap: 12px; align-items: flex-start; }
.rfq__assure .ic {
  flex: none; width: 40px; height: 40px; border-radius: 10px;
  background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.rfq__assure b { color: var(--ink); display: block; }
.rfq__assure span { font-size: .9rem; color: var(--muted); }

.rfq__card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 28px;
}
/* Row wrapper: paired fields share this 14px gap; no margin (all spacing from #rfqForm gap) */
.form-row { display: grid; grid-template-columns: 1fr; gap: 14px; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field label { font-weight: 600; font-size: .9rem; color: var(--ink); }
.field .req { color: var(--accent); }
/* Counterpart to .req for optional fields. Existing muted token, no new colour. */
.field .opt { color: var(--muted); font-weight: 400; }
.field input, .field select, .field textarea {
  font-family: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--bg);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  min-height: 44px;
  transition: border-color .15s ease, box-shadow .15s ease;
  width: 100%;
}
.field textarea { min-height: 110px; resize: vertical; line-height: 1.55; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(122, 31, 43, .15);
}
.field input[aria-invalid="true"], .field select[aria-invalid="true"], .field textarea[aria-invalid="true"] {
  border-color: #c0392b;
  box-shadow: 0 0 0 3px rgba(192, 57, 43, .12);
}
.field .error {
  color: #b23121;
  font-size: .82rem;
  min-height: 1em;
}
/* When empty, take up no space so gaps stay a uniform 14px; reappears when JS fills it */
.field .error:empty { display: none; }

/* Dropzone */
/* NOTE: currently unused — the RFQ form's "Upload Drawing" field was removed.
   The .dropzone, .file-list and .file-chip rules below are kept for future use. */
.dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  padding: 24px;
  min-height: 130px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;                 /* internal spacing (margins are zeroed by #rfqForm *) */
  text-align: center;
  color: var(--muted);
  transition: border-color .18s ease, background-color .18s ease;
  cursor: pointer;
}
.dropzone:hover, .dropzone:focus-within { border-color: var(--accent); }
.dropzone.is-dragover { border-color: var(--accent); background: var(--accent-soft); }
.dropzone__icon { color: var(--accent); margin-bottom: 8px; display: inline-flex; }
.dropzone strong { color: var(--ink); }
.dropzone small { display: block; margin-top: 6px; font-size: .82rem; }
.dropzone input[type="file"] { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

.file-list { margin-top: 14px; display: grid; gap: 8px; }
.file-list:empty { display: none; }   /* no reserved space until files are added */
.file-chip {
  display: flex; align-items: center; gap: 10px;
  background: var(--accent-soft); color: var(--accent);
  border-radius: 8px; padding: 8px 12px; font-size: .88rem;
}
.file-chip .name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-chip .size { color: var(--muted); margin-left: auto; flex: none; }
.file-chip button {
  flex: none; border: none; background: transparent; color: var(--accent);
  display: inline-flex; padding: 4px; border-radius: 6px; line-height: 0;
}
.file-chip button:hover { background: rgba(122, 31, 43, .15); }

/* Web3Forms honeypot. Offscreen, NOT display:none — bots must still find and tick it.
   Absolutely positioned, so it is not a flex item and adds no gap to the form. */
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Submit-level error (network / API failure). Injected by JS only when it has text,
   so it costs no space in .form-foot at rest. Matches .field .error styling. */
.form-error { color: #b23121; font-size: .82rem; }

.form-foot { margin-top: 20px; display: flex; flex-direction: column; gap: 12px; }
.form-note { font-size: .82rem; color: var(--muted); }
.form-success {
  display: none;
  align-items: flex-start;
  gap: 12px;
  background: var(--accent-soft);
  border: 1px solid #E3C6CA;
  color: var(--accent);
  border-radius: var(--radius-sm);
  padding: 16px 18px;
}
.form-success.is-visible { display: flex; }
.form-success svg { flex: none; color: var(--accent); margin-top: 2px; }
.form-success b { color: var(--ink); }

/* ==========================================================================
   FOOTER
   ========================================================================== */
.site-footer { background: var(--ink); color: #C6B8B2; padding-block: 56px 24px; }
/* Mobile-first: single column. Tablet -> 2 cols, desktop -> 4 cols (see media queries). */
.footer__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
}
/* Footer logo: the light artwork on the dark footer. Single image (no
   cross-fade pair like the header), left-aligned above the tagline. */
/* block + max-content: no inline line-box leading under the logo (so the 16px
   gap is exactly 16px), and the click target still hugs the artwork */
.footer__brand .brand { color: #fff; display: block; width: max-content; margin-bottom: 16px; }
.footer__brand .brand__logo { height: 34px; width: auto; }
@media (max-width: 640px) { .footer__brand .brand__logo { height: 30px; } }
.footer__brand .brand .brand-sub { color: #9A8B8E; }
.footer__brand p { color: #B0A29C; font-size: .92rem; max-width: 32ch; margin: 0; }
.footer__col h4 {
  color: #fff;
  font-size: .82rem;
  text-transform: uppercase;
  letter-spacing: .1em;
  margin: 0 0 14px;
}
/* All link spacing comes from the 10px flex gap — no item margins */
.footer__col ul,
.footer__col address {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.footer__col li { margin: 0; }
.footer__col a, .footer__col address {
  color: #C6B8B2;
  font-size: .92rem;
  font-style: normal;
  line-height: 1.5;
}
.footer__col a { margin: 0; }
.footer__col a:hover { color: #fff; }
.footer__col address a { display: block; }

.footer__bottom {
  margin-top: 40px;
  padding-top: 22px;
  border-top: 1px solid color-mix(in srgb, var(--border) 12%, transparent);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  font-size: .85rem;
  color: #9C8E89;
}
.footer__bottom a { color: #C6B8B2; }
.footer__legal { display: flex; gap: 18px; flex-wrap: wrap; justify-content: center; }

/* ==========================================================================
   SCROLL REVEAL
   ========================================================================== */
/* Only hide reveals when JS is present (so content is visible if JS fails). */
.js .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .5s ease-out, transform .5s ease-out;
  will-change: opacity, transform;
}
.reveal.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
  }

/* ==========================================================================
   RESPONSIVE — tablet (>=641px)
   ========================================================================== */
@media (min-width: 641px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); }
  .cases__grid { grid-template-columns: repeat(2, 1fr); }
  .quotes__grid { grid-template-columns: repeat(2, 1fr); }
  .form-row.two { grid-template-columns: 1fr 1fr; }



  /* Footer: tablet -> 2 columns */
  .footer__grid { grid-template-columns: 1fr 1fr; gap: 40px; }
}

/* ==========================================================================
   RESPONSIVE — desktop (>=1025px)
   ========================================================================== */
@media (min-width: 1025px) {
  .card-grid { grid-template-columns: repeat(3, 1fr); }
  .cases__grid { grid-template-columns: repeat(3, 1fr); }
  .quotes__grid { grid-template-columns: repeat(3, 1fr); }

  .overview__grid { grid-template-columns: 1.05fr .95fr; }
  .rfq__layout { grid-template-columns: .9fr 1.1fr; align-items: start; }

  /* Infrastructure: image right, list left */
  /* DESKTOP: two columns. Left = heading + description + machine list (stacked);
     Right = image panel spanning both rows so it fills the left-side height. */
  .infra__layout {
    display: grid;
    grid-template-columns: 1fr 1.1fr;
    grid-template-areas:
      "head  media"
      "list  media";
    column-gap: 56px;
    row-gap: 28px;                /* list sits ~28px below the description */
    align-items: start;
  }
  .infra__layout .infra__head  { grid-area: head; margin: 0; max-width: none; }
  .infra__layout .infra__media { grid-area: media; align-self: center; margin: 0; }
  .infra__layout .infra__list  { grid-area: list; }
  /* The product shots are 4:3, so the stage holds 4:3 here too: object-fit:contain then
     fills it edge to edge with no white letterbox. Stretching to the full left-column
     height (now five machines) would leave the machine floating in ~220px of white,
     so the panel is capped by its own ratio and centred against the text column. */
  .infra__stage { aspect-ratio: 4 / 3; height: auto; min-height: 0; }



  /* Footer: desktop -> 4 columns (brand wider) + horizontal bottom bar */
  .footer__grid { grid-template-columns: 1.5fr 1fr 1fr 1.5fr; gap: 48px; }
  .footer__bottom {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    text-align: left;
  }
  .footer__legal { order: 2; justify-content: flex-end; } /* copyright left, Privacy/Terms right */
}

/* Larger desktop hero text breathing room */
@media (min-width: 1025px) {
  .hero { min-height: 88vh; }
}

/* ==========================================================================
   RESPONSIVE — mobile nav (<=900px collapses nav)
   ========================================================================== */
@media (max-width: 900px) {
  .nav-toggle { display: inline-flex; }
  .header-cta .btn--primary { display: none; } /* CTA lives in the menu on mobile */

  .nav {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    padding: 12px var(--gutter) 18px;
    max-height: calc(100dvh - var(--header-h));
    overflow-y: auto;
    transform: translateY(-12px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s ease, transform .2s ease, visibility .2s;
  }
  .nav.is-open { transform: none; opacity: 1; visibility: visible; }
  .nav a { min-height: 48px; padding: 12px 14px; font-size: 1rem; border-radius: 10px; }
  .nav .nav-quote {
    margin-top: 8px;
    background: var(--accent);
    color: #fff;
    justify-content: center;
    font-weight: 600;
  }
  .nav .nav-quote:hover { background: var(--accent-hover); color: #fff; }
  @media (prefers-reduced-motion: reduce) {
    .nav { transition: none; }
  }
}
@media (min-width: 901px) {
  /* desktop top nav stays short; these live in the footer + mobile menu */
  .nav .nav-quote,
  .nav .nav__more { display: none; } /* Quality / Process / Case Studies + dup CTA */
}

/* Lock scroll when mobile menu open */
body.nav-open { overflow: hidden; }

/* RFQ form spacing: all vertical spacing comes from the single 14px flex gap */
/* ALL vertical spacing in these forms comes from this one flex gap, with every
   child margin zeroed. Do not add margins to form children: that is how the
   creeping-gap problem starts. Applies to the homepage RFQ, the contact page
   RFQ (same id, different page) and the careers application. */
#rfqForm, #careersForm { display: flex; flex-direction: column; gap: 14px; }
#rfqForm *, #careersForm * { margin-top: 0; margin-bottom: 0; }
#rfqForm textarea, #careersForm textarea { min-height: 90px; }
#rfqForm .dropzone { min-height: 130px; }

/* ==========================================================================
   INNER PAGES  (body.page)
   Every rule below is scoped to body.page or to classes the homepage does not
   use, so none of it reaches the homepage.
   ========================================================================== */

/* The homepage header starts transparent over the dark hero video and only
   turns solid past 90px of scroll (JS adds .is-scrolled). Inner pages have no
   dark hero for it to sit over, so it must be solid from first paint. These
   mirror the .is-scrolled rules exactly rather than inventing a second look. */
body.page .site-header {
  background-color: rgba(251, 248, 245, .96);
  backdrop-filter: blur(10px);
  border-bottom-color: var(--border);
  box-shadow: var(--shadow-sm);
}
body.page .site-header::before { opacity: 0; }
body.page .site-header .brand__logo--dark { opacity: 1; }
body.page .site-header .brand__logo--light { opacity: 0; }
body.page .site-header .brand,
body.page .site-header .brand:hover { color: var(--ink); }
body.page .site-header .brand .brand-sub { color: var(--muted); }
body.page .site-header .nav a { color: var(--body); }
body.page .site-header .nav a:hover { background: var(--accent-soft); color: var(--accent); }
body.page .site-header .nav-toggle { color: var(--ink); border-color: var(--border); background: var(--surface); }

/* Current-page marker. Reuses the existing nav hover treatment so it adds no
   new visual language, it just makes that state persistent. */
.nav a[aria-current="page"],
body.page .site-header .nav a[aria-current="page"] {
  color: var(--accent);
  background: var(--accent-soft);
}

/* Keep in-page anchors clear of the sticky header. Scoped to inner pages so
   homepage scroll positions are untouched. */
body.page [id] { scroll-margin-top: calc(var(--header-h) + 16px); }

/* ---------- Page hero ----------
   Same .section-head markup as the homepage sections (eyebrow + heading +
   optional lead). Only the padding differs, so it clears the sticky header
   without leaving a cavern above the first line. */
.page-hero {
  /* Compact band, not a screen filler. Asymmetric on purpose: a little more
     above to clear the sticky header, less below because the next section
     brings its own top padding. */
  padding-block: clamp(26px, 3vw, 40px) clamp(22px, 2.4vw, 32px);
  background: var(--panel);
}
.page-hero .section-head { max-width: 760px; margin-bottom: 0; }

/* The hero's bottom padding and the next section's top padding were stacking
   into ~180px of empty band at desktop, which read as a layout fault. Pull the
   following section in so the two do not double up. Only ever matches the
   section directly after a page hero. */
.page-hero + .section { padding-top: clamp(30px, 4vw, 52px); }

/* ---------- Long-form copy (policies, and any future text page) ----------
   Narrow measure for readability. Headings step down from the page .h2. */
.prose { max-width: 72ch; }
.prose > h2 {
  font-size: clamp(1.22rem, 1.08rem + .55vw, 1.5rem);
  margin-top: 2.5rem;
}
.prose > h2:first-child { margin-top: 0; }
.prose h3 { font-size: 1.02rem; margin-top: 1.7rem; }
.prose ul, .prose ol { margin: 0 0 1rem; padding-left: 1.35rem; }
.prose li { margin-bottom: .5rem; }
.prose address { font-style: normal; margin: 0 0 1rem; }
.prose .meta { color: var(--muted); font-size: .9rem; }

/* ==========================================================================
   INNER PAGE LAYOUT HELPERS
   Used by about.php and capabilities.php. Tokens only, no new colours.
   None of these class names appear on the homepage.
   ========================================================================== */

/* Two images side by side, each in the existing 4:3 .overview__media card.
   Stacks on mobile, pairs from 641px. */
.media-pair {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(18px, 3vw, 26px);
  margin-top: clamp(28px, 4vw, 44px);
}
@media (min-width: 641px) {
  .media-pair { grid-template-columns: 1fr 1fr; }
}

/* Flips the two columns of .overview__grid on desktop, so alternating
   capability blocks put the image left, then right, then left. Below 1025px
   .overview__grid is a single column and source order applies, which keeps
   the image above its text on mobile every time. */
@media (min-width: 1025px) {
  .overview__grid--flip > :first-child { order: 2; }
}

/* Plain labelled tiles for short lists (part types). Not .card: no media,
   no hover lift, nothing to click. */
.tile-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(12px, 2vw, 16px);
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (min-width: 641px)  { .tile-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1025px) { .tile-grid { grid-template-columns: repeat(3, 1fr); } }
.tile {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  padding: 16px 18px;
  font-weight: 600;
  color: var(--ink);
  font-size: .95rem;
}
.tile svg { flex: none; color: var(--accent); }
/* <address> defaults to italic, which reads as a different style from the
   sibling tiles. Match them. */
.tile address { font-style: normal; }
.tile a { color: inherit; }
.tile a:hover { color: var(--accent); }

/* Name / spec rows for the machine list. */
.spec-list {
  list-style: none;
  margin: 1.4rem 0 0;
  padding: 0;
  border-top: 1px solid var(--border);
}
.spec-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 16px;
  padding: 13px 0;
  border-bottom: 1px solid var(--border);
}
.spec-list .spec__name { font-weight: 600; color: var(--ink); }
.spec-list .spec__val  { color: var(--muted); font-size: .9rem; }

/* .lead defaults to --body (#4A3F42), which is 1.78:1 on --ink and effectively
   invisible. Inherit the section's own #CDC3BF instead: 10.42:1, passes AA.
   Nothing on the homepage uses .section--ink, so this changes nothing there. */
.section--ink .lead { color: inherit; }

/* Capability blocks on /capabilities. At 1025px the text column runs 53 to 71
   percent taller than a 4:3 image, which reads as lopsided. Letting the media
   match the row height fixes it without cutting copy that carries real buyer
   information. object-fit: cover already handles the tighter crop.
   Desktop only: below 1025px .overview__grid is a single column and the 4:3
   box is the right shape. Scoped to --cap so the homepage is untouched. */
@media (min-width: 1025px) {
  .overview__grid--cap .overview__media {
    align-self: stretch;
    aspect-ratio: auto;
    min-height: 100%;
  }
}

/* Responsive map embed. Fixed aspect box so the iframe cannot shift layout as
   it loads, and a --panel ground so the space does not flash white first. */
.map-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  background: var(--panel);
}
.map-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
@media (max-width: 640px) { .map-embed { aspect-ratio: 4 / 3; } }

/* ==========================================================================
   NAV FIT  (7 nav entries, 6 of them visible on desktop)
   ==========================================================================
   With Home on the bar the header needs ~940px of content in a container that
   is only 886px wide at 901px. Flexbox resolved that by shrinking the ONLY
   flexible item, the logo, from 175px down to 33px: an unreadable sliver, and
   a worse failure than wrapping because nothing looks broken enough to notice.

   Fix is two parts: stop the logo absorbing the pressure, then buy the space
   back from nav gaps and padding in the band where it is tight. No item is
   dropped and no font family or colour changes. */
.brand { flex: none; }
.brand .brand__logo { flex: none; }

@media (min-width: 901px) and (max-width: 1100px) {
  .nav { gap: 14px; }
  .nav a { padding: 6px 8px; font-size: .9rem; }
}

/* ==========================================================================
   CAPABILITIES PROCESS STRIP
   A map of the six capabilities at the top of /capabilities. Each item anchors
   down to its own section. Desktop: six across, joined by a connector line
   through the number row. Mobile: the same row, scrolled horizontally, rather
   than a cramped grid.
   ========================================================================== */
.capstrip { margin-top: clamp(26px, 4vw, 40px); }
.capstrip__track {
  list-style: none;
  margin: 0;
  padding: 0 0 6px;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(124px, 1fr);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  overscroll-behavior-x: contain;
}
.capstrip__item { position: relative; scroll-snap-align: center; }
/* Connector line, drawn behind the numbers and stopped at the two ends so the
   sequence reads as cut-through-to-finish rather than a loop. */
.capstrip__item::before {
  content: "";
  position: absolute;
  top: 20px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--border);
}
.capstrip__item:first-child::before { left: 50%; }
.capstrip__item:last-child::before  { right: 50%; }
.capstrip__item a {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  padding: 0 6px;
  text-align: center;
  text-decoration: none;
}
.capstrip__num {
  position: relative;
  z-index: 1;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--surface);
  border: 2px solid var(--border);
  color: var(--muted);
  font-weight: 700;
  font-size: .84rem;
  font-variant-numeric: tabular-nums;
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.capstrip__label {
  font-size: .8rem;
  font-weight: 600;
  color: var(--body);
  line-height: 1.3;
  transition: color .2s ease;
}
.capstrip__item a:hover .capstrip__num,
.capstrip__item a:focus-visible .capstrip__num {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
}
.capstrip__item a:hover .capstrip__label,
.capstrip__item a:focus-visible .capstrip__label { color: var(--accent); }
@media (prefers-reduced-motion: reduce) {
  .capstrip__num, .capstrip__label { transition: none; }
}

/* ==========================================================================
   ABOUT: DARK CAPACITY BAND  (.section--ink, once per page)
   No button here on purpose: .btn--primary is 1.76:1 against --ink. Text is
   #fff (18:1), the unit is --gold (5.31:1) and body copy inherits #CDC3BF
   (10.42:1), all of which clear AA.
   ========================================================================== */
.statband { display: grid; gap: clamp(18px, 3.5vw, 40px); align-items: center; }
@media (min-width: 901px) { .statband { grid-template-columns: 1.15fr .85fr; } }
.statband__figure { display: flex; align-items: baseline; gap: .55rem; flex-wrap: wrap; }
.statband__num {
  font-family: var(--font-head);
  font-size: clamp(3.4rem, 2rem + 7vw, 6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.03em;
  color: #fff;
}
.statband__unit {
  font-size: clamp(.92rem, .88rem + .25vw, 1.05rem);
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold);
}

/* ==========================================================================
   CAPABILITIES: FULL-BLEED BLOCK  (breaks the left/right rhythm)
   The figure is a direct child of .section, outside .container, so it spans
   the full width with no 100vw trick and therefore no scrollbar overflow.
   ========================================================================== */
.cap-bleed__media {
  width: 100%;
  height: clamp(230px, 32vw, 440px);
  overflow: hidden;
  margin-bottom: clamp(26px, 4vw, 46px);
}
.cap-bleed__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cap-bleed__body { max-width: 780px; }

/* ==========================================================================
   REVEAL RHYTHM
   Section headings run slightly slower than the content under them, and the
   observer starts them slightly earlier (see main.js), so a section reads
   top-down instead of arriving all at once. Wrapped in no-preference so the
   reduced-motion rule above still wins for anyone who asks for less motion.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .js .section-head.reveal { transition-duration: .72s; }
}

/* ==========================================================================
   INNER PAGE IMAGE HERO
   Dark photographic band at the top of each inner page. Shorter than the
   homepage hero, never full screen.

   SCRIM: a horizontal gradient in --ink, heaviest on the left where the copy
   sits and lightest on the right so the photograph still reads. Measured
   against the actual pixels of each hero image: worst single pixel behind the
   text is 6.90:1 on /about, 7.95:1 on /capabilities, 7.63:1 on /careers and
   7.12:1 on /contact, all versus white. AA needs 4.5:1. Do not lighten these
   stops without re-measuring: every one of these photos contains blown-out
   highlights (white walls, skylights) that sit at L=1.0 unscrimmed.
   ========================================================================== */
.page-hero--image {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 45vh;
  padding-block: clamp(32px, 5vw, 56px);
  background: var(--ink);   /* shows while the photo decodes, so no white flash */
  overflow: hidden;
}
@media (max-width: 640px) { .page-hero--image { min-height: 38vh; } }

.page-hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
.page-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* MOBILE default: copy spans the full width, so the scrim stays heavy all
     the way across. Measured worst pixel behind text: 8.95:1 to 10.09:1. */
  background: linear-gradient(90deg,
              rgba(30, 20, 22, .86) 0%,
              rgba(30, 20, 22, .78) 100%);
}
@media (min-width: 901px) {
  /* DESKTOP: copy occupies the left ~62%, so the scrim stays heavy there and
     lifts sharply afterwards, letting the photograph actually read on the
     right. Measured worst pixel behind text: /about 5.96:1, /capabilities
     7.45:1, /careers 6.80:1, /contact 6.27:1. AA needs 4.5:1.
     Re-measure before moving these stops: every hero photo has blown
     highlights that sit at L=1.0 with no scrim at all. */
  .page-hero__scrim {
    background: linear-gradient(90deg,
                rgba(30, 20, 22, .88) 0%,
                rgba(30, 20, 22, .80) 55%,
                rgba(30, 20, 22, .42) 75%,
                rgba(30, 20, 22, .24) 100%);
  }
}
.page-hero--image > .container { position: relative; z-index: 2; width: 100%; }
.page-hero--image .eyebrow { color: var(--gold); }
.page-hero--image h1,
.page-hero--image .h2,
.page-hero--image .lead { color: #fff; }

/* ==========================================================================
   TOOLPATH  (/capabilities hero only)
   A flat pattern drawing itself the way a cutting head traces a path.
   Runs once, on scroll into view. No loop.

   Degradation: the dasharray only exists under .js, so with JS off the
   outline renders complete rather than blank. Under reduced motion the
   dashoffset is zeroed and no animation runs, so it is complete and static.
   pathLength="1" on every shape means the dash maths needs no measurement.
   ========================================================================== */
.toolpath { width: 100%; height: auto; display: block; overflow: visible; }
.toolpath [class^="toolpath__"] {
  fill: none;
  stroke: var(--gold);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.toolpath__bend { stroke-dasharray: .012 .012; opacity: .85; }

.js .toolpath__outline,
.js .toolpath__hole {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.js .toolpath__bend { opacity: 0; }

.toolpath.is-in .toolpath__outline {
  animation: tp-draw 1.35s cubic-bezier(.42, 0, .32, 1) forwards;
}
.toolpath.is-in .toolpath__hole {
  animation: tp-draw .5s ease-out forwards;
}
.toolpath.is-in .toolpath__hole:nth-of-type(1) { animation-delay: 1.10s; }
.toolpath.is-in .toolpath__hole:nth-of-type(2) { animation-delay: 1.25s; }
.toolpath.is-in .toolpath__hole:nth-of-type(3) { animation-delay: 1.40s; }
.toolpath.is-in .toolpath__hole:nth-of-type(4) { animation-delay: 1.55s; }
.toolpath.is-in .toolpath__bend {
  animation: tp-fade .45s ease-out forwards;
  animation-delay: 1.85s;
}
@keyframes tp-draw { to { stroke-dashoffset: 0; } }
@keyframes tp-fade { to { opacity: .85; } }

@media (prefers-reduced-motion: reduce) {
  .js .toolpath__outline,
  .js .toolpath__hole { stroke-dashoffset: 0; }
  .js .toolpath__bend { opacity: .85; }
  .toolpath.is-in .toolpath__outline,
  .toolpath.is-in .toolpath__hole,
  .toolpath.is-in .toolpath__bend { animation: none; }
}

/* ==========================================================================
   IMAGE REVEAL WIPE  (/about and /capabilities)
   Images are cut in left to right instead of fading up. Text keeps the fade.
   Same .reveal hook, so the existing observer drives it with no extra JS.
   ========================================================================== */
.js .reveal--wipe {
  opacity: 1;
  transform: none;
  clip-path: inset(0 100% 0 0);
  transition: clip-path .7s cubic-bezier(.4, 0, .2, 1);
}
.reveal--wipe.is-in { clip-path: inset(0 0 0 0); }
@media (prefers-reduced-motion: reduce) {
  .js .reveal--wipe { clip-path: none; transition: none; }
}

/* ---- /capabilities hero: copy left, toolpath right ---------------------- */
.caps-hero__grid { display: grid; gap: clamp(20px, 4vw, 48px); align-items: center; }
.caps-hero__art { display: none; }        /* mobile: keep the hero at 38vh */
@media (min-width: 901px) {
  .caps-hero__grid { grid-template-columns: 1.15fr .85fr; }
  .caps-hero__art { display: block; max-width: 380px; margin-left: auto; }
}
.caps-hero .section-head { margin-bottom: 0; }

/* ---- Process strip band: slim, it is navigation not a section ---------- */
.capstrip-band { padding-block: clamp(20px, 3vw, 30px); }
.capstrip-band .capstrip { margin-top: 0; }

/* Small muted aside inside a content block. Used for the add-on note under the
   post processing capability, so it reads as a qualifier rather than a third body
   paragraph. Tokens only. */
.note { font-size: .85rem; color: var(--muted); }

/* Footer with the Company column omitted (only the homepage published), so the
   remaining three keep sensible widths instead of inheriting the four-column
   track list. */
@media (min-width: 1025px) {
  .footer__grid--3 { grid-template-columns: 1.5fr 1fr 1.5fr; }
}
