/* ============================================================================
   Venus Engineering Works — site stylesheet
   Design language follows DesignBoard.html. Two themes, each with its own
   palette rather than an inversion of the other: light (the default) is a
   neutral paper ramp tuned for spec sheets read under plant lighting; dark is
   the board's own surface ramp. Both carry the Venu logo blue as the accent.
   ========================================================================= */

/* ----------------------------------------------------------- theme: light -
   Light is the default: bare :root carries it, so a visitor with JS off (the
   <head> script never runs) or with nothing stored still gets the white page.
   Dark only applies when the toggle has written data-theme="dark". */
:root,
:root[data-theme="light"]{
  --bg:        #FFFFFF;
  --bg-2:      #F7F7F9;
  --surface:   #FFFFFF;
  --surface-2: #F5F5F7;
  --surface-3: #ECECEF;

  --border:    rgba(9,9,11,.10);
  --border-2:  rgba(9,9,11,.18);

  --text:      #101014;
  --text-2:    #52525B;
  --text-3:    #66666F;   /* 4.8:1 on the tinted surfaces, AA at 10px */

  /* Venu logo blue. The wordmark's dominant pixels are #205888/#285888, so
     the fill is #23598B itself (7.3:1 under white) and the gradient runs to a
     brighter companion blue (#2A6DAB, 5.4:1) — blue to blue, never purple.
     As text it is 6.2:1 even on --surface-3. */
  --accent:      #23598B;
  --accent-2:    #2A6DAB;
  --accent-ink:  #FFFFFF;
  --accent-text: #23598B;
  --accent-soft: rgba(35,89,139,.08);
  --accent-line: rgba(35,89,139,.28);
  --accent-glow: rgba(35,89,139,.28);
  /* headline gradient text (.grad): large display type, so 3:1 is the bar;
     the palest stop is 3.9:1 on white */
  --grad-1: #23598B;
  --grad-2: #2A6DAB;
  --grad-3: #3A86C8;

  --ok:   #047857;
  --warn: #B45309;
  --err:  #BE123C;

  --plate:      #FFFFFF;
  --plate-edge: rgba(9,9,11,.07);
  --stage:      radial-gradient(115% 85% at 50% 8%, #FFFFFF 0%, #F4F4F6 58%, #EBEBEF 100%);
  --stage-floor: radial-gradient(60% 12% at 50% 92%, rgba(9,9,11,.10), transparent 70%);

  --shadow-sm: 0 1px 2px rgba(9,9,11,.05);
  --shadow-md: 0 4px 16px rgba(9,9,11,.07);
  --shadow-lg: 0 12px 32px rgba(9,9,11,.10);
  --shadow-xl: 0 24px 60px rgba(9,9,11,.13);

  --grid-line: rgba(9,9,11,.028);
  --glass:     rgba(255,255,255,.78);
  --glass-2:   rgba(255,255,255,.97);
  --scrim:     rgba(0,0,0,.42);
  color-scheme: light;
}

/* ------------------------------------------------------------ theme: dark - */
:root[data-theme="dark"]{
  --bg:        #09090B;
  --bg-2:      #0D0D10;
  --surface:   #131316;
  --surface-2: #1A1A1F;
  --surface-3: #212127;

  --border:    rgba(255,255,255,.08);
  --border-2:  rgba(255,255,255,.14);

  --text:      #FAFAFA;
  --text-2:    #A1A1AA;
  /* the board's #63636B reads as 3.5:1 here; --text-3 carries 10-12px labels
     (chips, breadcrumbs, spec row headers) so it has to clear AA at small size */
  --text-3:    #8A8A94;

  /* The logo blue lifted a step so a fill still reads against the near-black
     ground (#2D6FAD is 3.8:1 on --bg, enough for rings, rules and dots) while
     white labels on it stay AA: 5.3:1, and 4.6:1 at the #3478B8 end of the
     gradient — worst point on the ramp. */
  --accent:      #2D6FAD;
  --accent-2:    #3478B8;
  --accent-ink:  #FFFFFF;
  /* a fill blue as TEXT on these surfaces is only 3.3-3.8:1 — lifted for text
     only: 7.2:1 on --surface-3, 8.4:1 on --surface */
  --accent-text: #7DB3E6;
  --accent-soft: rgba(58,134,200,.14);
  --accent-line: rgba(58,134,200,.36);
  --accent-glow: rgba(45,111,173,.45);
  --grad-1: #4F8FCC;   /* 5.8:1 on --bg */
  --grad-2: #7DB3E6;
  --grad-3: #A9D0F2;

  --ok:   #10B981;
  --warn: #F59E0B;
  --err:  #F43F5E;

  /* product art is background-knockout PNG/WebP (see _build/cutout_images.py),
     so the "plate" is a lit stage the part stands on, not a white box */
  --plate:      #F2F3F5;
  --plate-edge: rgba(255,255,255,.08);
  --stage:      radial-gradient(115% 85% at 50% 8%, #23232B 0%, #17171B 55%, #121215 100%);
  --stage-floor: radial-gradient(60% 12% at 50% 92%, rgba(0,0,0,.55), transparent 70%);

  --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --shadow-md: 0 4px 16px rgba(0,0,0,.4);
  --shadow-lg: 0 12px 40px rgba(0,0,0,.5);
  --shadow-xl: 0 24px 70px rgba(0,0,0,.6);

  --grid-line: rgba(255,255,255,.022);
  --glass:     rgba(9,9,11,.72);
  --glass-2:   rgba(13,13,16,.96);
  --scrim:     rgba(0,0,0,.55);
  color-scheme: dark;
}

/* ----------------------------------------------------- tokens: invariant -- */
:root{
  --font-ui:   'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-disp: 'Space Grotesk', 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'Cascadia Code', Consolas, monospace;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 24px;

  --content-w: 1200px;
  --wide-w:    1440px;
  --header-h:  68px;
  --gut: clamp(18px, 4vw, 32px);

  /* fluid type — scales from 360px to 1600px without a breakpoint jump */
  --fs-h1:  clamp(30px, 1.6rem + 2.2vw, 54px);
  --fs-h2:  clamp(23px, 1.3rem + 1.1vw, 33px);
  --fs-h3:  clamp(16px, 1rem + .2vw, 17.5px);
  --fs-body:clamp(14.5px, .9rem + .15vw, 15.5px);
  --fs-lead:clamp(15.5px, .95rem + .35vw, 17px);

  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
}

/* ---------------------------------------------------------------- base ---- */
*{ margin:0; padding:0; box-sizing:border-box; }
html{ scroll-behavior:smooth; -webkit-text-size-adjust:100%; }
body{
  background:var(--bg);
  color:var(--text);
  font-family:var(--font-ui);
  font-size:var(--fs-body);
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
  transition:background .3s var(--ease), color .3s var(--ease);
}
::selection{ background:var(--accent); color:var(--accent-ink); }
/* height:auto is load-bearing. Every <img> carries width/height attributes for
   CLS, and those map to presentational hints that make height *definite* — which
   silently disables `aspect-ratio` and squashes the image the moment max-width
   constrains it. Rules that position an image absolutely set their own height
   and win on specificity. */
img{ max-width:100%; height:auto; display:block; }
a{ color:inherit; }
svg{ flex-shrink:0; }
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }
button{ font-family:inherit; }

.wrap{ max-width:var(--content-w); margin:0 auto; padding:0 var(--gut); }
.wrap-wide{ max-width:var(--wide-w); margin:0 auto; padding:0 var(--gut); }

.skip{
  position:absolute; left:-9999px; top:0; z-index:200;
  background:var(--accent); color:var(--accent-ink); padding:10px 18px;
  border-radius:0 0 var(--r-sm) 0; font-weight:600; font-size:13.5px;
}
.skip:focus{ left:0; }

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

/* The blanket rule above already zeroes durations; the gallery additionally
   drops the transforms themselves, so a reduced-motion swap is a plain
   instant replacement rather than a 0ms jump between two offset positions. */
@media (prefers-reduced-motion: reduce){
  .gal-card:hover{ transform:none; }
  .gal-card:hover .gal-media img{ transform:none; }
  .lb-img.pre-next, .lb-img.pre-prev,
  .lb-img.out-next, .lb-img.out-prev{ transform:none; }
}

/* ------------------------------------------------------------- ambient ---- */
.ambient{ position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden; }
.ambient::before{
  content:''; position:absolute; top:-340px; left:50%; transform:translateX(-50%);
  width:min(900px, 120vw); height:640px; border-radius:50%;
  background:radial-gradient(closest-side, var(--accent-soft), transparent 70%);
  filter:blur(40px);
}
.ambient::after{
  content:''; position:absolute; inset:0;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image:radial-gradient(ellipse 90% 60% at 50% 0%, #000 0%, transparent 72%);
          mask-image:radial-gradient(ellipse 90% 60% at 50% 0%, #000 0%, transparent 72%);
}
main, footer, header{ position:relative; z-index:1; }

/* -------------------------------------------------------------- header ---- */
.hdr{
  position:sticky; top:0; z-index:60;
  background:var(--glass);
  -webkit-backdrop-filter:blur(16px) saturate(1.4);
          backdrop-filter:blur(16px) saturate(1.4);
  border-bottom:1px solid var(--border);
}
/* Same width as .wrap so the logo's left edge lines up with the page content
   (hero headline) below it — owner, 2026-09-28. */
.hdr-in{
  max-width:var(--content-w); margin:0 auto; padding:0 var(--gut);
  height:var(--header-h); display:flex; align-items:center; gap:clamp(12px,2vw,28px);
}

.brand{ display:flex; align-items:center; gap:10px; text-decoration:none; flex-shrink:0; }
/* The supplied logo is dark-on-white artwork, so it needs a light chip to read
   on the dark theme. The chip lives on a wrapper, never on the <img>: padding
   on a replaced element with width:auto fights its intrinsic ratio and squashed
   the logo ~11% on every page. */
.logo-chip{
  display:inline-flex; align-items:center;
  background:#fff; border-radius:7px; padding:4px 8px;
  border:1px solid var(--plate-edge);
  transition:transform .2s var(--ease), box-shadow .2s var(--ease);
}
.logo-chip img{ height:26.4px; width:auto; object-fit:contain; }   /* 22px +20%, owner 2026-09-28 */
.brand:hover .logo-chip{ transform:translateY(-1px); box-shadow:var(--shadow-sm); }
:root:not([data-theme="dark"]) .logo-chip{
  background:transparent; border-color:transparent; padding:0;
}

.nav{ display:flex; align-items:center; gap:2px; margin-left:auto; }
.nav-item{ position:relative; }
.nav-link, .nav-trigger{
  display:inline-flex; align-items:center; gap:5px;
  height:38px; padding:0 12px; border-radius:9px;
  font-size:13.5px; font-weight:500; color:var(--text-2);
  text-decoration:none; white-space:nowrap;
  background:none; border:0; cursor:pointer; font-family:inherit;
  transition:color .18s var(--ease), background .18s var(--ease);
}
.nav-link:hover, .nav-trigger:hover{ color:var(--text); background:var(--surface-2); }
.nav-link[aria-current="page"]{ color:var(--text); }
.nav-link[aria-current="page"]::after{
  content:''; position:absolute; left:12px; right:12px; bottom:2px; height:2px;
  border-radius:2px; background:var(--accent);
}
.nav-trigger svg{ width:10px; height:10px; stroke:currentColor; stroke-width:2.6; transition:transform .22s var(--ease); }
.nav-trigger[aria-expanded="true"]{ color:var(--text); background:var(--surface-2); }
.nav-trigger[aria-expanded="true"] svg{ transform:rotate(180deg); }

.hdr-tools{ display:flex; align-items:center; gap:10px; margin-left:6px; }
.theme-btn{
  width:36px; height:36px; border-radius:9px; flex-shrink:0;
  background:var(--surface); border:1px solid var(--border);
  color:var(--text-2); cursor:pointer; display:grid; place-items:center;
  transition:color .18s, border-color .18s, background .18s, transform .18s;
}
.theme-btn:hover{ color:var(--text); border-color:var(--border-2); transform:translateY(-1px); }
.theme-btn svg{ width:16px; height:16px; stroke:currentColor; stroke-width:1.9; fill:none; }
.theme-btn .i-sun{ display:none; }
:root:not([data-theme="dark"]) .theme-btn .i-sun{ display:block; }
:root:not([data-theme="dark"]) .theme-btn .i-moon{ display:none; }

.hdr-cta{
  display:inline-flex; align-items:center; gap:7px;
  height:38px; padding:0 16px; border-radius:9px;
  font-size:13px; font-weight:600; text-decoration:none; white-space:nowrap;
  background:linear-gradient(120deg, var(--accent), var(--accent-2));
  color:#fff; box-shadow:0 2px 12px var(--accent-glow);
  transition:box-shadow .2s var(--ease), filter .2s var(--ease), transform .2s var(--ease);
}
.hdr-cta:hover{ box-shadow:0 6px 22px var(--accent-glow); filter:brightness(1.07); transform:translateY(-1px); }
.hdr-cta svg{ width:14px; height:14px; stroke:currentColor; }

.burger{
  display:none; width:38px; height:38px; margin-left:auto;
  border-radius:9px; background:var(--surface); border:1px solid var(--border);
  color:var(--text); cursor:pointer; place-items:center;
}
.burger svg{ width:18px; height:18px; stroke:currentColor; stroke-width:2; }

/* ------------------------------------------------------------ dropdowns --- */
.drop{
  position:absolute; top:calc(100% + 8px); left:50%; transform:translateX(-50%) translateY(-6px);
  min-width:238px; padding:7px;
  background:var(--glass-2);
  -webkit-backdrop-filter:blur(18px); backdrop-filter:blur(18px);
  border:1px solid var(--border); border-radius:var(--r-md);
  box-shadow:var(--shadow-xl);
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .18s var(--ease), transform .18s var(--ease-out), visibility .18s;
}
.nav-item[data-open="true"] .drop{
  opacity:1; visibility:visible; pointer-events:auto; transform:translateX(-50%) translateY(0);
}
.drop a{
  display:flex; flex-direction:column; gap:1px;
  padding:9px 11px; border-radius:8px;
  font-size:13.5px; font-weight:500; color:var(--text-2); text-decoration:none;
  transition:color .16s, background .16s;
}
.drop a:hover{ color:var(--text); background:var(--surface-2); }
.drop a small{ font-size:11.5px; color:var(--text-3); font-weight:400; line-height:1.4; }
.drop a:hover small{ color:var(--text-2); }

/* --------------------------------------------------- products mega panel ---
   Opaque on purpose. The panel used to be --glass-2 + blur, so page copy read
   through it and every row looked provisional. It is a solid --surface sheet
   spanning the header's full width, with its contents held to the site
   content column so the rows do not drift into a 1440px void.              */
.mega{
  position:absolute; left:0; right:0; top:100%;
  background:var(--surface);
  border-top:1px solid var(--border);
  border-bottom:1px solid var(--border);
  box-shadow:var(--shadow-xl);
  opacity:0; visibility:hidden; transform:translateY(-6px);
  transition:opacity .16s var(--ease), transform .16s var(--ease-out), visibility .16s;
}
.mega[data-open="true"]{ opacity:1; visibility:visible; transform:translateY(0); }
.mega-in{
  max-width:var(--content-w); margin:0 auto; padding:22px var(--gut) 24px;
  display:grid; grid-template-columns:1.35fr 1fr .9fr; gap:clamp(18px,2vw,30px);
  align-items:start;
}
.mega-col > h3{
  font-size:10.5px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-3); font-family:var(--font-mono);
  display:flex; align-items:center; gap:9px; margin-bottom:11px;
}
.mega-col > h3::after{          /* accent rule that runs out to the column edge */
  content:''; flex:1; height:1px; border-radius:1px;
  background:linear-gradient(90deg, var(--accent-line), transparent);
}
.mega-list{ display:grid; grid-template-columns:1fr; gap:2px; list-style:none; margin:0; padding:0; }
.mega-list.two{ grid-template-columns:1fr 1fr; }

/* one row = thumbnail chip + name + mono meta line + hover chevron */
.mega-row{
  display:grid; grid-template-columns:44px minmax(0,1fr) 14px;
  align-items:center; gap:11px; min-height:58px;
  padding:6px 8px 6px 6px; border-radius:10px;
  text-decoration:none; color:inherit;
  transition:background .16s var(--ease);
}
.mega-row:hover{ background:var(--surface-2); }
.mega-row:focus-visible{
  outline:2px solid var(--accent-line); outline-offset:1px; background:var(--surface-2);
}
.mega-thumb{
  position:relative; width:44px; height:44px; flex-shrink:0;
  border-radius:9px; overflow:hidden;
  background:var(--stage); border:1px solid var(--border);
  transition:border-color .16s var(--ease);
}
.mega-row:hover .mega-thumb,
.mega-row:focus-visible .mega-thumb{ border-color:var(--accent-line); }
.mega-thumb img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:contain; object-position:center; padding:6px;
}
.mega-rt{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.mega-rn{
  font-size:14px; font-weight:600; line-height:1.3; color:var(--text-2);
  transition:color .16s var(--ease);
  /* names run to 38 characters ("Obnoxious Gas & Vacuum Services Valves"); a
     single nowrap line clipped four of the ten. Two lines, then ellipsis. */
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
  overflow:hidden;
}
.mega-row:hover .mega-rn,
.mega-row:focus-visible .mega-rn{ color:var(--text); }
.mega-rm{
  font-family:var(--font-mono); font-size:10.5px; font-weight:400;
  letter-spacing:.02em; color:var(--text-3); line-height:1.4;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.mega-go{ display:flex; align-items:center; justify-content:flex-end; }
.mega-go svg{
  width:13px; height:13px; stroke:var(--accent-text); fill:none; stroke-width:2.2;
  opacity:0; transform:translateX(-3px);
  transition:opacity .16s var(--ease), transform .16s var(--ease);
}
.mega-row:hover .mega-go svg,
.mega-row:focus-visible .mega-go svg{ opacity:1; transform:translateX(0); }

/* featured column */
.mega-card{
  background:var(--surface-2); border:1px solid var(--border);
  border-radius:var(--r-md); padding:15px 16px 16px;
}
.mega-card p{ font-size:12.5px; line-height:1.55; color:var(--text-2); margin:0 0 13px; }
.mega-card .btn-sm{ width:100%; }
.btn-sm{ min-height:38px; padding:0 15px; font-size:12.5px; border-radius:9px; }
.btn-sm svg{ width:13px; height:13px; }
.mega-quiet{
  margin-top:13px; padding-top:12px; border-top:1px solid var(--border);
  display:flex; flex-direction:column; gap:2px;
}
.mega-quiet a{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:6px 8px; margin:0 -8px; border-radius:8px;
  font-size:12.5px; font-weight:500; color:var(--text-2); text-decoration:none;
  transition:color .16s var(--ease), background .16s var(--ease);
}
.mega-quiet a:hover{ color:var(--text); background:var(--surface-3); }
.mega-quiet a:focus-visible{ outline:2px solid var(--accent-line); outline-offset:1px; }
.mega-quiet svg{
  width:12px; height:12px; stroke:var(--accent-text); fill:none; stroke-width:2.2;
  flex-shrink:0; opacity:.55; transition:opacity .16s var(--ease), transform .16s var(--ease);
}
.mega-quiet a:hover svg{ opacity:1; transform:translateX(2px); }

/* between the mobile breakpoint and 1100px the third column has no room: the
   featured card drops under the two lists rather than squeezing all three. */
@media (max-width:1099px){
  .mega-in{ grid-template-columns:1.3fr 1fr; }
  .mega-feat{ grid-column:1/-1; }
  .mega-card{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
  .mega-card p{ flex:1 1 320px; margin:0; }
  .mega-card .btn-sm{ width:auto; }
  .mega-quiet{
    margin:0; padding:0; border:0; flex-direction:row; gap:4px;
  }
}
@media (prefers-reduced-motion: reduce){
  .mega{ transition:opacity .01ms, visibility .01ms; transform:none; }
  .mega[data-open="true"]{ transform:none; }
  .mega-go svg, .mega-quiet svg{ transition:opacity .01ms; }
}

/* ---------------------------------------------------------- mobile nav ---- */
.mnav{
  position:fixed; inset:var(--header-h) 0 0; z-index:55;
  background:var(--bg-2); overflow-y:auto;
  padding:16px var(--gut) 64px;
  transform:translateX(100%); visibility:hidden;
  transition:transform .3s var(--ease), visibility .3s;
  overscroll-behavior:contain;
}
.mnav[data-open="true"]{ transform:translateX(0); visibility:visible; }
.mnav h3{
  font-size:10.5px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-3); font-family:var(--font-mono); margin:22px 0 6px;
}
.mnav h3:first-child{ margin-top:6px; }
.mnav a{
  display:block; padding:12px; border-radius:9px; min-height:44px;
  font-size:15px; font-weight:500; color:var(--text-2); text-decoration:none;
}
.mnav a:hover, .mnav a:focus-visible{ background:var(--surface-2); color:var(--text); }
.mnav details > summary{
  display:flex; align-items:center; justify-content:space-between;
  padding:12px; border-radius:9px; min-height:44px; cursor:pointer;
  font-size:15px; font-weight:500; color:var(--text-2); list-style:none;
}
.mnav details > summary::-webkit-details-marker{ display:none; }
.mnav details > summary::after{
  content:''; width:7px; height:7px; border:solid var(--text-3);
  border-width:0 1.8px 1.8px 0; transform:rotate(45deg) translateY(-2px);
  transition:transform .2s;
}
.mnav details[open] > summary{ color:var(--text); }
.mnav details[open] > summary::after{ transform:rotate(-135deg); }
.mnav details a{ padding-left:22px; font-size:14px; color:var(--text-3); min-height:40px; }
.mnav-cta{ margin-top:26px; display:grid; gap:10px; }

/* ------------------------------------------------------------ sections ---- */
.sec{ padding:clamp(48px, 7vw, 84px) 0; }
.sec-sm{ padding:clamp(36px, 5vw, 56px) 0; }
.eyebrow{
  display:inline-flex; align-items:center; gap:7px;
  font-size:11px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--accent-text); font-family:var(--font-mono); margin-bottom:12px;
}
.eyebrow::before{ content:''; width:20px; height:1.5px; background:var(--accent); border-radius:2px; }
.sec-head{ max-width:66ch; margin-bottom:clamp(26px,3.5vw,38px); }
.sec-head h2{
  font-family:var(--font-disp); font-size:var(--fs-h2); font-weight:700;
  letter-spacing:-.022em; line-height:1.18; margin-bottom:10px; text-wrap:balance;
}
.sec-head p{ color:var(--text-2); font-size:var(--fs-lead); text-wrap:pretty; }

/* ---------------------------------------------------------------- hero ---- */
.hero{ padding:clamp(44px,6vw,80px) 0 clamp(40px,5vw,64px); }
.hero-grid{
  display:grid; grid-template-columns:1.05fr .95fr;
  gap:clamp(32px,5vw,60px); align-items:center;
}
.hero-badge{
  display:inline-flex; align-items:center; gap:8px;
  padding:6px 14px; border-radius:99px;
  background:var(--accent-soft); border:1px solid var(--accent-line);
  font-size:12.5px; font-weight:500; color:var(--text-2); margin-bottom:20px;
}
.pulse{
  width:7px; height:7px; border-radius:50%; background:var(--ok);
  box-shadow:0 0 0 0 rgba(16,185,129,.6); animation:pulse 2.4s infinite;
}
@keyframes pulse{
  0%{ box-shadow:0 0 0 0 rgba(16,185,129,.5); }
  70%{ box-shadow:0 0 0 8px rgba(16,185,129,0); }
  100%{ box-shadow:0 0 0 0 rgba(16,185,129,0); }
}
.hero h1{
  font-family:var(--font-disp); font-size:var(--fs-h1); font-weight:700;
  letter-spacing:-.032em; line-height:1.06; margin-bottom:18px; text-wrap:balance;
}
.grad{
  background:linear-gradient(100deg, var(--grad-1) 8%, var(--grad-2) 55%, var(--grad-3) 96%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.hero-lead{ color:var(--text-2); font-size:var(--fs-lead); max-width:52ch; margin-bottom:28px; text-wrap:pretty; }
.hero-actions{ display:flex; gap:12px; flex-wrap:wrap; margin-bottom:32px; }

.hero-art{ position:relative; border-radius:var(--r-xl); }
.hero-art .plate{
  aspect-ratio:1/1; background:var(--stage);
  border:1px solid var(--border); border-radius:var(--r-xl);
  position:relative; overflow:hidden;
}
.hero-art .plate::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:var(--stage-floor), linear-gradient(150deg, transparent 58%, var(--accent-soft));
}
.hero-art .plate img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:contain; padding:clamp(22px,4vw,44px);
  z-index:1;
}

.stats{
  display:grid; grid-template-columns:repeat(4,1fr);
  border:1px solid var(--border); border-radius:var(--r-lg);
  background:var(--surface); overflow:hidden;
}
.stat{ padding:16px 12px; }
.stat + .stat{ border-left:1px solid var(--border); }
.stat b{
  display:block; font-family:var(--font-disp); font-size:clamp(19px,2vw,24px);
  font-weight:700; letter-spacing:-.02em; line-height:1.2;
}
.stat span{
  font-size:10.5px; color:var(--text-3); font-weight:500;
  letter-spacing:.05em; text-transform:uppercase;
}

/* -------------------------------------------------------------- buttons --- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  min-height:44px; padding:0 20px;
  border-radius:10px; border:1px solid transparent;
  font-size:13.5px; font-weight:600; letter-spacing:-.005em;
  text-decoration:none; cursor:pointer; white-space:nowrap; font-family:inherit;
  transition:background .18s var(--ease), border-color .18s var(--ease),
             color .18s var(--ease), box-shadow .2s var(--ease),
             transform .18s var(--ease), filter .18s var(--ease);
}
.btn:active{ transform:translateY(1px); }
.btn svg{ width:15px; height:15px; stroke:currentColor; }
.btn-grad{
  background:linear-gradient(120deg, var(--accent), var(--accent-2)); color:#fff;
  box-shadow:0 2px 12px var(--accent-glow);
}
.btn-grad:hover{ box-shadow:0 8px 26px var(--accent-glow); filter:brightness(1.07); transform:translateY(-2px); }
.btn-outline{ background:transparent; color:var(--text); border-color:var(--border-2); }
.btn-outline:hover{ background:var(--surface-2); border-color:var(--text-3); transform:translateY(-2px); }
.btn-soft{ background:var(--accent-soft); color:var(--accent-text); border:1px solid var(--accent-line); box-shadow:none; }
.btn-soft:hover{ background:var(--accent-line); color:var(--text); transform:none; }
.btn-ghost{ background:transparent; color:var(--text-2); }
.btn-ghost:hover{ background:var(--surface-2); color:var(--text); }

/* ---------------------------------------------------------------- cards --- */
.grid{ display:grid; gap:clamp(14px,1.6vw,20px); }
.g2{ grid-template-columns:repeat(2,1fr); }
.g3{ grid-template-columns:repeat(3,1fr); }
.g4{ grid-template-columns:repeat(4,1fr); }
.gauto{ grid-template-columns:repeat(auto-fill,minmax(min(272px,100%),1fr)); }

.card{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:clamp(18px,2vw,22px);
  transition:border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.card:hover{ border-color:var(--border-2); }
.card-lift:hover{ transform:translateY(-4px); box-shadow:var(--shadow-lg); }
.card h3{
  font-family:var(--font-disp); font-size:var(--fs-h3); font-weight:600;
  letter-spacing:-.01em; margin-bottom:7px; line-height:1.35;
}
.card p{ font-size:13.5px; color:var(--text-2); }

.icon-tile{
  width:42px; height:42px; border-radius:11px;
  background:var(--accent-soft); border:1px solid var(--accent-line);
  display:grid; place-items:center; margin-bottom:16px;
}
.icon-tile svg{ width:22px; height:22px; stroke:var(--accent-text); fill:none; stroke-width:1.7; shape-rendering:geometricPrecision; }
.card-link{
  display:inline-flex; align-items:center; gap:5px; margin-top:14px;
  font-size:13px; font-weight:600; color:var(--accent-text); text-decoration:none;
}
.card-link svg{ width:13px; height:13px; stroke:currentColor; transition:transform .2s var(--ease); }
.card-link:hover svg{ transform:translateX(3px); }

/* mouse-follow spotlight; JS sets --mx / --my */
.card-spot{ position:relative; overflow:hidden; }
.card-spot::before{
  content:''; position:absolute; inset:0; border-radius:inherit; pointer-events:none; z-index:1;
  background:radial-gradient(280px circle at var(--mx,50%) var(--my,50%), var(--accent-soft), transparent 65%);
  opacity:0; transition:opacity .25s;
}
.card-spot:hover::before{ opacity:1; }

/* ---- product card --------------------------------------------------------
   The image plate is a fixed-ratio box and the <img> is absolutely positioned
   inside it with object-fit:contain. Absolute positioning matters: a plain
   `max-height:100%` on a grid child inside an aspect-ratio box does NOT
   constrain the image (percentage max-height has no definite basis to resolve
   against there), so tall art overflowed and got clipped to its blank middle.
   Source art is whitespace-trimmed by _build/trim_images.py, so `contain`
   fills the plate properly instead of floating in baked-in margins.        */
.pcard{
  display:flex; flex-direction:column; overflow:hidden;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  text-decoration:none;
  transition:border-color .2s var(--ease), transform .25s var(--ease), box-shadow .25s var(--ease);
}
.pcard:hover{ border-color:var(--border-2); transform:translateY(-4px); box-shadow:var(--shadow-lg); }
/* square stage: 21 of the 32 valve renders are portrait (median 0.77 w/h), so a
   4/3 landscape plate shrank the part to fit its height and left dead air on
   both sides. 1/1 gives portrait art the most room while keeping every card in
   the grid exactly the same height. */
.pcard-img{
  position:relative; aspect-ratio:1/1; flex-shrink:0;
  background:var(--stage); border-bottom:1px solid var(--border);
  overflow:hidden;
}
.pcard-img::after{           /* contact shadow — grounds the part on the stage */
  content:''; position:absolute; inset:0; background:var(--stage-floor);
  pointer-events:none;
}
.pcard-img img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:contain; object-position:center;
  padding:12% 14%;
  transition:transform .45s var(--ease-out);
  z-index:1;
}
.pcard:hover .pcard-img img{ transform:scale(1.045); }
.pcard-body{ padding:16px 18px 18px; flex:1; display:flex; flex-direction:column; gap:7px; }
.pcard-body h3{
  font-family:var(--font-disp); font-size:14.5px; font-weight:600;
  letter-spacing:-.01em; line-height:1.35; margin:0;
}
.pcard-body p{ font-size:13px; color:var(--text-2); line-height:1.6; margin:0; }
.pcard-meta{ margin-top:auto; padding-top:10px; display:flex; flex-wrap:wrap; gap:6px; align-items:flex-start; }
.chip{
  font-size:10.5px; font-family:var(--font-mono); color:var(--text-3);
  padding:3px 8px; border-radius:99px; border:1px solid var(--border);
  white-space:nowrap; line-height:1.5;
}
.chip-a{ color:var(--accent-text); border-color:var(--accent-line); background:var(--accent-soft); }
/* long size/class ranges must wrap inside the card, not clip at its edge */
.pcard-meta .chip{ white-space:normal; max-width:100%; overflow-wrap:anywhere; text-align:left; }

/* photo card (industries) — cover is right here: these are photographs and
   letterboxing them would look worse than a considered crop */
.itile{
  position:relative; overflow:hidden; border-radius:var(--r-md);
  border:1px solid var(--border); aspect-ratio:4/3; background:var(--surface-2);
}
.itile img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  transition:transform .5s var(--ease-out), filter .3s var(--ease);
  filter:saturate(.72) brightness(.76);
}
.itile:hover img{ transform:scale(1.06); filter:saturate(1) brightness(.88); }
.itile figcaption{
  position:absolute; inset:auto 0 0 0; padding:12px 14px;
  background:linear-gradient(transparent, rgba(0,0,0,.88));
  font-size:12.5px; font-weight:600; color:#fff; line-height:1.35;
}

/* ------------------------------------------------------------ spec table -- */
.spec{
  width:100%; border-collapse:collapse; font-size:13.5px;
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-lg); overflow:hidden;
}
/* width:100% is load-bearing, not cosmetic. A caption is not a table cell, so
   under table-layout:auto the browser shrink-wraps it to the widest column it
   can borrow rather than the table box. At 375px that rendered "Design &
   Testing International Standard" 123px wide inside a 339px table — 36% of the
   bar, wrapped to six lines, with the rest of the header strip left empty.
   Pinning the width makes the caption span the table at every viewport. */
