/* ============================================================
   HEDROTEC — Self-hosted fonts
   IBM Plex, served first-party from assets/fonts/ (no Google
   Fonts / third-party CDN). Only the weights/styles actually
   used by the design system below are included — all "latin"
   subset (English + German, incl. ä ö ü ß), normal style only.
   Source: official IBM Plex distribution, github.com/IBM/plex
   (SIL Open Font License 1.1 — see assets/fonts/LICENSE.txt).
   ============================================================ */
@font-face{
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-sans-400.woff2') format('woff2');
}
@font-face{
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-sans-500.woff2') format('woff2');
}
@font-face{
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-sans-600.woff2') format('woff2');
}
@font-face{
  font-family: 'IBM Plex Sans Condensed';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-sans-condensed-500.woff2') format('woff2');
}
@font-face{
  font-family: 'IBM Plex Sans Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-sans-condensed-600.woff2') format('woff2');
}
@font-face{
  font-family: 'IBM Plex Sans Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-sans-condensed-700.woff2') format('woff2');
}
@font-face{
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-400.woff2') format('woff2');
}
@font-face{
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-500.woff2') format('woff2');
}

/* ============================================================
   HEDROTEC — Design tokens
   Paper-light page, read like technical documentation, not a
   SaaS demo: one sober petrol-blue accent, no glow, no dark
   mode. Diagrams are the exception — they stay dark, framed
   like instrument-panel viewports set into the page.
   ============================================================ */
:root{
  --bg:            #f3f4f1;
  --bg-elevated:   #ffffff;
  --bg-soft:       #eaebe6;
  --bg-panel:      #10151a;
  --clay:          #1c5266;
  --clay-hover:    #28657c;
  --clay-soft:     #6bb6d6;
  --clay-dim:      #17323d;
  --teal:          #1c5266;
  --teal-soft:     #6bb6d6;
  --ink:           #14171a;
  --ink-muted:     #4b5157;
  --ink-faint:     #7a8086;
  --line:          rgba(20,23,26,0.10);
  --line-strong:   rgba(20,23,26,0.22);

  --font-display: 'IBM Plex Sans Condensed', var(--font-body);
  --font-body:    'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

  --container: 1180px;
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --section-pad: clamp(4rem, 9vw, 8rem);
}

*, *::before, *::after{ box-sizing: border-box; }
html{ scroll-behavior: smooth; max-width: 100%; }
body{
  margin: 0;
  max-width: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
img, svg{ max-width: 100%; display: block; }
a{ color: inherit; }
h1,h2,h3,h4{ margin: 0; font-family: var(--font-display); font-weight: 650; letter-spacing: -0.005em; }
p{ margin: 0; }
ul{ margin: 0; padding: 0; list-style: none; }
button{ font-family: inherit; }

.container{
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

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

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Belt-and-braces: guarantee every staged/drawn element resolves to its
     final visible state with no residual transform, not just a fast one. */
  .stage-reveal, .stage-block, .flow-node, .diagram-frame, .radar-frame,
  .pillar-item, .timeline::after, .feature--flagship .feature-copy::before{
    transform: none !important;
    opacity: 1 !important;
  }
  .radar-frame .radar-axis, .radar-frame .radar-ring{ stroke-dashoffset: 0 !important; }
  .radar-frame .radar-poly{ transform: scale(1) !important; opacity: 1 !important; }
  .hero-photo{ animation: none !important; }
}

/* ---------- type ---------- */
.eyebrow{
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--clay);
}
.eyebrow--teal{ color: var(--clay); }

.display-xl{
  font-size: clamp(2.6rem, 5.6vw, 5.25rem);
  line-height: 1.02;
}
.display-lg{
  font-size: clamp(2rem, 3.6vw, 3.1rem);
  line-height: 1.08;
}
.display-md{
  font-size: clamp(1.4rem, 2.2vw, 1.9rem);
  line-height: 1.2;
}
.lede{
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  color: var(--ink-muted);
  line-height: 1.6;
  max-width: 46ch;
}
.body-muted{ color: var(--ink-muted); }