.spec caption{
  width:100%; box-sizing:border-box;
  text-align:left; padding:14px 18px; font-family:var(--font-disp);
  font-size:14px; font-weight:600; color:var(--text);
  border-bottom:1px solid var(--border); background:var(--surface-2);
}
.spec th, .spec td{ padding:12px 18px; text-align:left; vertical-align:top; }
.spec th{
  width:34%; font-weight:500; color:var(--text-3); font-size:12.5px;
  border-right:1px solid var(--border);
}
.spec td{ color:var(--text); font-family:var(--font-mono); font-size:12.5px; line-height:1.7; }
.spec tr + tr th, .spec tr + tr td{ border-top:1px solid var(--border); }
.spec tbody tr{ transition:background .16s; }
.spec tbody tr:hover td, .spec tbody tr:hover th{ background:var(--surface-2); }

.tablewrap{ overflow-x:auto; border-radius:var(--r-lg); -webkit-overflow-scrolling:touch; }

.cmp{ width:100%; border-collapse:collapse; font-size:13px; min-width:720px; }
.cmp thead th{
  position:sticky; top:0; z-index:1; background:var(--surface-2);
  padding:12px 14px; text-align:left; font-size:11px; font-weight:600;
  letter-spacing:.08em; text-transform:uppercase; color:var(--text-3);
  border-bottom:1px solid var(--border-2); white-space:nowrap;
}
.cmp td{
  padding:12px 14px; border-bottom:1px solid var(--border);
  color:var(--text-2); font-family:var(--font-mono); font-size:12px; vertical-align:top;
}
.cmp td:first-child{ font-family:var(--font-ui); font-weight:600; color:var(--text); }
.cmp td:first-child a{ color:var(--text); text-decoration:none; }
.cmp td:first-child a:hover{ color:var(--accent-text); }
.cmp tbody tr{ transition:background .16s; }
.cmp tbody tr:hover{ background:var(--surface-2); }

/* multi-line spec values: the live page prints each on its own line, so they
   are emitted as separate blocks rather than joined with an invented separator */
.spec td .ln, .cmp td .ln{ display:block; }
.spec td .ln + .ln, .cmp td .ln + .ln{ margin-top:6px; }

/* --------------------------------------------------------------- prose ---- */
.prose{ max-width:72ch; }
.prose p{ color:var(--text-2); font-size:var(--fs-body); margin-bottom:16px; text-wrap:pretty; }
.prose p:last-child{ margin-bottom:0; }
.prose h2{
  font-family:var(--font-disp); font-size:clamp(19px,2vw,22px); font-weight:700;
  letter-spacing:-.02em; margin:36px 0 14px; color:var(--text);
}
.prose h3{
  font-family:var(--font-disp); font-size:var(--fs-h3); font-weight:600;
  letter-spacing:-.01em; margin:26px 0 10px; color:var(--text);
}
.prose strong{ color:var(--text); font-weight:600; }
.prose > ul, .prose > ol{ margin:0 0 18px 20px; color:var(--text-2); font-size:var(--fs-body); }
.prose li{ margin-bottom:8px; }
.prose li::marker{ color:var(--accent-text); }

.ticks{ list-style:none; margin:0 !important; display:grid; gap:10px; }
.ticks li{ position:relative; padding-left:28px; color:var(--text-2); font-size:14.5px; }
.ticks li::before{
  content:''; position:absolute; left:0; top:.42em;
  width:16px; height:16px; border-radius:50%;
  background:var(--accent-soft); border:1px solid var(--accent-line);
}
.ticks li::after{
  content:''; position:absolute; left:5px; top:.68em;
  width:5px; height:8px; border:solid var(--accent-text); border-width:0 1.6px 1.6px 0;
  transform:rotate(45deg);
}
.nums{ list-style:none; counter-reset:n; display:grid; gap:12px; margin:0 !important; }
.nums li{ position:relative; padding-left:38px; color:var(--text-2); font-size:14.5px; counter-increment:n; }
.nums li::before{
  content:counter(n); position:absolute; left:0; top:-1px;
  width:24px; height:24px; border-radius:7px;
  background:var(--accent-soft); border:1px solid var(--accent-line);
  color:var(--accent-text); font-family:var(--font-mono); font-size:11.5px; font-weight:600;
  display:grid; place-items:center;
}