/* ---------- buttons ---------- */
.btn{
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1.5rem;
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid transparent;
  transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, transform 160ms ease;
  cursor: pointer;
}
.btn--primary{
  background: var(--clay);
  color: #ffffff;
}
.btn--primary:hover{ background: var(--clay-hover); transform: translateY(-1px); }
.btn--ghost{
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn--ghost:hover{ border-color: var(--clay); color: var(--clay); }

/* ---------- nav ---------- */
/* backdrop-filter lives on ::before (not on .site-header itself) because
   filter/backdrop-filter on an element makes it the containing block for
   position:fixed descendants — which would trap .nav-links (the mobile
   dropdown, position:fixed) inside the header's own 4.5rem-tall box
   instead of the viewport, collapsing the full-screen menu to a sliver. */
.site-header{
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: 1px solid var(--line);
}
.site-header::before{
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(243,244,241,0.88);
  backdrop-filter: blur(10px);
}
.nav{
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 4.5rem;
}
.nav-mark{
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 1.15rem;
  letter-spacing: 0.01em;
  color: var(--ink);
}
.nav-mark strong{ font-weight: 600; }
.nav-mark span{
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.12em;
  color: var(--ink-faint);
  text-transform: uppercase;
}
.nav-links{
  display: flex;
  gap: clamp(1.25rem, 2.5vw, 2.25rem);
  font-size: 0.9rem;
}
.nav-links a{
  text-decoration: none;
  color: var(--ink-muted);
  padding: 0.4rem 0;
  border-bottom: 1px solid transparent;
  transition: color 150ms ease, border-color 150ms ease;
}
.nav-links a:hover, .nav-links a[aria-current="page"]{
  color: var(--ink);
  border-color: var(--clay);
}
.nav-cta{ display: flex; align-items: center; gap: 1.5rem; }
.nav-toggle{
  display: none;
  background: none;
  border: 1px solid var(--line-strong);
  color: var(--ink);
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 2px;
  align-items: center;
  justify-content: center;
}

/* ---------- footer ---------- */
.site-footer{
  border-top: 1px solid var(--line);
  background: var(--bg-soft);
  padding-block: 3.5rem 2rem;
}
.footer-grid{
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: 2.5rem;
}
.footer-brand p{
  color: var(--ink-muted);
  max-width: 32ch;
  margin-top: 0.75rem;
  font-size: 0.9rem;
}
.footer-col h4{
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.9rem;
}
.footer-col a, .footer-col p{
  display: block;
  color: var(--ink-muted);
  text-decoration: none;
  font-size: 0.9rem;
  margin-bottom: 0.55rem;
}
.footer-col a:hover{ color: var(--clay); }
.footer-bottom{
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  font-size: 0.78rem;
  color: var(--ink-faint);
  font-family: var(--font-mono);
}
.footer-legal{ display: flex; gap: 1.25rem; }
.footer-legal a{ color: inherit; text-decoration: none; }
.footer-legal a:hover{ color: var(--clay); }

/* ---------- section shells ---------- */
section{ padding-block: var(--section-pad); }
.section--tight{ padding-block: clamp(3rem, 6vw, 5rem); }
.section--inset{ background: var(--bg-soft); }
.section--elevated{ background: var(--bg-elevated); }
.divider{ height: 1px; background: var(--line); border: 0; margin: 0; }

/* ---------- hero ---------- */
.hero{
  padding-top: clamp(3.5rem, 8vw, 6rem);
  padding-bottom: clamp(3rem, 6vw, 5rem);
}
.hero-grid{
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
.hero-actions{
  display: flex;
  gap: 1rem;
  margin-top: 2.25rem;
  flex-wrap: wrap;
}
.hero-copy .eyebrow{ margin-bottom: 1.1rem; display: block; }
.hero-copy h1{ margin-bottom: 1.25rem; }

/* ---------- photo hero (home) ---------- */
.hero--photo{
  position: relative;
  min-height: 86vh;
  display: flex;
  align-items: flex-end;
  padding-top: 0;
  padding-bottom: clamp(3rem, 7vw, 5.5rem);
  overflow: hidden;
}
.hero-photo{
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: saturate(0.85) brightness(0.5);
  animation: heroZoom 22s ease-in-out infinite alternate;
}
@keyframes heroZoom{ from{ transform: scale(1); } to{ transform: scale(1.06); } }
.hero-photo-overlay{
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(16,21,26,0.25) 0%, rgba(16,21,26,0.55) 55%, rgba(16,21,26,0.94) 100%);
}
.hero-photo-content{ position: relative; z-index: 2; max-width: 780px; }
.hero-photo-content .eyebrow{ color: #a9c3ce; }
.hero-photo-content h1{ color: #ffffff; }
.hero-photo-content .lede{ color: rgba(255,255,255,0.82); max-width: 54ch; }
.hero-h1{
  max-width: 19ch;
  text-wrap: balance;
  font-size: clamp(2.6rem, 4.9vw, 4.6rem);
}
.hero-caption-bar{
  position: relative;
  z-index: 3;
  background: var(--bg-panel);
}
.hero-photo-caption{
  padding-block: 0.65rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  color: rgba(243,244,241,0.5);
  text-align: right;
}

/* Products — closing water-surface band. Reuses the Home opening hero's
   photo/overlay/white-text/zoom system (.hero-photo, .hero-photo-overlay,
   .hero-photo-content — including its prefers-reduced-motion handling)
   rather than a new component, but at closing-band scale, not full
   opening-hero height, and center- rather than bottom-aligned so the page
   reads as arriving at a poised conclusion rather than a second hero.
   Single-class specificity, so these overrides win by source order alone
   over the earlier .hero--photo rules for the properties redefined here;
   .hero--photo's position/overflow/display:flex are inherited as-is. */
.hero--closing{
  min-height: clamp(420px, 58vh, 620px);
  align-items: center;
  padding-block: clamp(3rem, 6vw, 5rem);
  text-align: center;
}
/* .hero-photo-overlay's default gradient is bottom-heavy (dark at the
   base, much lighter toward the top) because the opening hero's text
   sits flush against the bottom edge. This section centers its text
   instead, so it can land anywhere in the band — including the lighter
   upper region, where it loses contrast against bright highlights in
   the water photo. A flat, uniform darkening (rather than a directional
   gradient) keeps contrast consistent regardless of where the centered
   text falls, while still reading as the same dark-panel treatment. */
.hero--closing .hero-photo-overlay{
  background: rgba(16,21,26,0.62);
}
/* .hero-photo-content h1{color:#fff} (above) only targets h1, since the
   opening hero uses one; this section correctly uses h2 (it isn't the
   page's h1), so it needs its own override or it renders in the default
   dark ink color against a dark photo — effectively invisible. */
.hero--closing h2{ color: #ffffff; }
.hero--closing .hero-photo-content{ margin-inline: auto; }
.hero--closing .lede{ margin-inline: auto; }
.hero--closing .hero-actions{ justify-content: center; margin-top: 2rem; }

/* ---------- scroll reveal (progressive enhancement) ---------- */
.js .card, .js .process-step, .js .stat, .js .timeline-item,
.js .feature-copy, .js .feature-visual, .js .hero-photo-content,
.js .diagram-frame, .js .flow-node, .js .pillar-item, .js .radar-frame,
.js .stage-block, .js .timeline{
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 640ms cubic-bezier(0.22,1,0.36,1), transform 640ms cubic-bezier(0.22,1,0.36,1);
}
.js .is-visible{ opacity: 1; transform: translateY(0); }
.card-grid .card:nth-child(2){ transition-delay: 90ms; }
.card-grid .card:nth-child(3){ transition-delay: 180ms; }
.process .process-step:nth-child(2){ transition-delay: 80ms; }
.process .process-step:nth-child(3){ transition-delay: 160ms; }
.process .process-step:nth-child(4){ transition-delay: 240ms; }
.process .process-step:nth-child(5){ transition-delay: 320ms; }
.stat-strip .stat:nth-child(2){ transition-delay: 70ms; }
.stat-strip .stat:nth-child(3){ transition-delay: 140ms; }
.stat-strip .stat:nth-child(4){ transition-delay: 210ms; }

/* ---------- Phase 2B motion system ----------
   Everything below builds on the reveal architecture above: a parent
   (.diagram-frame, .radar-frame, .feature-copy, .pillar-item…) gets
   `.is-visible` from js/main.js's IntersectionObserver/manualCheck pair,
   and these rules key staged children off that same class — no separate
   scroll-linked/scrubbing engine, no animation library. */

/* Staged build-up inside a diagram: each element sequences off its own
   --stage-delay custom property, set inline per element in the markup.
   transform-box:fill-box makes translateY/scale behave correctly on SVG
   shapes (rect/path/g/circle), not just HTML elements. */
.js .diagram-frame .stage-reveal{
  opacity: 0;
  transform: translateY(8px);
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity 520ms cubic-bezier(0.22,1,0.36,1), transform 520ms cubic-bezier(0.22,1,0.36,1);
  transition-delay: var(--stage-delay, 0ms);
}
.js .diagram-frame.is-visible .stage-reveal{ opacity: 1; transform: translateY(0); }
.js .diagram-frame .stage-reveal--scale{ transform: scale(0.82); }
.js .diagram-frame.is-visible .stage-reveal--scale{ transform: scale(1); }

/* Six-axis maturity radar — axes/rings draw in via stroke-dashoffset,
   labels fade in once drawn, the illustrative polygon builds last. */
.js .radar-frame .radar-axis, .js .radar-frame .radar-ring{
  stroke-dasharray: 420;
  stroke-dashoffset: 420;
  transition: stroke-dashoffset 900ms cubic-bezier(0.22,1,0.36,1);
}
.js .radar-frame.radar-draw .radar-axis{ stroke-dashoffset: 0; }
.js .radar-frame.radar-draw .radar-ring:nth-of-type(1){ stroke-dashoffset: 0; transition-delay: 80ms; }
.js .radar-frame.radar-draw .radar-ring:nth-of-type(2){ stroke-dashoffset: 0; transition-delay: 160ms; }
.js .radar-frame .radar-label{
  opacity: 0;
  transition: opacity 480ms ease;
  transition-delay: 620ms;
}
.js .radar-frame.radar-draw .radar-label{ opacity: 1; }
.js .radar-frame .radar-poly{
  opacity: 0;
  transform: scale(0.6);
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity 700ms ease, transform 700ms cubic-bezier(0.22,1,0.36,1);
  transition-delay: 900ms;
}
.js .radar-frame.radar-draw .radar-poly{ opacity: 1; transform: scale(1); }

/* Technology — five-pillar list builds in order (01→05) on reveal.
   Rows are single-column (heading stacked above description) so long
   headings never compete with the description for width — the previous
   42%/1fr split caused uneven wrapping and row heights. No accent bar:
   all five rows share the same subtle top-border divider. */
.js .feature-list--pillars li{
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 560ms cubic-bezier(0.22,1,0.36,1), transform 560ms cubic-bezier(0.22,1,0.36,1);
  position: relative;
}
.js .feature-list--pillars li.is-visible{ opacity: 1; transform: translateY(0); }
.feature-list--pillars li:nth-child(1){ transition-delay: 0ms; }
.feature-list--pillars li:nth-child(2){ transition-delay: 90ms; }
.feature-list--pillars li:nth-child(3){ transition-delay: 180ms; }
.feature-list--pillars li:nth-child(4){ transition-delay: 270ms; }
.feature-list--pillars li:nth-child(5){ transition-delay: 360ms; }
.feature-list--pillars li:nth-child(6){ transition-delay: 450ms; }

/* Six-pillar diagnostic accordion — native <details>/<summary>, enhanced
   with numbering emphasis, a border-state on open, and a disclosure
   transition for the revealed text. No JS-driven accordion behavior. */
.pillar-item{
  box-shadow: inset 2px 0 0 0 transparent;
  transition: box-shadow 220ms ease, background-color 220ms ease;
}
.pillar-item[open]{
  background: var(--bg-elevated);
  box-shadow: inset 2px 0 0 0 var(--clay);
}
.pillar-num{ color: var(--clay); font-family: var(--font-mono); }
.pillar-item summary{
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.pillar-item summary::-webkit-details-marker{ display: none; }
.pillar-item summary::after{
  content: '+';
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 1.1rem;
  color: var(--ink-faint);
  transition: transform 220ms cubic-bezier(0.22,1,0.36,1), color 220ms ease;
}
.pillar-item[open] summary::after{ transform: rotate(45deg); color: var(--clay); }
.pillar-item[open] p{ animation: pillarDisclose 260ms cubic-bezier(0.22,1,0.36,1); }
@keyframes pillarDisclose{
  from{ opacity: 0; transform: translateY(-4px); }
  to{ opacity: 1; transform: translateY(0); }
}

/* Services methodology rail — a continuous connecting line under the
   Diagnose→Prioritize→Design→Pilot→Scale steps, with per-step nodes that
   activate (outline → filled) as each stage reveals, tying the five
   process-step cards into one visual sequence instead of five unrelated
   cards. */
.process--five{ grid-template-columns: repeat(5, 1fr); }
.process--six{ grid-template-columns: repeat(6, 1fr); }
.process--rail{ position: relative; padding-top: 0.5rem; }
.process--rail::before{
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 1px;
  background: var(--line-strong);
}
.process--rail .process-step{ position: relative; }
.process--rail .process-step::before{
  content: '';
  position: absolute;
  left: 1.5rem; top: -0.5rem;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--bg);
  border: 1.5px solid var(--line-strong);
  transition: background-color 320ms ease, border-color 320ms ease, transform 320ms cubic-bezier(0.22,1,0.36,1);
  transform: scale(0.9);
}
.js .process--rail .process-step.is-visible::before{
  background: var(--clay);
  border-color: var(--clay);
  transform: scale(1);
}

/* About — timeline accent line grows once the timeline enters view,
   layered over the existing static border-left. */
.js .timeline{ position: relative; }
.js .timeline::after{
  content: '';
  position: absolute;
  left: -1px; top: 0;
  width: 1px; height: 0;
  background: var(--clay);
  transition: height 1100ms cubic-bezier(0.22,1,0.36,1);
}
.js .timeline.is-visible::after{ height: 100%; }

/* Homepage — Recovera given more visual weight than HEDRO ECO via a
   restrained accent bar that draws in with the copy, not a floating card
   or fake 3D treatment. */
.js .feature--flagship .feature-copy{ position: relative; padding-left: 1.1rem; }
.js .feature--flagship .feature-copy::before{
  content: '';
  position: absolute;
  left: 0; top: 0.15rem; bottom: 0.15rem;
  width: 2px;
  background: var(--clay);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 760ms cubic-bezier(0.22,1,0.36,1);
  transition-delay: 160ms;
}
.js .feature--flagship .feature-copy.is-visible::before{ transform: scaleY(1); }

/* Contact — restrained micro-interactions only. */
.field input, .field textarea, .field select{
  transition: border-color 180ms ease, box-shadow 180ms ease;
}
.field input:invalid:not(:placeholder-shown),
.field textarea:invalid:not(:placeholder-shown){
  border-color: rgba(178,58,58,0.55);
}
.field--emphasized textarea{
  border-color: var(--clay);
  box-shadow: 0 0 0 3px rgba(28,82,102,0.08);
}
.btn{ transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, transform 160ms ease, box-shadow 160ms ease; }
.btn:active{ transform: translateY(0) scale(0.98); }

/* Mobile fallback for wide horizontal process diagrams — shown only under
   640px, hidden on larger viewports where the SVG diagram is used instead. */
.mobile-steps{ display: none; }

.card{ transition: transform 220ms ease, box-shadow 220ms ease, border-color 220ms ease; }
.card:hover{
  transform: translateY(-3px);
  border-color: var(--line-strong);
  box-shadow: 0 12px 28px rgba(20,23,26,0.08);
}

/* ---------- stat strip ---------- */
.stat-strip{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.stat{
  padding: 2.25rem clamp(1rem, 2vw, 1.75rem);
  border-left: 1px solid var(--line);
}
.stat:first-child{ border-left: none; }
.stat-value{
  font-family: var(--font-mono);
  font-size: clamp(1.6rem, 3vw, 2.3rem);
  color: var(--clay);
  letter-spacing: -0.02em;
}
.stat-label{
  margin-top: 0.5rem;
  font-size: 0.82rem;
  color: var(--ink-muted);
  line-height: 1.4;
}

/* ---------- two-col feature ---------- */
.feature{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
.feature--reverse .feature-copy{ order: 2; }
.feature--reverse .feature-visual{ order: 1; }
/* Kept as a separate, never-transformed wrapper around .feature-visual —
   position:sticky breaks in combination with the transform the reveal
   system applies directly to .feature-visual, so the two responsibilities
   (stick-on-scroll vs. fade-up-on-reveal) must live on different elements. */
.sticky-wrap{ position: sticky; top: 6rem; align-self: start; }
@media (max-width: 960px){
  .sticky-wrap{ position: static; align-self: auto; }
}
/* Technology — platform-layers section only: text column slightly wider
   than the diagram (55/45) so the dark graphic reads as a companion
   visual, not the dominant element; graphic centered against the list
   rather than pinned to its top. */
.feature--pillars{ grid-template-columns: 55fr 45fr; }
.feature--pillars .sticky-wrap{ align-self: center; }
@media (max-width: 960px){
  .feature--pillars{ grid-template-columns: 1fr; }
}
.feature-copy h2{ margin-bottom: 1.1rem; }
.feature-copy p{ color: var(--ink-muted); margin-bottom: 1rem; max-width: 52ch; }
.feature-list{ margin-top: 1.5rem; }
.feature-list li{
  display: grid;
  grid-template-columns: 42% 1fr;
  gap: 0.75rem;
  padding: 0.7rem 0;
  border-top: 1px solid var(--line);
  font-size: 0.92rem;
  color: var(--ink-muted);
}
.feature-list li:last-child{ border-bottom: 1px solid var(--line); }
.feature-list b{ color: var(--ink); font-weight: 500; }
/* Technology — platform-layers list only: single-column rows (heading
   stacked above description) at every width, so long headings never
   compete with the description for space. Must follow the base
   .feature-list rules above so it wins the cascade at equal specificity. */
.feature-list--pillars li{
  grid-template-columns: 1fr;
  row-gap: 0.35rem;
}
.feature-list--pillars b{
  display: block;
  font-size: 0.98rem;
}
.feature-list--pillars span{ max-width: 60ch; }

/* ---------- process ---------- */
.process{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
/* Three-column variant (e.g. homepage Problem/Deployment Gap) — placed
   before the responsive block below so the existing .process breakpoints
   (2-col at 960px, 1-col at 640px) still win by cascade order at their
   media widths, same as the default 4-column layout. */
.process--three{ grid-template-columns: repeat(3, 1fr); }
.process-step{
  background: var(--bg);
  padding: 2rem 1.5rem;
}
.process-step .stage{
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--clay);
}
.process-step h3{
  font-size: 1.15rem;
  margin-top: 0.6rem;
  margin-bottom: 0.6rem;
}
.process-step p{
  font-size: 0.88rem;
  color: var(--ink-muted);
}

/* ---------- cards ---------- */
.card-grid{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}
/* Two-column variant (e.g. About page regional presence) — placed before
   the responsive block below so the existing .card-grid breakpoints
   (2-col at 960px, 1-col at 640px) still win by cascade order at their
   media widths, same as the default 3-column layout. */
.card-grid--two{ grid-template-columns: repeat(2, 1fr); }
.card{
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  padding: 2rem;
  border-radius: 3px;
}
.card h2, .card h3{ font-size: 1.15rem; margin-bottom: 0.75rem; }
.card p{ color: var(--ink-muted); font-size: 0.92rem; }

/* ---------- spec table ---------- */
.spec-table{
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.spec-table th{
  text-align: left;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--line-strong);
}
.spec-table td{
  padding: 0.95rem 1rem;
  border-bottom: 1px solid var(--line);
  color: var(--ink-muted);
}
.spec-table td:first-child{ color: var(--ink); }
.spec-table td.mono, .spec-table th.mono{ font-family: var(--font-mono); color: var(--clay); }

/* ---------- CTA band ---------- */
.cta-band{
  background: var(--bg-soft);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  text-align: center;
}
.cta-band h2{ margin-bottom: 1.25rem; }
.cta-band .lede{ margin-inline: auto; text-align: center; }
.cta-band .hero-actions{ justify-content: center; margin-top: 2rem; }

/* ---------- diagram ----------
   Diagrams stay dark, like an instrument-panel viewport set
   into the page — the one place the platform's signal color
   runs at full brightness. Locally overrides the page tokens
   so every var(--ink)/var(--clay-soft) etc. used inside an
   SVG panel resolves to its dark-surface value automatically. */
.diagram-frame{
  --bg-elevated: #1a2229;
  --ink: #f3f4f1;
  --ink-muted: #b9c2c6;
  --ink-faint: #7c868c;
  --line: rgba(243,244,241,0.10);
  --line-strong: rgba(243,244,241,0.22);
  --clay: #3e7c93;
  position: relative;
  background: radial-gradient(120% 120% at 30% 20%, rgba(107,182,214,0.09), transparent 60%), var(--bg-panel);
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: clamp(1.5rem, 4vw, 2.5rem);
}
.diagram-caption{
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  text-align: center;
}

.diagram text{ font-family: var(--font-mono); }
text.eyebrow-svg{ font-size: 10.5px; letter-spacing: 0.06em; fill: var(--ink-faint); text-transform: uppercase; }
text.mono-svg{ font-size: 13px; fill: var(--ink-muted); }
text.accent-svg{ fill: var(--clay-soft); }
text.accent-teal-svg{ fill: var(--teal-soft); }

/* Vertical Reactor Architecture — public patent-safe system-envelope image.
   Deliberately small/muted: it labels a function count, not a process
   step, and must stay visually secondary to .diagram-caption's disclaimer. */
.vr-envelope-img{ max-width: 260px; height: auto; margin-inline: auto; }
.envelope-label{
  margin-top: 1.6rem;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  opacity: 0.85;
}

/* Vertical Reactor Architecture — animated available-head / vertical-
   envelope / head-assisted-withdrawal schematic. The base shapes (head
   line, envelope, withdrawal path) are always visible via the existing
   .stage-reveal reveal-on-scroll system; these three classes add only a
   subtle looping highlight on top of that static structure. Each keyframe
   set starts and ends at opacity:0, so the sitewide prefers-reduced-motion
   rule (animation-iteration-count:1 forced) always resolves to the
   complete static schematic with no travelling highlight — no separate
   reduced-motion override needed here. Pure CSS transform/opacity/stroke,
   no JavaScript, no SMIL. */
.vr-head-dot{ animation: vrHeadPulse 7s ease-in-out infinite forwards; }
.vr-envelope-scan{ animation: vrEnvelopeScan 7s ease-in-out infinite forwards; }
.vr-withdraw-dash{ animation: vrWithdrawPulse 7s ease-in-out infinite forwards; }
@keyframes vrHeadPulse{
  0%   { opacity: 0; transform: translateY(0); }
  6%   { opacity: 0.9; }
  26%  { opacity: 0.9; transform: translateY(110px); }
  34%  { opacity: 0; transform: translateY(110px); }
  100% { opacity: 0; transform: translateY(0); }
}
@keyframes vrEnvelopeScan{
  0%   { opacity: 0; transform: translateY(0); }
  36%  { opacity: 0; transform: translateY(0); }
  46%  { opacity: 0.3; }
  64%  { opacity: 0.3; transform: translateY(180px); }
  72%  { opacity: 0; transform: translateY(180px); }
  100% { opacity: 0; transform: translateY(0); }
}
@keyframes vrWithdrawPulse{
  0%   { opacity: 0; stroke-dashoffset: 0; }
  72%  { opacity: 0; stroke-dashoffset: 0; }
  78%  { opacity: 0.9; }
  94%  { opacity: 0.9; stroke-dashoffset: -64; }
  100% { opacity: 0; stroke-dashoffset: -64; }
}

/* ---------- contact ---------- */
.contact-grid{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
}
.field{ margin-bottom: 1.4rem; }
.field label{
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.5rem;
}
.field input, .field textarea, .field select{
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--line-strong);
  color: var(--ink);
  padding: 0.85rem 1rem;
  border-radius: 2px;
  font-family: var(--font-body);
  font-size: 0.95rem;
}
.field textarea{ resize: vertical; min-height: 8rem; }
.field input:focus, .field textarea:focus, .field select:focus{ border-color: var(--teal); }

.contact-info dt{
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 1.5rem;
}
.contact-info dt:first-child{ margin-top: 0; }
.contact-info dd{
  margin: 0.4rem 0 0;
  font-size: 1.05rem;
}
.contact-info a{ text-decoration: none; color: var(--clay); }

/* ---------- legal pages (Impressum / Datenschutz) ----------
   Narrower reading column than the site's marketing sections —
   dense legal prose reads better at ~64ch than the ~1180px
   container width used elsewhere. */
.legal-content{ max-width: 64ch; }
.legal-content h2{
  font-family: var(--font-display);
  margin-top: 3rem;
  margin-bottom: 1rem;
}
.legal-content h2:first-child{ margin-top: 0; }
.legal-content p{ color: var(--ink-muted); margin: 0 0 1rem; }
.legal-content ul{
  list-style: disc;
  padding-left: 1.25rem;
  margin: 0 0 1.25rem;
}
.legal-content li{ color: var(--ink-muted); margin-bottom: 0.4rem; }
.legal-content .contact-info{ margin-bottom: 1.5rem; }

/* ---------- page hero (interior pages) ---------- */
.page-hero{
  padding-top: clamp(3rem, 7vw, 5rem);
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
  border-bottom: 1px solid var(--line);
}
.page-hero .lede{ margin-top: 1.1rem; }

/* Services hero — breakout two-column split, scoped to .services-hero-frame
   (services.html only). Unlike every other two-column hero on the site,
   this one deliberately does NOT sit inside .container: the wrapper's
   left margin is computed with the same formula .container uses (so the
   eyebrow/heading/lede start at the exact x-position every other page's
   heading does — text position is untouched), but its right margin is
   just the standard gutter instead of the symmetric centering margin
   .container would apply. That gives the image column substantially more
   width than a conventional contained split once the viewport exceeds
   the container's max-width, without ever moving the text. Below that
   width the max() falls back to the plain gutter and the layout behaves
   like an ordinary contained two-column grid; the 960px breakpoint below
   collapses it to one column same as every other two-col hero. */
.services-hero-frame{
  margin-left: max(var(--gutter), calc((100vw - var(--container)) / 2));
  margin-right: var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.3fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
}
@media (max-width: 960px){
  .services-hero-frame{ grid-template-columns: 1fr; }
}

/* Aerial water-treatment infrastructure photo. 4/5 portrait at desktop is
   a deliberate choice for this specific source image: it's landscape
   (2000x1600), so a taller-than-native target ratio makes object-fit:
   cover scale to match height rather than width — meaning it crops the
   sides but keeps the FULL vertical extent (tree line, the two circular
   structures, the central basin, the lower channels) with zero vertical
   loss. object-position 55% keeps both circular structures in frame
   (they sit slightly right of the photo's own centerline). 4/3 on mobile
   crops only ~6% of the frame either way — effectively the whole image
   stays visible, never a thin panoramic strip. */
.services-hero-image-frame{
  position: relative;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 4 / 5;
}
.services-hero-image-frame img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 55% 50%;
  display: block;
}
@media (max-width: 960px){
  .services-hero-image-frame{ aspect-ratio: 4 / 3; }
  .services-hero-image-frame img{ object-position: 50% 45%; }
}
/* Restrained engineering-drawing overlay on top of the unaltered photo —
   corner registration ticks, a dashed site-boundary inset and a compass
   glyph, in the same white technical linework every SVG diagram on the
   site already uses, applied here to a real photograph instead of an
   abstract panel. No color grading on the photo itself. */
.services-hero-overlay{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Products hero — scoped two-column split, used only where .products-hero
   is present (products.html). Same architecture as .institute-hero below
   (grid text/visual split layered on the shared .page-hero), kept as its
   own class so it doesn't touch that pattern or the plain .page-hero used
   on About/Contact/Technology. align-items:start (not center) is the
   deliberate difference: the text must stay pinned to its current
   top-left position regardless of how tall the companion diagram renders,
   not drift to a vertically centered position against it. */
.products-hero{
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}
@media (max-width: 960px){
  .products-hero{ grid-template-columns: 1fr; }
}

/* Services / Institute hero — scoped two-column split, used only where
   .institute-hero is present (services.html). Does not touch the shared
   .page-hero pattern used by other interior pages. Reuses .stage-block
   and .feature-visual purely for their existing reveal transition (both
   already in js/main.js's revealTargets) — no new motion code. */
.institute-hero{
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
.institute-hero-visual{
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 4 / 5;
}
.institute-hero-visual img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 45% 42%;
  display: block;
}
@media (max-width: 960px){
  .institute-hero{ grid-template-columns: 1fr; }
  .institute-hero-visual{ aspect-ratio: 16 / 10; }
  .institute-hero-visual img{ object-position: 50% 38%; }
}

/* Institute operations hall — wide editorial transition image between the
   positioning copy and the six-pillar diagnostic scope. Full container
   width, restrained hairline border consistent with .diagram-frame /
   .institute-hero-visual, no caption/overlay. */
.institute-editorial{
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 16 / 7;
}
.institute-editorial img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 90%;
  display: block;
}
@media (max-width: 960px){
  .institute-editorial{ aspect-ratio: 4 / 3; }
}

/* About — water-infrastructure editorial transition image between the
   founding thesis paragraph and the company timeline. Same restrained
   treatment as the Institute editorial image above. */
.about-editorial{
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
.about-editorial img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  display: block;
}
@media (max-width: 960px){
  .about-editorial{ aspect-ratio: 4 / 5; }
  .about-editorial img{ object-position: 60% 42%; }
}

/* About — engineering/construction editorial transition image between the
   company timeline and the patent section. Same restrained treatment as
   the other editorial images above. */
.engineering-editorial{
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
.engineering-editorial img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  display: block;
}
@media (max-width: 960px){
  .engineering-editorial{ aspect-ratio: 4 / 5; }
}

/* Home — Al-Tall field-context photo, full-VIEWPORT-bleed editorial band
   (supersedes the earlier container-width .altall-editorial treatment).
   .altall-field-band uses the standard left:50%/-50vw breakout so the
   image spans the true viewport edge to edge regardless of the section's
   own container/padding; .altall-field-section drops the section's own
   top padding so the photo sits flush at the very top of the section for
   an immersive, unboxed entrance, while keeping the normal bottom
   padding rhythm for the Al-Tall text content beneath it. No border/
   radius here (a full-bleed band reads as a page-edge plate, not a
   framed panel — a hairline border made no sense once the frame's own
   edges are off-screen). No overlay on the photo itself; all metadata
   lives below it in .altall-field-caption instead, keeping the image
   clean per the "no decorative overlays" brief.

   The source photo is square (2000x2000), shot as a phone panorama with
   a tall band of empty sky above the settlement. At full-viewport width
   and a 16/9 target, object-fit:cover crops aggressively (cover always
   scales to match container width here, since target aspect > 1 while
   source aspect = 1) — object-position 50% 62% biases the visible slice
   toward the settlement/hillside band and away from the empty sky.
   max-height keeps the band from becoming excessive on very wide
   viewports (100vw at 16/9 alone would exceed 700px past ~1250px wide).
   Mobile switches to 1/1 — matching the source exactly, so the ENTIRE
   photograph shows with zero cropping, the safest way to guarantee the
   settlement stays legible and the band never reads as a shallow strip. */
.altall-field-section{
  padding-top: 0;
  padding-bottom: clamp(3rem, 6vw, 5rem);
}
.altall-field-band{
  position: relative;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  aspect-ratio: 16 / 9;
  max-height: 640px;
  overflow: hidden;
}
.altall-field-band img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 62%;
  display: block;
}
@media (max-width: 640px){
  .altall-field-band{ aspect-ratio: 1 / 1; max-height: none; }
}
.altall-field-caption{
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.9rem;
  padding-top: 1.25rem;
  margin-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.altall-field-caption span{
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.altall-field-caption p{
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
}

/* Technology — Pillar 02 (Biological Treatment) full-width industrial
   aeration-basin photograph. Same restrained editorial-image recipe used
   elsewhere on the site (hairline border, no caption overlay, object-fit
   cover) but sized to the full content width rather than paired in a
   two-column .feature — the photograph carries the section rather than
   illustrating a text block beside it. 16/9 keeps both basins (the
   turbulent mixing zone and the aerated diffuser grid below it) in frame;
   object-position weights slightly toward the diffuser pattern, the more
   legible "aeration" cue. 4/3 on mobile crops less aggressively than a
   portrait ratio would on this landscape, top-down source photo. */
.biotreat-editorial{
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
.biotreat-editorial img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 62%;
  display: block;
}
@media (max-width: 960px){
  .biotreat-editorial{ aspect-ratio: 4 / 3; }
}

/* Products — real industrial membrane-treatment hall, editorial transition
   between the complete Recovera VRR-1 section and HEDRO ECO. Same recipe
   as .biotreat-editorial (hairline border, no chrome, object-fit cover,
   full content width) — deliberately NOT paired in a two-column .feature
   with copy, so it reads as a field-context pause rather than another
   product image. Source is a wide-angle membrane hall (pressure-vessel
   racks, piping, a "…WATER" labelled vessel) at 2000x1600 (5:4); 16/9
   desktop keeps every vessel rack and most of the piping in frame while
   trimming ceiling ductwork and catwalk floor — object-position is
   pushed high (17%) because the vessels and pipework sit in the upper
   two-thirds of the source and the empty floor grating in the lower
   third contributes the least context. 4/3 mobile crops only ~6% of the
   frame, effectively showing the whole photograph. */
.recovera-membrane-editorial{
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
.recovera-membrane-editorial img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 17%;
  display: block;
}
@media (max-width: 960px){
  .recovera-membrane-editorial{ aspect-ratio: 4 / 3; }
  .recovera-membrane-editorial img{ object-position: 50% 30%; }
}

/* Technology — Digital & AI Operations, mobile fallback (<=640px, inside
   .mobile-steps, replacing the wide SVG). Reuses .diagram-frame for the
   same dark instrument-panel surface as the desktop visual instead of
   introducing a new light "card" look, so the control loop still reads
   as one continuous technical system rather than plain leftover text.
   Scoped entirely to .aiops-mobile-* — does not touch .mobile-steps or
   .process, which products.html's own mobile fallback still uses as-is. */
.aiops-mobile-loop{ display: flex; flex-direction: column; }
.aiops-mobile-step{
  display: grid;
  grid-template-columns: 2rem 1fr;
  gap: 0.9rem;
  position: relative;
  padding-bottom: 1.75rem;
}
.aiops-mobile-step:last-child{ padding-bottom: 0; }
.aiops-mobile-step:not(:last-child)::before{
  content: '';
  position: absolute;
  left: 0.9375rem;
  top: 2rem;
  bottom: 0;
  width: 1px;
  background: var(--line-strong);
}
.aiops-mobile-num{
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--bg-elevated);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-faint);
  position: relative;
  z-index: 1;
}
.aiops-mobile-step--feedback .aiops-mobile-num{
  color: var(--teal-soft);
  border-color: var(--teal-soft);
}
.aiops-mobile-tag{
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--teal-soft);
}
.aiops-mobile-body h3{ font-size: 1.05rem; margin: 0.35rem 0 0.4rem; color: var(--ink); }
.aiops-mobile-body p{ font-size: 0.88rem; color: var(--ink-muted); margin: 0; }

/* Technology — AFM surface-characterization pair: two research-plate
   panels, same treatment as the product-render frames below (light
   elevated background, hairline border, no drop shadow). Grid row
   stretch gives both panels equal height; each image is width-driven
   (no object-fit cropping) so axis labels / Rq annotations at the
   image edges are never cut. Stacks on mobile. */
.afm-gallery{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.afm-gallery-frame{
  background: var(--bg-elevated);
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  padding: clamp(1rem, 3vw, 1.75rem);
  display: flex;
  align-items: center;
  justify-content: center;
}
.afm-gallery-frame img{
  width: 100%;
  height: auto;
  display: block;
}
@media (max-width: 960px){
  .afm-gallery{ grid-template-columns: 1fr; }
}

/* Products — Recovera VRR-1 exterior render. Light elevated frame (not
   .diagram-frame's dark panel) since the render already sits on its own
   neutral studio background — a dark panel would clash with it. No
   cropping: the full skid is preserved via natural aspect ratio. */
.recovera-hero{
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
.recovera-exterior-frame{
  background: var(--bg-elevated);
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  padding: clamp(1rem, 3vw, 1.75rem);
  display: flex;
  align-items: center;
  justify-content: center;
}
.recovera-exterior-img{
  width: 100%;
  height: auto;
  display: block;
}
@media (max-width: 960px){
  .recovera-hero{ grid-template-columns: 1fr; }
}

/* Products — HEDRO ECO exterior render + process architecture. Exterior
   reuses the Recovera exterior frame treatment (.recovera-exterior-frame /
   .recovera-exterior-img) for visual consistency between the two product
   presentations. The process-architecture diagram gets its own frame:
   wide, uncropped (the image already contains its own stage labels and
   disclaimer text, so cropping would remove real content). */
.hedro-eco-hero{
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
@media (max-width: 960px){
  .hedro-eco-hero{ grid-template-columns: 1fr; }
}
/* HEDRO ECO — animated conceptual process architecture (replaces the old
   static hedro-eco-process-architecture image). Bespoke per-node micro-
   motion layered on top of an always-visible static structure — boxes,
   arrows and labels never animate, only these accents do — so the
   diagram stays fully legible under prefers-reduced-motion: the sitewide
   rule above forces animation-iteration-count:1, and every keyframe set
   here resolves to a sensible resting frame (mostly opacity:0, i.e. the
   accent simply isn't drawn, leaving the always-static labeled boxes/
   arrows to carry the full explanation on their own). SMIL flow-dots
   (animateMotion) are paused separately by js/main.js for every
   .diagram-frame svg, the same mechanism already used by Recovera's and
   the ceramic-membrane diagram's flow dots — no new JS needed here. */
.hedroeco-bubble{
  animation: hedroecoBubble 3.6s ease-in infinite;
  transform-box: fill-box;
  transform-origin: center;
}
.hedroeco-bubble:nth-of-type(2){ animation-delay: 1.1s; }
.hedroeco-bubble:nth-of-type(3){ animation-delay: 2.2s; }
@keyframes hedroecoBubble{
  0%   { opacity: 0; transform: translateY(0); }
  15%  { opacity: 0.85; }
  85%  { opacity: 0.5; }
  100% { opacity: 0; transform: translateY(-26px); }
}
.hedroeco-equalize-ripple{
  stroke-dasharray: 6 5;
  animation: hedroecoRipple 2.8s linear infinite;
}
@keyframes hedroecoRipple{
  0%   { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -22; }
}
.hedroeco-permeate-dot{
  animation: hedroecoPermeate 3.2s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}
.hedroeco-permeate-dot:nth-of-type(2){ animation-delay: 1.05s; }
.hedroeco-permeate-dot:nth-of-type(3){ animation-delay: 2.1s; }
@keyframes hedroecoPermeate{
  0%   { opacity: 0; transform: translateX(0); }
  20%  { opacity: 0.9; }
  80%  { opacity: 0.9; }
  100% { opacity: 0; transform: translateX(34px); }
}
.hedroeco-disinfect-pulse{
  animation: hedroecoPulse 3s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}
@keyframes hedroecoPulse{
  0%, 100% { opacity: 0.3; transform: scale(0.9); }
  50%      { opacity: 1; transform: scale(1.08); }
}

/* HEDRO ECO — mobile fallback (<=640px, inside .mobile-steps, replacing
   the wide SVG). Same dark instrument-panel + numbered-loop treatment as
   the Digital & AI Operations mobile fallback on the Technology page,
   reimplemented under its own hedroeco-mobile-* classes so this stays
   fully independent of that page and of Recovera's own .mobile-steps
   content on this page. */
.hedroeco-mobile-loop{ display: flex; flex-direction: column; }
.hedroeco-mobile-step{
  display: grid;
  grid-template-columns: 2rem 1fr;
  gap: 0.9rem;
  position: relative;
  padding-bottom: 1.75rem;
}
.hedroeco-mobile-step:last-child{ padding-bottom: 0; }
.hedroeco-mobile-step:not(:last-child)::before{
  content: '';
  position: absolute;
  left: 0.9375rem;
  top: 2rem;
  bottom: 0;
  width: 1px;
  background: var(--line-strong);
}
.hedroeco-mobile-num{
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--bg-elevated);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-faint);
  position: relative;
  z-index: 1;
}
.hedroeco-mobile-step--outlet .hedroeco-mobile-num{
  color: var(--teal-soft);
  border-color: var(--teal-soft);
}
.hedroeco-mobile-tag{
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--teal-soft);
}
.hedroeco-mobile-body h3{ font-size: 1.05rem; margin: 0.35rem 0 0.4rem; color: var(--ink); }
.hedroeco-mobile-body p{ font-size: 0.88rem; color: var(--ink-muted); margin: 0; }
/* Solids/sludge branch — visually distinct from the main numbered water
   path: indented off the Biological Treatment step, dashed border, muted
   (not teal) tag, so it reads as a secondary, slower branch rather than
   another primary stage. */
.hedroeco-mobile-branch{
  grid-column: 1 / -1;
  margin: 0.9rem 0 0 2.9rem;
  padding: 0.85rem 1rem;
  border: 1px dashed var(--line-strong);
  border-radius: 3px;
  opacity: 0.85;
}
.hedroeco-mobile-branch .hedroeco-mobile-tag{ color: var(--ink-faint); }
.hedroeco-mobile-branch p{ font-size: 0.82rem; color: var(--ink-muted); margin: 0.3rem 0 0; }

.breadcrumb{
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 1.25rem;
}
.breadcrumb a{ color: var(--ink-faint); text-decoration: none; }
.breadcrumb a:hover{ color: var(--clay); }

/* ---------- company timeline (about) ----------
   Engineering-progression rail: a wide two-column item grid (mono stage
   number + short tag in a dedicated marker column, heading/body in a
   wider content column) rather than the old single-line "stage" label
   crammed above the heading. The growing accent overlay on .timeline
   itself (.js .timeline::after, defined earlier in the scroll-reveal
   block) and each .timeline-item's individual fade-up reveal are both
   pre-existing sitewide mechanisms — reusing the same class names here
   means no JS changes were needed to wire this up. A short horizontal
   tick (replacing the old filled-circle node) crosses the rail at each
   stage, echoing the corner-tick/registration-mark linework used on the
   Services hero photo overlay elsewhere on the site. */
.timeline{
  border-left: 1px solid var(--line-strong);
  padding-left: 2.25rem;
  max-width: 860px;
}
.timeline-item{
  position: relative;
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 0.5rem 1.75rem;
  padding-bottom: 2.75rem;
}
.timeline-item:last-child{ padding-bottom: 0; }
.timeline-item::before{
  content: '';
  position: absolute;
  left: -2.25rem;
  top: 0.6rem;
  width: 1.1rem;
  height: 2px;
  background: var(--clay);
}
.timeline-item-num{
  display: block;
  font-family: var(--font-mono);
  font-size: 1.6rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1;
  color: var(--clay);
}
.timeline-item-tag{
  display: block;
  margin-top: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.timeline-item-body h3{ font-size: 1.35rem; margin: 0 0 0.6rem; }
.timeline-item-body p{ color: var(--ink-muted); max-width: 58ch; }
.timeline-item-signal{
  margin-top: 0.85rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--ink-muted);
}
.timeline-item-signal span{
  color: var(--ink-faint);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 0.66rem;
}

/* ---------- responsive ---------- */
@media (max-width: 960px){
  .hero-grid, .feature, .feature--reverse .feature-copy, .feature--reverse .feature-visual,
  .contact-grid{
    grid-template-columns: 1fr;
  }
  .feature--reverse .feature-copy{ order: 1; }
  .feature--reverse .feature-visual{ order: 2; }
  .stat-strip{ grid-template-columns: repeat(2, 1fr); }
  .stat:nth-child(3){ border-left: none; }
  .process{ grid-template-columns: repeat(2, 1fr); }
  .card-grid{ grid-template-columns: repeat(2, 1fr); }
  .footer-grid{ grid-template-columns: 1fr 1fr; row-gap: 2rem; }
}
@media (max-width: 640px){
  .nav-links{
    position: fixed;
    inset: 4.5rem 0 0 0;
    background: var(--bg);
    flex-direction: column;
    padding: 2rem var(--gutter);
    gap: 1.5rem;
    font-size: 1.1rem;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms ease, transform 180ms ease;
  }
  .nav-links.is-open{
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .nav-cta .btn--ghost{ display: none; }
  .nav-toggle{ display: inline-flex; }
  .stat-strip, .process, .card-grid{ grid-template-columns: 1fr; }
  .stat, .process-step{ border-left: none; border-top: 1px solid var(--line); }
  .stat:first-child, .process-step:first-child{ border-top: none; }
  .footer-grid{ grid-template-columns: 1fr; gap: 2rem; }
  .footer-bottom{ flex-direction: column; gap: 0.5rem; }

  /* Company timeline — collapse the number/tag marker column to sit as
     an inline row above the heading instead of beside it. */
  .timeline{ padding-left: 1.75rem; }
  .timeline-item{ grid-template-columns: 1fr; gap: 0.4rem; padding-bottom: 2.25rem; }
  .timeline-item::before{ left: -1.75rem; }
  .timeline-item-marker{ display: flex; align-items: baseline; gap: 0.65rem; }
  .timeline-item-tag{ margin-top: 0; }

  /* Motion simplification on small viewports: shorter travel distance,
     no continuous hero zoom, and the connecting rail (built for a wide
     row of steps) steps aside for a plain vertical stack. */
  .js .card, .js .process-step, .js .stat, .js .timeline-item,
  .js .feature-copy, .js .feature-visual, .js .hero-photo-content,
  .js .diagram-frame, .js .flow-node, .js .pillar-item, .js .radar-frame,
  .js .stage-block{
    transform: translateY(12px);
  }
  .hero-photo{ animation: none; }
  .process--rail::before,
  .process--rail .process-step::before{ display: none; }

  /* Wide horizontal flow diagrams give way to a plain vertical step
     sequence below 640px instead of a horizontally-scrolling SVG. */
  .diagram-frame.diagram--wide{ display: none; }
  .mobile-steps{ display: block; }

  /* Services — six-pillar accordion and deliverables list were fixed
     2-column grids with no mobile break (pre-existing gap versus every
     other grid on the site, which already collapses to 1 column here). */
  .pillar-grid, .deliverables-grid{ grid-template-columns: 1fr !important; }
}