/* ---------------------------------------------------------- breadcrumbs --- */
.crumbs{ padding:18px 0 0; font-size:12.5px; color:var(--text-3); }
.crumbs ol{ list-style:none; display:flex; align-items:center; gap:7px; flex-wrap:wrap; }
.crumbs a{ color:var(--text-3); text-decoration:none; transition:color .16s; }
.crumbs a:hover{ color:var(--text-2); }
.crumbs li:not(:last-child)::after{ content:'/'; margin-left:7px; opacity:.45; }
.crumbs [aria-current]{ color:var(--text-2); }

/* ---------------------------------------------------------- page header --- */
.phead{ padding:26px 0 clamp(30px,4vw,44px); }
.phead h1{
  font-family:var(--font-disp); font-size:clamp(27px,1.4rem+2vw,42px); font-weight:700;
  letter-spacing:-.028em; line-height:1.1; margin-bottom:14px; text-wrap:balance;
}
.phead p{ color:var(--text-2); font-size:var(--fs-lead); max-width:66ch; text-wrap:pretty; }
/* Adjacent-sibling only, so the single-paragraph leads that most pages carry
   keep their exact spacing; the multi-paragraph leads on /inspections-quality-
   control/ and /trouble-shooting-for-valves/ stop reading as one wall. Matches
   the 14px .prose p rhythm used everywhere else. */
.phead p + p{ margin-top:14px; }

/* --------------------------------------------------------------- notice --- */
.notice{
  display:flex; gap:12px; align-items:flex-start;
  padding:14px 16px; border-radius:var(--r-md);
  background:color-mix(in srgb, var(--warn) 9%, transparent);
  border:1px solid color-mix(in srgb, var(--warn) 32%, transparent);
  font-size:13px; color:var(--text-2); line-height:1.6;
}
.notice svg{ width:16px; height:16px; stroke:var(--warn); fill:none; margin-top:2px; }
.notice b{ color:var(--warn); font-weight:600; }

/* -------------------------------------------------------------- figure ---- */
/* Figures use the same stage as the product cards. The media box is an
   absolutely-positioned frame: sizing the <img> directly let its width/height
   attributes pin the height, which cancelled `aspect-ratio` and cropped ~48%
   off tall valve art under object-fit:cover. */
.fig{
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-md); overflow:hidden;
  display:flex; flex-direction:column;
}
.fig-media{
  position:relative; aspect-ratio:4/3; flex-shrink:0;
  background:var(--stage); overflow:hidden;
}
.fig-media::after{
  content:''; position:absolute; inset:0; background:var(--stage-floor); pointer-events:none;
}
.fig-media img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:contain; padding:8%;
  z-index:1;
}
.fig-media img.ph{ object-fit:cover; padding:0; }   /* photographs fill the frame */
.fig figcaption{
  padding:10px 14px; font-size:12px; color:var(--text-3); line-height:1.5;
  border-top:1px solid var(--border);
}
.fig-art .fig-media{ aspect-ratio:3/4; }   /* portrait frame for portrait parts */

/* ---- gallery + lightbox ---------------------------------------------------
   The trouble-shooting shots are square sources between 200 and 1200px. Left
   to an auto-fit `.g-figs` grid they rendered ragged with mis-aligned
   captions, so each one gets an identical square frame and the image is
   `cover`-cropped inside it. The card is an <a> to the full file: with JS off
   it is a plain link, which is the whole no-JS story for this component.  */
.gal{
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px;
  align-content:start;
}
.gal-card{
  display:flex; flex-direction:column; overflow:hidden; text-decoration:none;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  box-shadow:var(--shadow-sm);
  transition:border-color .2s var(--ease), transform .25s var(--ease),
             box-shadow .25s var(--ease);
}
.gal-card:hover{
  border-color:var(--border-2); transform:translateY(-4px); box-shadow:var(--shadow-lg);
}
.gal-card:focus-visible{
  outline:2px solid var(--accent); outline-offset:2px;
  border-color:var(--accent-line);
}
/* square frame; the <img> is absolutely positioned so its width/height
   attributes cannot pin the height and cancel `aspect-ratio` (see .fig-media) */
.gal-media{
  position:relative; display:block; aspect-ratio:1/1; flex-shrink:0;
  background:var(--stage); overflow:hidden; border-bottom:1px solid var(--border);
}
.gal-media::after{
  content:''; position:absolute; inset:0; background:var(--stage-floor);
  pointer-events:none; z-index:2;
}
.gal-media img,
.gal-media img.ph{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; padding:0; z-index:1;
  transition:transform .25s var(--ease);
}
.gal-card:hover .gal-media img{ transform:scale(1.04); }
/* flex:1 so a two-line caption does not make its card taller than the one
   beside it — the strip absorbs the difference instead */
.gal-cap{
  display:flex; align-items:baseline; gap:10px; justify-content:space-between;
  flex:1; padding:10px 13px; font-size:12px; line-height:1.5; color:var(--text-3);
}
.gal-cap-t{ min-width:0; }
.gal-num{
  flex-shrink:0; font-family:var(--font-mono); font-size:10.5px;
  letter-spacing:.04em; color:var(--text-3); opacity:.8;
}
@media (max-width:520px){ .gal{ gap:12px; } }

/* ---- lightbox (injected by site.js; never present in the served HTML) ---- */
.lb{
  border:0; padding:0; background:transparent; overflow:visible;
  max-width:100vw; max-height:100vh; width:100%; height:100%;
  color:var(--text);
}
.lb::backdrop{ background:rgba(0,0,0,.82); }
@supports (backdrop-filter:blur(8px)){
  .lb::backdrop{ background:rgba(0,0,0,.72); backdrop-filter:blur(8px); }
}
.lb-inner{
  position:absolute; inset:0; display:flex; flex-direction:column;
  align-items:center; justify-content:center; padding:clamp(16px,4vw,40px);
}
/* the stage is only as large as the image, so the scrim click target is
   everything around it */
.lb-stage{
  position:relative; display:grid; place-items:center; flex-shrink:0;
  max-width:min(90vw,1400px); max-height:78vh; pointer-events:none;
}
.lb-img{
  grid-area:1/1; max-width:100%; max-height:78vh;
  width:auto; height:auto; object-fit:contain;
  border-radius:var(--r-md); box-shadow:var(--shadow-xl);
  background:var(--surface); pointer-events:auto;
}
/* two stacked layers swapped alternately, so the outgoing frame visibly
   slides under the incoming one instead of cross-dissolving in place */
.lb-img.is-out,
.lb-img.is-in{ transition:transform .32s var(--ease-out), opacity .32s var(--ease-out); }
.lb-img.pre-next{ transform:translateX(40px); opacity:0; }
.lb-img.pre-prev{ transform:translateX(-40px); opacity:0; }
.lb-img.out-next{ transform:translateX(-40px); opacity:0; }
.lb-img.out-prev{ transform:translateX(40px); opacity:0; }
.lb-img.hide{ opacity:0; visibility:hidden; }
.lb-meta{
  margin-top:18px; text-align:center; max-width:min(90vw,720px);
  display:flex; flex-direction:column; gap:5px; align-items:center;
  flex-shrink:0;
}
/* The scrim is dark in BOTH themes, so this text cannot use --text: in light
   mode that token is near-black and the caption disappeared into the scrim.
   Fixed light values are correct here precisely because the backdrop is
   theme-independent. */
.lb-cap{ font-size:13.5px; color:#FAFAFA; line-height:1.5; }
.lb-count{
  font-family:var(--font-mono); font-size:11px; letter-spacing:.06em;
  color:rgba(250,250,250,.72);
}
.lb-btn{
  position:absolute; z-index:3; width:44px; height:44px; border-radius:999px;
  display:grid; place-items:center; cursor:pointer;
  border:1px solid rgba(255,255,255,.22); background:rgba(20,20,24,.62);
  color:#FAFAFA;
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  box-shadow:0 4px 16px rgba(0,0,0,.4);
  transition:background .2s var(--ease), border-color .2s var(--ease),
             transform .2s var(--ease);
}
.lb-btn:hover{
  background:rgba(38,38,46,.82); border-color:rgba(255,255,255,.42);
  transform:scale(1.06);
}
.lb-btn:focus-visible{ outline:2px solid #FFF; outline-offset:2px; }
.lb-btn svg{ width:20px; height:20px; fill:none; stroke:currentColor; }
.lb-prev{ left:clamp(8px,2vw,26px); top:50%; margin-top:-22px; }
.lb-next{ right:clamp(8px,2vw,26px); top:50%; margin-top:-22px; }
.lb-prev svg{ transform:rotate(180deg); }
.lb-close{ right:clamp(8px,2vw,26px); top:clamp(8px,2vw,26px); }
.lb-close svg{ stroke-width:2; }
.lb[data-single="1"] .lb-prev,
.lb[data-single="1"] .lb-next,
.lb[data-single="1"] .lb-count{ display:none; }
html.lb-open{ overflow:hidden; }

/* ------------------------------------------------------------ timeline ---- */
.tl{ position:relative; padding-left:30px; }
.tl::before{
  content:''; position:absolute; left:7px; top:6px; bottom:6px; width:1px;
  background:linear-gradient(var(--accent), var(--accent-2), transparent);
}
.tl-item{ position:relative; padding-bottom:26px; }
.tl-item:last-child{ padding-bottom:0; }
.tl-item::before{
  content:''; position:absolute; left:-27px; top:6px;
  width:9px; height:9px; border-radius:50%;
  background:var(--accent); box-shadow:0 0 0 3px var(--accent-soft);
}
.tl-item b{
  display:block; font-family:var(--font-mono); font-size:12px; color:var(--accent-text);
  font-weight:600; margin-bottom:3px;
}
.tl-item p{ color:var(--text-2); font-size:14px; }

/* ---------------------------------------------------------------- FAQ ----- */
.faq{ border:1px solid var(--border); border-radius:var(--r-lg); overflow:hidden; background:var(--surface); }
.faq details + details{ border-top:1px solid var(--border); }
.faq summary{
  padding:16px 20px; cursor:pointer; font-weight:600; font-size:14.5px;
  display:flex; align-items:center; justify-content:space-between; gap:14px;
  list-style:none; transition:background .16s; min-height:44px;
}
.faq summary::-webkit-details-marker{ display:none; }
.faq summary:hover{ background:var(--surface-2); }
.faq summary::after{
  content:''; width:8px; height:8px; flex-shrink:0;
  border:solid var(--text-3); border-width:0 1.6px 1.6px 0;
  transform:rotate(45deg) translateY(-2px); transition:transform .2s var(--ease);
}
.faq details[open] summary::after{ transform:rotate(-135deg) translateY(0); }
.faq-body{ padding:0 20px 18px; color:var(--text-2); font-size:14px; line-height:1.7; }

/* --------------------------------------------------------------- CTA ------ */
.cta{
  border-radius:var(--r-xl); padding:clamp(32px,5vw,52px) clamp(22px,4vw,42px);
  text-align:center; position:relative; overflow:hidden;
  background:
    radial-gradient(600px 300px at 20% 0%, var(--accent-soft), transparent 62%),
    radial-gradient(500px 320px at 88% 100%, color-mix(in srgb, var(--accent-2) 14%, transparent), transparent 60%),
    var(--surface);
  border:1px solid var(--border);
}
.cta h2{
  font-family:var(--font-disp); font-size:var(--fs-h2); font-weight:700;
  letter-spacing:-.02em; line-height:1.2; margin:0 auto 12px; max-width:24ch;
  text-wrap:balance;
}
.cta p{ color:var(--text-2); font-size:var(--fs-body); max-width:56ch; margin:0 auto 24px; text-wrap:pretty; }
.cta-actions{ display:flex; gap:12px; justify-content:center; flex-wrap:wrap; }

/* ------------------------------------------------------------- contact ---- */
.cbox{ background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:22px; }
.cbox h3{ font-family:var(--font-disp); font-size:15px; font-weight:600; margin-bottom:14px; }
.crow{ display:flex; gap:12px; align-items:flex-start; padding:11px 0; }
.crow + .crow{ border-top:1px solid var(--border); }
.crow svg{ width:16px; height:16px; stroke:var(--accent-text); fill:none; margin-top:3px; }
.crow b{
  display:block; font-size:11px; color:var(--text-3); font-weight:500;
  letter-spacing:.06em; text-transform:uppercase; margin-bottom:2px;
}
.crow a, .crow span{ color:var(--text-2); font-size:14px; text-decoration:none; line-height:1.55; }
.crow a:hover{ color:var(--accent-text); }

.embed{
  border:1px solid var(--border); border-radius:var(--r-lg); overflow:hidden;
  background:var(--surface); min-height:520px;
}
.embed iframe{ width:100%; height:1000px; border:0; display:block; }
.embed-16x9{ position:relative; aspect-ratio:16/9; min-height:0; }
.embed-16x9 iframe{ position:absolute; inset:0; width:100%; height:100%; }

/* -------------------------------------------------------------- footer ----
   Four bands inside one .wrap: CTA -> five-column link grid -> trust chips ->
   legal bar. The grid is 1.6fr + four equal columns; the brand column earns
   that 1.6fr by carrying the contact block and socials, so no column bottoms
   out far above its neighbours. Everything is token-driven, so both themes
   come out of the same rules.                                             */
.ftr{
  border-top:1px solid var(--border); background:var(--bg-2);
  margin-top:40px; padding-top:clamp(38px,5vw,56px);
}

/* --- main link grid --- */
.ftr-grid{
  display:grid; grid-template-columns:1.62fr 1fr 1.42fr .9fr 1.02fr;
  gap:clamp(24px,2.6vw,34px); align-items:start;
  padding-bottom:clamp(26px,3vw,34px);
}
/* The four link lists hold 6/5/4/5 rows and the rare-application names wrap to
   two lines however the column is sized, so the columns have no common natural
   height. Rather than spacing a short list out to fake alignment (which would
   put its rows out of step with its neighbours), the columns keep one uniform
   row rhythm and simply run out of rows — the trust strip's border directly
   below closes the block off, so a short column reads as finished, not empty.
   `align-items:start` keeps every head on the same top line. */
.ftr-col{ min-width:0; }
.ftr h3{
  font-size:10.5px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-3); font-family:var(--font-mono);
  display:flex; align-items:center; gap:9px; margin-bottom:13px;
}
.ftr h3::after{            /* same accent rule the mega-menu heads use */
  content:''; flex:1; height:1px; border-radius:1px;
  background:linear-gradient(90deg, var(--accent-line), transparent);
}
.ftr-col ul{ list-style:none; display:grid; gap:9px; margin:0; padding:0; }
.ftr-col a{
  display:inline-block; color:var(--text-2); text-decoration:none;
  font-size:13.5px; line-height:1.45;
  border-bottom:1px solid transparent;
  transition:color .16s var(--ease), transform .16s var(--ease), border-color .16s var(--ease);
}
.ftr-col a:hover{ color:var(--text); transform:translateX(2px); border-bottom-color:var(--border-2); }
.ftr-col a:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:3px; }
.ftr-all{
  display:inline-flex !important; align-items:center; gap:6px;
  color:var(--accent-text) !important; font-weight:600;
}
.ftr-all svg{ width:12px; height:12px; stroke:currentColor; fill:none; }
.ftr-all:hover{ border-bottom-color:var(--accent-line) !important; }

/* --- brand column --- */
.ftr-brand{ min-width:0; }
.ftr-logo{ display:inline-block; text-decoration:none; }
.ftr-logo img{
  height:30px; width:auto; background:#fff; border-radius:6px;
  padding:3px 7px; border:1px solid var(--plate-edge);
}
.ftr-logo:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:8px; }
.ftr-tag{
  color:var(--text-2); font-size:13.5px; line-height:1.6;
  margin:14px 0 16px; max-width:38ch; text-wrap:pretty;
}
.ftr-contact{ list-style:none; display:grid; gap:10px; margin:0; padding:0; }
.ftr-contact li{
  display:grid; grid-template-columns:16px minmax(0,1fr); gap:10px;
  align-items:start; font-size:13px; color:var(--text-2); line-height:1.5;
}
.ftr-contact svg{ width:15px; height:15px; stroke:var(--accent-text); margin-top:2px; }
.ftr-contact a{
  color:var(--text-2); text-decoration:none;
  border-bottom:1px solid transparent; transition:color .16s var(--ease), border-color .16s var(--ease);
  overflow-wrap:anywhere;
}
.ftr-contact a:hover{ color:var(--text); border-bottom-color:var(--border-2); }
.ftr-contact a:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:3px; }
/* Each span is an authored address line. Letting them re-wrap produced a
   four-line ragged block in a three-line box, so they hold their own line and
   the rare long one shrinks a touch instead. */
.ftr-addr{ display:grid; gap:1px; }
.ftr-addr span{ white-space:nowrap; }
@media (max-width:1439px){ .ftr-addr span{ white-space:normal; } }

.socials{ display:flex; gap:8px; flex-wrap:wrap; flex-shrink:0; }
.socials a{
  width:40px; height:40px; border-radius:10px;
  background:var(--surface); border:1px solid var(--border);
  display:grid; place-items:center;
  transition:border-color .18s var(--ease), background .18s var(--ease), transform .18s var(--ease);
}
.socials a:hover{ border-color:var(--accent); background:var(--accent-soft); transform:translateY(-2px); }
.socials a:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.socials svg{ width:16px; height:16px; fill:var(--text-2); transition:fill .18s var(--ease); }
.socials a:hover svg{ fill:var(--accent); }

/* --- trust strip --- */
.ftr-strip{
  padding:16px 0;
  border-top:1px solid var(--border); border-bottom:1px solid var(--border);
  display:flex; align-items:center; justify-content:space-between;
  gap:16px 24px; flex-wrap:wrap;
}
.ftr-trust{
  list-style:none; margin:0; padding:0;
  display:flex; flex-wrap:wrap; gap:8px 10px; align-items:center;
  min-width:0;
}
.ftr-chip{
  display:inline-flex; align-items:center; gap:6px;
  font-size:10.5px; font-family:var(--font-mono); color:var(--text-3);
  padding:4px 10px; border-radius:99px; border:1px solid var(--border);
  background:var(--surface); line-height:1.5; white-space:nowrap;
}
.ftr-chip svg{ width:11px; height:11px; stroke:var(--ok); fill:none; }

/* --- legal bar --- */
.ftr-bot{
  padding:18px 0 24px;
  display:flex; align-items:center; justify-content:space-between;
  gap:12px 20px; flex-wrap:wrap;
  font-family:var(--font-mono); font-size:11.5px; color:var(--text-3);
}
.ftr-place{ text-align:center; }
.ftr-bot-a{ display:flex; align-items:center; gap:16px; }
.ftr-bot-a a{
  color:var(--text-3); text-decoration:none;
  border-bottom:1px solid transparent; transition:color .16s var(--ease), border-color .16s var(--ease);
}
.ftr-bot-a a:hover{ color:var(--text); border-bottom-color:var(--border-2); }
.ftr-bot-a a:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:3px; }
.ftr-top{ display:inline-flex; align-items:center; gap:6px; }
.ftr-top svg{
  width:12px; height:12px; stroke:currentColor; fill:none;
  transform:rotate(180deg); transition:transform .18s var(--ease);
}
.ftr-top:hover svg{ transform:rotate(180deg) translateY(-2px); }

/* --- footer responsive ---
   1100 is where five columns stop fitting: the brand goes full width and the
   four link columns become a 2x2, which keeps their heights matched rather
   than leaving a tall brand column beside four short ones. */
@media (max-width:1099px){
  .ftr-grid{ grid-template-columns:repeat(4,1fr); gap:32px 28px; }
  .ftr-brand{ grid-column:1/-1; }
  .ftr-tag{ max-width:60ch; }
  .ftr-brand .ftr-contact{
    display:flex; flex-wrap:wrap; gap:10px 28px; margin-bottom:0;
  }
}
@media (max-width:899px){
  .ftr-grid{ grid-template-columns:1fr 1fr; gap:28px; }
}
@media (max-width:519px){
  .ftr-grid{ grid-template-columns:1fr; gap:24px; }
  .ftr-bot{ flex-direction:column; align-items:flex-start; gap:10px; }
  .ftr-place{ text-align:left; }
}
@media (prefers-reduced-motion: reduce){
  .ftr-col a:hover{ transform:none; }
  .socials a:hover{ transform:none; }
  .ftr-top:hover svg{ transform:rotate(180deg); }
}

/* ----------------------------------------------------------- responsive --- */
/* ultrawide: widen the shell, don't stretch the text */
@media (min-width:1600px){
  :root{ --content-w:1320px; --wide-w:1560px; }
}
@media (min-width:1921px){
  :root{ --content-w:1400px; --wide-w:1680px; }
}

@media (max-width:1180px){
  .nav-link, .nav-trigger{ padding:0 9px; font-size:13px; }
  .g4{ grid-template-columns:repeat(3,1fr); }
}
@media (max-width:1024px){
  .nav, .hdr-cta{ display:none; }
  .hdr-tools{ margin-left:auto; }
  .burger{ display:grid; margin-left:0; }
  .mega{ display:none; }
  .hero-grid{ grid-template-columns:1fr; gap:32px; }
  .hero-art{ order:-1; max-width:520px; }
  .g3{ grid-template-columns:repeat(2,1fr); }
}
@media (max-width:860px){
  .g4{ grid-template-columns:repeat(2,1fr); }
  .g2{ grid-template-columns:1fr; }
}
@media (max-width:680px){
  .stats{ grid-template-columns:repeat(2,1fr); }
  .stat:nth-child(3){ border-left:0; }
  .stat:nth-child(n+3){ border-top:1px solid var(--border); }
  .g3{ grid-template-columns:1fr; }
  .hero-actions .btn, .cta-actions .btn{ flex:1 1 100%; }
}
@media (max-width:560px){
  .g4{ grid-template-columns:1fr 1fr; }
  /* caption is in this list deliberately: with .spec switched to display:block
     a table-caption box still shrink-wraps to its own content, which is what
     rendered the caption 123px wide inside a 339px table and wrapped it to six
     lines. As a block it fills the table box like every other row here. */
  .spec, .spec caption, .spec tbody, .spec tr, .spec th, .spec td{ display:block; width:100%; }
  .spec th{ border-right:0; padding-bottom:2px; width:100%; }
  .spec td{ padding-top:2px; }
  .spec tr + tr th{ border-top:1px solid var(--border); }
  .spec tr + tr td{ border-top:0; }
  .embed iframe{ height:1200px; }
}
@media (max-width:400px){
  .g4{ grid-template-columns:1fr; }
}

/* touch devices: no hover-lift (it sticks after tap) */
@media (hover:none){
  .pcard:hover, .card-lift:hover{ transform:none; }
  .pcard:hover .pcard-img img{ transform:none; }
  .card-spot::before{ display:none; }
}

/* --------------------------------------------------------------- print ---- */
/* Spec sheets get printed and read on plant terminals — force light on white
   and drop all chrome regardless of the on-screen theme. */
@media print{
  :root, :root[data-theme="dark"], :root[data-theme="light"]{
    --bg:#fff; --bg-2:#fff; --surface:#fff; --surface-2:#fff; --surface-3:#fff;
    --text:#000; --text-2:#333; --text-3:#666;
    --border:#ccc; --border-2:#999; --accent:#000; --accent-soft:transparent;
    --plate:#fff; --plate-edge:#ccc;
    color-scheme: light;
  }
  body{ background:#fff; color:#000; font-size:11pt; }
  .ambient, .hdr, .mnav, .mega, .drop, .ftr, .cta, .skip,
  .hero-actions, .card-link, .theme-btn, .burger{ display:none !important; }
  main{ padding:0 !important; }
  .wrap, .wrap-wide{ max-width:100%; padding:0; }
  a{ text-decoration:none; color:#000; }
  a[href^="http"]::after{ content:" (" attr(href) ")"; font-size:8pt; color:#666; }
  .spec, .card, .fig, .gal-card{ border:1px solid #999; break-inside:avoid; }
  .lb, dialog.lb{ display:none !important; }
  .gal{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
  .gal-card{ box-shadow:none; }
  .gal-media{ aspect-ratio:auto; background:none; border-bottom:1px solid #ccc; }
  .gal-media::after{ display:none; }
  .gal-media img{ position:static; width:100%; height:auto; object-fit:contain; }
  .gal-num{ color:#666; }
  .spec caption{ background:none; border-bottom:1px solid #999; }
  .spec th, .spec td{ border-color:#ccc; color:#000; }
  .spec th{ border-right:1px solid #ccc; }
  .phead h1{ font-size:20pt; }
  h1,h2,h3{ break-after:avoid; }
  img{ max-height:7cm; width:auto; }
  .pcard-img{ aspect-ratio:auto; }
}

/* ---- content + sidebar layouts -------------------------------------------
   minmax(0,1fr) rather than 1fr: a bare 1fr track has an auto minimum, so one
   long unbreakable string (a standards list) blows the grid past the viewport
   instead of scrolling inside its own wrapper. */
.g-aside{ grid-template-columns:minmax(0,1fr) 320px; gap:clamp(28px,4vw,56px); align-items:start; }
.g-aside-l{ grid-template-columns:340px minmax(0,1fr); gap:clamp(24px,3vw,36px); align-items:start; }
.g-figs{ grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr)); gap:16px; }
.grid > *{ min-width:0; }

@media (max-width:960px){
  .g-aside, .g-aside-l{ grid-template-columns:minmax(0,1fr); }
  .g-aside aside{ position:static !important; }
}

/* photographs on the product stage fill it; only knockout art is contained */
.pcard-img img.ph, .hero-art .plate img.ph{ object-fit:cover; padding:0; }

/* rare-application page: prose beside one sticky lead shot */
.g-lead{ grid-template-columns:minmax(0,1fr) minmax(0,.85fr); gap:clamp(28px,4vw,52px); align-items:start; }
.lead-media{ position:sticky; top:calc(var(--header-h) + 20px); }

/* Product detail: the photo + enquire button sit in one column and the spec
   tables in the other, so on the 17 pages whose specs run long the media column
   just stopped — up to 486px of dead space on cast-steel-gate-valve. Sticky
   makes it track the specs instead, the same treatment .lead-media already
   gets. max-height + auto overflow so a media column that is somehow taller
   than the viewport can still be scrolled to its CTA rather than trapping it
   off-screen; pages whose specs are shorter than the photo never engage
   stickiness at all and are unchanged. */
@media (min-width:900px){
  .pdp-media{
    position:sticky; top:calc(var(--header-h) + 20px);
    max-height:calc(100vh - var(--header-h) - 40px); overflow:auto;
    scrollbar-width:thin;
  }
}
@media (max-width:960px){
  .g-lead{ grid-template-columns:minmax(0,1fr); }
  .lead-media{ position:static; max-width:460px; }
}

/* =========================================================== overview ====
   Home "Company overview": a four-step process rail, then a numbers panel
   beside a facility & certifications panel. Static markup — nothing here is
   hidden or animated by JS, so no-JS and reduced motion get the same page.

   The rail's connector is one rule drawn behind the steps (.ov-flow::before).
   The step cards are opaque, so the rule only shows in the gaps between them:
   a joined sequence without a single extra element. It runs horizontally
   through the icon row on desktop and down the icon column when stacked.   */
.ov-flow{
  --ov-icon:42px;                         /* .icon-tile size; centres the rule */
  position:relative; list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(14px,1.6vw,20px);
}
.ov-flow::before{
  content:''; position:absolute; z-index:0; height:2px; border-radius:2px;
  left:clamp(18px,2vw,22px); right:clamp(18px,2vw,22px);
  top:calc(clamp(18px,2vw,22px) + var(--ov-icon) / 2 - 1px);
  background:linear-gradient(90deg, var(--accent-line), var(--accent), var(--accent-line));
}
.ov-step{
  position:relative; z-index:1; min-width:0;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:clamp(18px,2vw,22px);
  transition:border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.ov-step:hover{ border-color:var(--accent-line); transform:translateY(-3px); box-shadow:var(--shadow-md); }
.ov-step-top{ display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; }
.ov-step .icon-tile{ margin:0; }
.ov-step-n{
  font-family:var(--font-mono); font-size:11.5px; font-weight:600;
  color:var(--accent-text); letter-spacing:.06em; font-variant-numeric:tabular-nums;
}
.ov-step h3{
  font-family:var(--font-disp); font-size:var(--fs-h3); font-weight:600;
  letter-spacing:-.01em; line-height:1.35; margin-bottom:7px;
}
.ov-step p{ font-size:13.5px; color:var(--text-2); line-height:1.6; text-wrap:pretty; }

@media (max-width:1024px){
  .ov-flow{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  /* two rows of two: a horizontal rule would run through the second row's
     text, so the connector is dropped and the numbers carry the sequence */
  .ov-flow::before{ display:none; }
}
@media (max-width:560px){
  .ov-flow{ grid-template-columns:minmax(0,1fr); }
  .ov-flow::before{            /* stacked: the rule runs down the icon column */
    display:block; width:2px; height:auto; right:auto;
    top:clamp(18px,2vw,22px); bottom:clamp(18px,2vw,22px);
    left:calc(clamp(18px,2vw,22px) + var(--ov-icon) / 2);
    background:linear-gradient(180deg, var(--accent-line), var(--accent), var(--accent-line));
  }
}
@media (hover:none){ .ov-step:hover{ transform:none; } }
@media (prefers-reduced-motion: reduce){ .ov-step:hover{ transform:none; } }
@media print{
  .ov-flow::before{ display:none; }
  .ov-flow{ grid-template-columns:1fr 1fr; }
  .ov-step{ break-inside:avoid; border:1px solid #999; background:#fff; }
}

/* ================================================================ form ==== */
.form-box{ padding:clamp(20px,2.5vw,28px); }
.vform{ display:grid; gap:16px; }
.field{ display:grid; gap:7px; min-width:0; }
.field-row{ display:grid; grid-template-columns:1fr 1fr; gap:16px; }
.field label{ font-size:12.5px; font-weight:600; color:var(--text-2); letter-spacing:.01em; }
.field label span{ color:var(--err); }
.field-in{
  position:relative; display:flex; align-items:center;
  border:1px solid var(--border-2); border-radius:10px;
  background:var(--surface-2);
  transition:border-color .18s var(--ease), box-shadow .18s var(--ease), background .18s var(--ease);
}
.field-in > svg{
  width:16px; height:16px; margin:0 0 0 13px; flex-shrink:0;
  stroke:var(--text-3); fill:none; pointer-events:none;
}
.field-in-area{ align-items:flex-start; }
.field-in-area > svg{ margin-top:13px; }
.field-in input, .field-in textarea{
  width:100%; border:0; background:transparent; outline:none;
  font-family:inherit; font-size:14px; color:var(--text);
  padding:12px 13px; resize:vertical;
}
.field-in textarea{ min-height:120px; line-height:1.6; }
.field-in input::placeholder, .field-in textarea::placeholder{ color:var(--text-3); }
.field-in:focus-within{
  border-color:var(--accent); background:var(--surface);
  box-shadow:0 0 0 3px var(--accent-soft);
}
.field-in:focus-within > svg{ stroke:var(--accent-text); }
/* browser autofill: keep it on-theme instead of the default yellow slab */
.field-in input:-webkit-autofill{
  -webkit-text-fill-color:var(--text);
  -webkit-box-shadow:0 0 0 40px var(--surface-2) inset;
  caret-color:var(--text);
}
.vform-submit{ position:relative; margin-top:2px; width:100%; }
.vform-label{ display:inline-flex; align-items:center; gap:8px; }
.vform-spin{
  position:absolute; width:17px; height:17px; border-radius:50%;
  border:2px solid rgba(255,255,255,.4); border-top-color:#fff;
  opacity:0; animation:vspin .7s linear infinite;
}
@keyframes vspin{ to{ transform:rotate(360deg); } }
.vform[data-busy="true"] .vform-label{ opacity:0; }
.vform[data-busy="true"] .vform-spin{ opacity:1; }
.vform-note{ font-size:12.5px; color:var(--text-3); text-align:center; margin-top:2px; }
.vform-note a{ color:var(--accent-text); text-decoration:none; }
.vform-note a:hover{ text-decoration:underline; text-underline-offset:3px; }
.field-in.invalid{ border-color:var(--err); }
.field-err{ font-size:11.5px; color:var(--err); }

.vform-done{ text-align:center; padding:22px 8px; }
.vform-done-mark{
  width:56px; height:56px; border-radius:50%; margin:0 auto 16px;
  display:grid; place-items:center; color:#fff;
  background:linear-gradient(135deg, var(--ok), #34D399);
  box-shadow:0 8px 24px color-mix(in srgb, var(--ok) 40%, transparent);
  animation:vpop .4s var(--ease-out);
}
.vform-done-mark svg{ width:26px; height:26px; stroke:#fff; }
@keyframes vpop{ 0%{ transform:scale(.6); opacity:0; } 100%{ transform:scale(1); opacity:1; } }
.vform-done h3{ font-family:var(--font-disp); font-size:19px; font-weight:700; margin-bottom:8px; }
.vform-done p{ color:var(--text-2); font-size:14px; max-width:34ch; margin:0 auto; }

@media (max-width:520px){
  .field-row{ grid-template-columns:1fr; }
}

/* ============================================ layout grids (audit fixes) === */
/* category hub sub-tiles: auto-fit fills the row, so 4 gate-valve types read as
   one 4-up row instead of a 3+1 with an orphan */
.gcat{ grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr)); }

/* industries: 5 across → 15 tiles land as a clean 5×3 with no orphan row */
.gind{ grid-template-columns:repeat(5,1fr); }
@media (max-width:1080px){ .gind{ grid-template-columns:repeat(4,1fr); } }
@media (max-width:820px){ .gind{ grid-template-columns:repeat(3,1fr); } }
@media (max-width:520px){ .gind{ grid-template-columns:repeat(2,1fr); } }

/* services: compact horizontal tiles (icon beside title) — the copy is just a
   service name, so a tall card left half-empty; this fills the shape.
   4 across, because there are exactly 8 services: the old 300px auto-fill
   settled on 3 columns at the 1136px content width and stranded the last two
   cards beside an empty third slot. 4x2 fills both rows. */
.gsvc{ grid-template-columns:repeat(4,1fr); }
@media (max-width:1080px){ .gsvc{ grid-template-columns:repeat(3,1fr); } }
@media (max-width:820px){ .gsvc{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:560px){ .gsvc{ grid-template-columns:minmax(0,1fr); } }
.svc{
  display:flex; align-items:center; gap:16px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:16px 18px;
  transition:border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.svc:hover{ border-color:var(--border-2); transform:translateY(-3px); box-shadow:var(--shadow-md); }
.svc .icon-tile{ margin:0; flex-shrink:0; }
.svc h3{
  font-family:var(--font-disp); font-size:14.5px; font-weight:600; line-height:1.35;
  letter-spacing:-.01em; margin:0;
}

/* welcome "what we do": 5 cards on a 6-col base — three up top, the trailing two
   centered below, so there is no lonely orphan and no forced equal-height void */
.gwwd{ grid-template-columns:repeat(6,1fr); align-items:start; }
.gwwd > *{ grid-column:span 2; }
.gwwd > *:nth-child(4){ grid-column:2 / 4; }
.gwwd > *:nth-child(5){ grid-column:4 / 6; }
@media (max-width:960px){
  .gwwd{ grid-template-columns:1fr 1fr; }
  .gwwd > *, .gwwd > *:nth-child(4), .gwwd > *:nth-child(5){ grid-column:auto; }
}
@media (max-width:620px){ .gwwd{ grid-template-columns:1fr; } }


/* ---- capability rail (home) ----------------------------------------------
   "What do we do" — five items whose bodies range from two lines to a nine-row
   tick list. As a card grid the heights fought each other; here a numbered
   index rail selects one panel at a time.

   Two things carry the layout stability:
   1. Every panel lives in the SAME grid cell (.cr-stack > * { grid-area:1/1 }),
      so the stack is permanently as tall as the tallest panel and switching
      cannot move anything. No JS measuring, no min-height to maintain.
   2. Every hidden state is scoped to `html.js`. With JS off all five panels are
      simply visible and stacked, which is also what print gets.               */
.caprail{ display:grid; gap:clamp(20px,2.4vw,28px); }

/* ---- the index rail ---------------------------------------------------- */
.cr-rail{ display:flex; flex-direction:column; gap:8px; }
.cr-tab{
  display:flex; align-items:center; gap:11px; width:100%; text-align:left;
  padding:12px 13px; border-radius:10px; cursor:pointer;
  background:var(--surface); border:1px solid var(--border); color:inherit;
  transition:border-color .2s var(--ease), background .2s var(--ease),
             transform .2s var(--ease);
}
/* the DesignBoard bento accent bar: neutral until the row is the active one */
.cr-tab > i{
  width:3px; height:30px; border-radius:99px; flex:none;
  background:var(--border-2);
  transition:background .2s var(--ease), height .2s var(--ease);
}
.cr-num{
  font-family:var(--font-mono); font-size:11.5px; font-weight:600;
  color:var(--text-3); flex:none; font-variant-numeric:tabular-nums;
  transition:color .2s var(--ease);
}
.cr-tab-title{
  font-family:var(--font-disp); font-size:15px; font-weight:600;
  letter-spacing:-.01em; line-height:1.3; text-wrap:balance; min-width:0;
}
.cr-chev{ margin-left:auto; flex:none; display:grid; place-items:center; }
.cr-chev svg{
  width:13px; height:13px; stroke:var(--text-3); fill:none;
  transition:transform .22s var(--ease), stroke .2s var(--ease);
}
.cr-tab:hover{ background:var(--surface-2); border-color:var(--border-2); transform:translateX(2px); }
.cr-tab[aria-selected="true"]{
  background:var(--surface-2); border-color:var(--accent-line);
}
.cr-tab[aria-selected="true"] > i{ background:var(--accent); height:34px; }
.cr-tab[aria-selected="true"] .cr-num{ color:var(--accent-text); }
.cr-tab[aria-selected="true"] .cr-chev svg{ stroke:var(--accent-text); }

/* ---- the panel stack --------------------------------------------------- */
.cr-stack{ display:grid; }
.cr-panel{ min-width:0; }
.cr-panel .icon-tile{ margin-bottom:14px; }
.cr-panel h3{ font-size:clamp(16.5px,1.4vw,19px); margin-bottom:10px; }
.cr-panel p{ font-size:var(--fs-body); color:var(--text-2); text-wrap:pretty; }
.cr-panel p + p{ margin-top:12px; }
.cr-panel p + .ticks{ margin-top:12px; }   /* breathing room between prose and its list */

/* ---- enhanced (JS on) -------------------------------------------------- */
html.js .cr-stack > .cr-panel{
  grid-area:1 / 1;                 /* all panels share one cell */
  opacity:0; visibility:hidden; transform:translateY(6px);
  transition:opacity .22s var(--ease-out), transform .22s var(--ease-out),
             visibility .22s;
}
html.js .cr-stack > .cr-panel[data-active="true"]{
  opacity:1; visibility:visible; transform:none;
}
/* reduced motion: the global rule already zeroes the duration; drop the offset
   too so the swap is a plain replacement rather than a 0ms jump between two
   positions (same treatment the gallery gets). */
html.reduced .cr-stack > .cr-panel{ transform:none; }

@media (min-width:900px){
  .caprail{
    grid-template-columns:minmax(280px,.9fr) minmax(0,1.6fr);
    gap:clamp(28px,3vw,40px); align-items:start;
  }
  .cr-rail{ position:sticky; top:calc(var(--header-h) + 24px); }
  /* tick lists inside a capability panel run two-up at this width — scoped to
     .cr-panel so the global .ticks (services page etc.) stays single-column */
  .cr-panel .ticks{ grid-template-columns:1fr 1fr; column-gap:18px; }
}

/* ---- accordion (<900px) -------------------------------------------------
   Same markup, no sticky: each tab becomes the header of the panel that
   follows it. Source order is rail-then-stack, so the panels are re-ordered
   into the rail's flow with `order` on a single flex column. */
@media (max-width:899px){
  html.js .caprail{ display:flex; flex-direction:column; gap:8px; }
  html.js .cr-rail{ display:contents; }
  html.js .cr-stack{ display:contents; }
  html.js .cr-tab{ order:var(--i); }
  html.js .cr-stack > .cr-panel{
    order:calc(var(--i) + 1);
    grid-area:auto; margin:-2px 0 6px;
  }
  /* an out-of-flow panel would leave the accordion with a permanent gap the
     height of the tallest panel, so collapsed rows are removed from layout */
  html.js .cr-stack > .cr-panel:not([data-active="true"]){ display:none; }
  html.js .cr-tab[aria-expanded="true"] .cr-chev svg{ transform:rotate(180deg); }
  /* the open row's header already states the title one line above — repeating
     it inside the panel reads as a stutter at this width */
  html.js .cr-stack > .cr-panel > h3{ display:none; }
  html.js .cr-stack > .cr-panel > .icon-tile{ margin-bottom:12px; }
}

/* ---- print --------------------------------------------------------------
   Everything visible, stacked, and the rail (a screen control) removed. */
@media print{
  .caprail{ display:block !important; }
  .cr-rail{ display:none !important; }
  .cr-stack{ display:block !important; }
  html.js .cr-stack > .cr-panel,
  .cr-stack > .cr-panel{
    display:block !important; grid-area:auto !important;
    opacity:1 !important; visibility:visible !important; transform:none !important;
    break-inside:avoid; margin-bottom:12px;
  }
}


/* ============================================================== legacy ====
   Our Legacy: the centre-spine timeline, its year navigator, the "Venus today"
   gallery and the family-story chapters. Reveal states are scoped to `html.js`
   (set by site.js at startup) so nothing is hidden when JS is off, and the
   reduced-motion block near the top of this file already flattens transitions
   to ~0ms.                                                                 */

/* ---- reveal ------------------------------------------------------------
   Only ever hidden when JS is present AND motion is welcome. `.reduced` is
   stamped on <html> by site.js when prefers-reduced-motion matches, so the
   initial state never even applies rather than relying on a fighting
   !important override. `--rx` lets a card come in from its own side of the
   spine; it defaults to 0 so non-timeline reveals just rise. */
html.js:not(.reduced) .reveal{
  opacity:0; transform:translate(var(--rx, 0), 14px);
  transition:opacity .46s var(--ease-out), transform .46s var(--ease-out);
  transition-delay:var(--rd, 0ms);
}
html.js:not(.reduced) .reveal.in{ opacity:1; transform:none; }

/* ---- stat strip -------------------------------------------------------
   The ISO tile's value is many times the length of "4", so the strip is laid
   out as rows that bottom-align the label: without this the long value wraps
   and drags its own caption a line below its neighbours'. */
.lg-stats .stat{ display:flex; flex-direction:column; justify-content:space-between; gap:6px; }
.lg-stats .stat b{ font-size:clamp(17px,1.6vw,22px); text-wrap:balance; }
.lg-stats .stat b[data-count]{ font-variant-numeric:tabular-nums; }

/* ---- intro: copy beside the 2026 portrait ---------------------------- */
.lg-intro{ grid-template-columns:minmax(0,1fr) minmax(0,.9fr); gap:clamp(26px,4vw,52px); align-items:center; }
.lg-intro .fig-media{ aspect-ratio:16/10; }
@media (max-width:900px){ .lg-intro{ grid-template-columns:minmax(0,1fr); } }

/* ---- year navigator ---------------------------------------------------
   Sticks under the site header. The scroller is its own overflow context, so
   fifteen years can never widen the page — only the strip scrolls. */
.lg-nav{
  position:sticky; top:var(--header-h); z-index:20;
  margin-bottom:clamp(22px,3vw,34px);
  background:var(--glass); border-block:1px solid var(--border);
  -webkit-backdrop-filter:blur(14px) saturate(1.3);
          backdrop-filter:blur(14px) saturate(1.3);
}
.lg-nav-scroll{
  display:flex; gap:2px; overflow-x:auto; scrollbar-width:none;
  max-width:var(--content-w); margin:0 auto; padding:8px var(--gut);
  scroll-snap-type:x proximity;
}
.lg-nav-scroll::-webkit-scrollbar{ display:none; }
.lg-nav a{
  flex:0 0 auto; scroll-snap-align:center;
  padding:7px 13px; border-radius:99px;
  font-family:var(--font-mono); font-size:12.5px; font-weight:500;
  color:var(--text-3); text-decoration:none; white-space:nowrap;
  border:1px solid transparent;
  transition:color .18s var(--ease), background .18s var(--ease), border-color .18s var(--ease);
}
.lg-nav a:hover{ color:var(--text); background:var(--surface-2); }
.lg-nav a[aria-current="true"]{
  color:var(--accent-text); background:var(--accent-soft); border-color:var(--accent-line);
}
@media (max-width:900px){
  /* A bottom bar on mobile: the header strip would eat a third of the screen.
     It is fixed only while the timeline section is on screen — `position:
     sticky` with `bottom:0` inside the section does exactly that, without JS,
     and crucially it stops overlapping the footer once the section ends.
     (A truly fixed bar sat on top of the footer and swallowed its taps.) */
  .lg-nav{
    position:fixed; top:auto; bottom:0; left:0; right:0; z-index:20; margin:0;
    border-top:1px solid var(--border); background:var(--glass-2);
    transition:transform .25s var(--ease), opacity .25s var(--ease);
  }
  /* site.js sets data-off once the timeline has scrolled past. A permanently
     fixed bar sits on top of the footer and swallows its taps. */
  .lg-nav[data-off="true"]{ transform:translateY(110%); opacity:0; pointer-events:none; }
  .lg-nav-scroll{ padding:7px 12px; }
  .lg-track{ padding-bottom:64px; }   /* clear the fixed bar */
}

/* ---- the spine --------------------------------------------------------
   `--fill` (0-1) is written by site.js from the track's bounding rect; with
   JS off it stays 1 so the line reads as a finished rule rather than an empty
   gutter. --spine-x is the single source of truth for the line's x — the dots
   read the same token, so they cannot drift apart. */
.lg-track{
  --spine-x:10px;             /* mobile: 34px inset, 2px line -> centre at 10 */
  position:relative; padding-left:34px;
}
.lg-track::before{
  content:''; position:absolute; left:var(--spine-x); top:6px; bottom:6px; width:2px;
  border-radius:2px; background:var(--border-2);
}
.lg-track::after{
  content:''; position:absolute; left:var(--spine-x); top:6px; width:2px; border-radius:2px;
  height:calc((100% - 12px) * var(--fill, 1));
  background:linear-gradient(var(--accent), var(--accent-2));
  box-shadow:0 0 10px var(--accent-glow);
}
html.js .lg-track{ --fill:0; }
html.js.reduced .lg-track{ --fill:1; }

/* ---- era chapter header ----------------------------------------------- */
.lg-era-head{ position:relative; margin:clamp(26px,4vw,46px) 0 clamp(16px,2vw,24px); }
.lg-era-head:first-child{ margin-top:0; }
.lg-era-head h3{
  font-family:var(--font-disp); font-size:clamp(19px,2.2vw,27px); font-weight:700;
  letter-spacing:-.022em; line-height:1.15;
}
.lg-era-head span{
  display:block; margin-top:4px;
  font-family:var(--font-mono); font-size:12px; font-weight:500;
  letter-spacing:.08em; color:var(--accent-text);
}

/* ---- milestone card ---------------------------------------------------- */
.lg-item{ position:relative; margin-bottom:clamp(16px,2vw,24px); }
.lg-item:last-child{ margin-bottom:0; }
.lg-item::before{             /* dot centred on the spine */
  content:''; position:absolute; left:-31px; top:26px;
  width:12px; height:12px; border-radius:50%;
  background:var(--surface); border:2px solid var(--border-2); z-index:2;
  transition:background .2s var(--ease), border-color .2s var(--ease),
             box-shadow .2s var(--ease), transform .2s var(--ease);
}
.lg-item.lit::before{
  background:var(--accent); border-color:var(--accent);
  box-shadow:0 0 0 4px var(--accent-soft);
}
.lg-item:hover::before,
.lg-item:focus-within::before{
  transform:scale(1.35); box-shadow:0 0 0 6px var(--accent-soft);
  border-color:var(--accent);
}
.lg-card{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:clamp(16px,2vw,22px);
  transition:border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.lg-item:hover .lg-card,
.lg-item:focus-within .lg-card{
  transform:translateY(-4px); border-color:var(--accent-line); box-shadow:var(--shadow-lg);
}
.lg-ico{
  display:grid; place-items:center; width:40px; height:40px; border-radius:11px;
  background:var(--surface-2); border:1px solid var(--border);
  color:var(--accent-text); margin-bottom:14px;
  transition:background .2s var(--ease), border-color .2s var(--ease);
}
.lg-ico svg{ width:20px; height:20px; }
.lg-item:hover .lg-ico,
.lg-item:focus-within .lg-ico{ background:var(--accent-soft); border-color:var(--accent-line); }
.lg-year{
  display:block; font-family:var(--font-disp); font-variant-numeric:tabular-nums;
  font-size:clamp(24px,2.6vw,32px); font-weight:700; letter-spacing:-.03em;
  line-height:1; color:var(--accent-text); margin-bottom:7px;
}
.lg-card h4{
  font-family:var(--font-disp); font-size:var(--fs-h3); font-weight:600;
  letter-spacing:-.012em; line-height:1.35; margin-bottom:7px;
}
.lg-card p{ color:var(--text-2); font-size:14px; text-wrap:pretty; }
.lg-card ul{ list-style:none; display:grid; gap:8px; margin:0; }
.lg-card li{ position:relative; padding-left:18px; color:var(--text-2); font-size:14px; }
.lg-card li::before{
  content:''; position:absolute; left:2px; top:.62em;
  width:5px; height:5px; border-radius:50%; background:var(--accent-line);
}
.lg-card strong{ color:var(--text); font-weight:600; }

/* ---- desktop: centre spine, cards alternating either side --------------
   The track becomes a two-column grid split down the middle; the spine runs
   in the seam. Left-side cards occupy column 1, right-side column 2, and the
   era headers span both. */
@media (min-width:901px){
  .lg-track{
    --spine-x:calc(50% - 1px);
    --lg-gap:clamp(48px,6vw,84px);
    display:grid; grid-template-columns:1fr 1fr;
    column-gap:var(--lg-gap); align-items:start;
    padding-left:0;
  }
  .lg-era-head{
    grid-column:1 / -1; text-align:center; position:relative; z-index:1;
    /* the spine runs behind the header, so the title needs its own ground or
       the 2px line strikes through the words */
    padding:16px 0; isolation:isolate;
  }
  .lg-era-head::before{
    content:''; position:absolute; z-index:-1; inset:0 50% 0 50%;
    width:min(420px,86%); margin-inline:auto; inset-inline:0;
    background:radial-gradient(60% 60% at 50% 50%, var(--bg) 62%, transparent 100%);
  }
  .lg-era-head::after{        /* thin rule under the chapter title */
    content:''; display:block; width:64px; height:1px; margin:14px auto 0;
    background:var(--border-2);
  }
  .lg-item[data-side="left"]{ grid-column:1; }
  .lg-item[data-side="right"]{ grid-column:2; }
  /* dot sits on the seam: half the column gap away from the card's edge */
  .lg-item[data-side="left"]::before{ left:auto; right:calc(var(--lg-gap) / -2 - 8px); }
  .lg-item[data-side="right"]::before{ left:calc(var(--lg-gap) / -2 - 8px); }
  .lg-item[data-side="left"] .lg-card{ text-align:right; }
  .lg-item[data-side="left"] .lg-ico{ margin-left:auto; }
  .lg-item[data-side="left"] ul{ text-align:left; }
  /* enter from each card's own side of the spine */
  html.js:not(.reduced) .lg-item[data-side="left"]{ --rx:-18px; }
  html.js:not(.reduced) .lg-item[data-side="right"]{ --rx:18px; }
  html.js:not(.reduced) .lg-era-head{ --rx:0; }
}

/* ---- Venus today gallery ---------------------------------------------- */
.lg-today{ grid-template-columns:repeat(2,1fr); }
.lg-today .fig-media{ aspect-ratio:16/10; }
.lg-today .fig{ transition:border-color .2s var(--ease), box-shadow .2s var(--ease); }
.lg-today .fig img{ transition:transform .35s var(--ease); }
.lg-today .fig:hover{ border-color:var(--accent-line); box-shadow:var(--shadow-lg); }
.lg-today .fig:hover img{ transform:scale(1.04); }
.lg-today .fig figcaption{ transition:background .2s var(--ease), color .2s var(--ease); }
.lg-today .fig:hover figcaption{ background:var(--surface-2); color:var(--text-2); }
@media (max-width:720px){ .lg-today{ grid-template-columns:1fr; } }

/* ---- family story: generation strip ------------------------------------ */
.lg-gens{ grid-template-columns:repeat(4,1fr); margin-bottom:clamp(30px,4vw,52px); }
.lg-gen{
  padding:16px 18px; border:1px solid var(--border); border-radius:var(--r-md);
  background:var(--surface);
}
.lg-gen b{
  display:block; font-family:var(--font-disp); font-size:14.5px; font-weight:600;
  letter-spacing:-.01em; line-height:1.3;
}
.lg-gen-yr{
  display:block; margin:3px 0 8px;
  font-family:var(--font-mono); font-size:11.5px; color:var(--accent-text);
}
.lg-gen p{ font-size:12.5px; color:var(--text-3); line-height:1.55; }
@media (max-width:900px){ .lg-gens{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:520px){ .lg-gens{ grid-template-columns:1fr; } }

/* ---- family story: chapters -------------------------------------------- */
.lg-chapters{ display:grid; gap:clamp(30px,4vw,54px); }
.lg-chapter{ display:grid; grid-template-columns:230px minmax(0,1fr); gap:clamp(22px,3vw,44px); align-items:start; }
.lg-chapter-head{ position:sticky; top:calc(var(--header-h) + 24px); }
.lg-chapter-head h3{
  font-family:var(--font-disp); font-size:clamp(16px,1.5vw,20px); font-weight:700;
  letter-spacing:-.018em; line-height:1.25; text-wrap:balance;
}
.lg-chapter-head span{
  display:block; margin-top:5px;
  font-family:var(--font-mono); font-size:11.5px; font-weight:500;
  letter-spacing:.06em; color:var(--accent-text);
}
.lg-chapter-body p{ color:var(--text-2); font-size:var(--fs-body); margin-bottom:15px; text-wrap:pretty; max-width:72ch; }
.lg-chapter-body p:last-child{ margin-bottom:0; }
/* drop cap on each chapter's opening paragraph */
.lg-chapter-body .lg-drop::first-letter{
  float:left; font-family:var(--font-disp); font-weight:700;
  font-size:3.1em; line-height:.86; padding:4px 10px 0 0;
  color:var(--accent-text);
}
.lg-quote{
  margin:0 0 18px; padding:2px 0 2px 18px;
  border-left:2px solid var(--accent-line);
  font-family:var(--font-disp); font-size:clamp(15.5px,1.4vw,18px); font-weight:500;
  line-height:1.45; letter-spacing:-.012em; color:var(--text); text-wrap:pretty;
}
@media (max-width:900px){
  .lg-chapter{ grid-template-columns:minmax(0,1fr); gap:14px; }
  .lg-chapter-head{ position:static; }
}

/* ---- print -------------------------------------------------------------
   The spine's filled half is a gradient the printer would render as a grey
   smudge, so the base rule alone carries the line. Reveals must be visible
   whatever state JS left them in, and the navigator is screen furniture. */
@media print{
  html.js:not(.reduced) .reveal,
  html.js:not(.reduced) .reveal.in{ opacity:1 !important; transform:none !important; }
  .lg-nav{ display:none !important; }
  .lg-track{ display:block !important; padding-left:34px; --spine-x:10px; }
  .lg-track::after{ display:none; }
  .lg-track::before{ background:#999; }
  .lg-item{ break-inside:avoid; }
  .lg-item[data-side="left"] .lg-card,
  .lg-item[data-side="right"] .lg-card{ text-align:left; }
  .lg-item[data-side="left"]::before,
  .lg-item[data-side="right"]::before{ left:-31px; right:auto; background:#000; border-color:#000; box-shadow:none; }
  .lg-era-head{ text-align:left !important; }
  .lg-year, .lg-ico{ color:#000; }
  .lg-card{ border:1px solid #999; }
  .lg-chapter-head{ position:static !important; }
  .lg-quote{ border-left-color:#999; }
}


/* ---- clients marquee ------------------------------------------------------
   Two rows of client logos scrolling in opposite directions, full-bleed so the
   loop has no visible start or end. Every chip is a white plate in BOTH themes:
   these are other companies' trademarks and several (nalco, rspl, tata-projects,
   maa-kudargarhi) are near-black artwork that would vanish on the dark ground.
   A plate is also the honest treatment — no grayscale filter, no recolouring;
   each mark is shown as its owner publishes it.

   The loop is CSS only. Each track holds the twelve chips twice, so animating
   to translateX(-50%) lands on a pixel-identical frame. The seam needs the same
   gap the flex layout gives every other pair, and `gap` does not apply between
   the last child of set 1 and the first of set 2 (they are the two halves of one
   flex line, but the duplicate is a wrapper). Both halves therefore carry
   `padding-right` equal to the gap and the gap itself is 0 — every pitch in the
   row is then chip + 18px, seam included.                                   */
.clients{ display:flex; flex-direction:column; gap:18px; }

/* Its own overflow context: the tracks are far wider than the viewport and must
   never widen the page. The mask fades both ends into the page ground so chips
   enter and leave instead of being clipped. */
.clients-row{
  overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image:linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}

/* `will-change` promotes the track to its own compositor layer. Without it the
   browser re-rasterises the row every frame and the logos shimmer; with it the
   layer is painted once and only translated. */
.clients-track{
  display:flex; gap:0; width:max-content;
  animation:clients-scroll 48s linear infinite;
  will-change:transform; backface-visibility:hidden;
}
.clients-track[data-row="2"]{ animation-duration:56s; animation-direction:reverse; }
.clients-dupe{ display:flex; gap:0; }

@keyframes clients-scroll{ to{ transform:translateX(-50%); } }

/* Pause on hover or when anything inside takes focus, and when site.js reports
   the section is off-screen — an animation nobody can see is only battery. */
.clients:hover .clients-track,
.clients:focus-within .clients-track,
.clients[data-paused] .clients-track{ animation-play-state:paused; }

/* ---- chip ---------------------------------------------------------------
   Fixed box so the row pitch is constant and the -50% keyframe stays exact;
   the logo is centred inside with object-fit:contain and never upscaled past
   its own cap, so a 32x11 SVG and an 800x780 raster read at the same weight. */
.client-chip{
  flex:0 0 auto; box-sizing:content-box;
  --chip-gap:18px;
  width:200px; height:96px; padding-right:var(--chip-gap);   /* the row gap, seam included */
  display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:8px;
  transition:transform .2s var(--ease), box-shadow .2s var(--ease);
}
/* The plate is the chip's own box minus the gutter, painted by a pseudo-element
   so the gutter stays outside the border and the shadow. */
.client-chip::before{
  content:''; position:absolute; top:0; bottom:0; left:0; right:var(--chip-gap);
  background:#FFFFFF; border:1px solid var(--border);
  border-radius:var(--r-lg); box-shadow:var(--shadow-sm);
  z-index:-1;
}
.client-chip{ position:relative; isolation:isolate; }

/* Logo only — no caption (owner, 2026-09-28), so the logo takes the room the
   caption used to share. */
.client-chip img{
  max-width:156px; max-height:58px; width:auto; height:auto;
  object-fit:contain;
}
/* No artwork published for these three — the short name IS the mark, set
   large where a logo would sit. Hard-coded colour: the plate is white in both
   themes, so a theme-flipping token would put light text on white. */
.client-chip.is-text .client-name{
  font-family:var(--font-disp); font-size:22px; font-weight:700; line-height:1.2;
  color:#111114; text-align:center; letter-spacing:.02em;
  max-width:172px;
}

.client-chip:hover{ transform:translateY(-3px); }
.client-chip:hover::before{ box-shadow:var(--shadow-md); }
.client-chip:focus-within::before{ outline:2px solid var(--accent); outline-offset:2px; }

@media (max-width:700px){
  .client-chip{ --chip-gap:14px; width:160px; height:80px; }
  .client-chip img{ max-width:124px; max-height:48px; }
  .client-chip.is-text .client-name{ font-size:18px; max-width:140px; }
}

/* ---- static fallback ----------------------------------------------------
   Reduced motion, and JS off. Both collapse to the same thing: a centred
   wrapping grid showing each client once. The duplicate set is display:none
   rather than merely hidden, so it cannot contribute width. The mask goes too —
   there is nothing scrolling past an edge to fade.

   The site-wide reduced-motion block near the top of this file only clamps
   animation-duration to .01ms; on an infinite marquee that reads as a violent
   flicker, so the animation is removed outright here.                       */
@media (prefers-reduced-motion: reduce){
  .clients-row{ -webkit-mask-image:none; mask-image:none; overflow:visible; }
  .clients-track{
    animation:none !important; width:auto;
    flex-wrap:wrap; justify-content:center; gap:18px 0;
  }
  .clients-dupe{ display:none; }
}
html:not(.js) .clients-row{ -webkit-mask-image:none; mask-image:none; overflow:visible; }
html:not(.js) .clients-track{
  animation:none; width:auto; flex-wrap:wrap; justify-content:center; gap:18px 0;
}
html:not(.js) .clients-dupe{ display:none; }

/* ---- print --------------------------------------------------------------
   A mask prints as a grey wash and a marquee prints as whatever frame it was
   paused on. Flatten to the same static grid, black on white. */
@media print{
  .clients-row{ -webkit-mask-image:none; mask-image:none; overflow:visible; }
  .clients-track{
    animation:none !important; transform:none !important;
    width:auto; flex-wrap:wrap; justify-content:flex-start; gap:12px 0;
  }
  .clients-dupe{ display:none !important; }
  .client-chip{ break-inside:avoid; }
  .client-chip::before{ border-color:#999; box-shadow:none; }
}
