/* ==========================================================================
   GOWECO — public site design layer
   Replaces the mirror stylesheet (ResourceHandlermergeall.css), public.css
   and the _gw_fixes.css patch stack with one authored system.

   Grammar: white thin chrome, photographic hero with white type, hairline
   structure, no shadows / radius / gradients on UI, indigo #10069f accent,
   pink #FA4692 signpost, indigo footer.

   This file styles the markup the CMS already emits — no template rewrite is
   required for it to work.
   ========================================================================== */

:root{
  --bg:#ffffff;
  --bg-soft:#f6f6f3;
  --bg-warm:#f2f2ee;
  --ink:#15161a;
  --ink-2:#3a3d45;
  --muted:#6c6f78;
  --faint:#9a9da6;
  --line:#e5e5e0;
  --line-2:#d8d8d2;
  --accent:#10069f;
  --accent-ink:#0b0472;
  --pink:#fa4692;
  --indigo:#10069f;
  --pad:clamp(20px,4.2vw,72px);
  --maxw:1280px;
  --hdr-h:78px;
  /* The gap between the page menu and the utility cluster. Named because the
     hairline between them has to sit in the MIDDLE of this gap, and a hard
     -22px offset cannot stay centred once the gap shrinks with the viewport
     (at 1024 the gap is 20.5px, so -22px put the line on top of the CTA). */
  --hdr-gap:clamp(14px,2vw,34px);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--bg);color:var(--ink-2);
  font-family:"Inter","Noto Sans Arabic",-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  font-size:16px;line-height:1.75;font-weight:400;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
img{display:block;max-width:100%;height:auto}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
h1,h2,h3,h4,h5{color:var(--ink);font-weight:300;letter-spacing:-.022em;line-height:1.12;margin:0}
p{margin:0}
ul,ol{margin:0;padding:0;list-style:none}
.hide{display:none!important}
.clearfix::after{content:"";display:block;clear:both}
.container{max-width:var(--maxw);margin:0 auto;padding:0 var(--pad);width:100%}

/* --------------------------------------------------------------------------
   1. Header
   -------------------------------------------------------------------------- */
#headerwrapper{
  position:sticky;top:0;z-index:900;background:rgba(255,255,255,.96);
  backdrop-filter:saturate(1.2) blur(8px);
  border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:0;
  height:var(--hdr-h);padding:0 var(--pad);
  width:100%;max-width:none;margin:0;
}
#logo{flex:0 0 auto;display:flex;align-items:center;margin:0;padding:0;float:none;width:auto}
.logo-inner{display:flex;align-items:center}
#logo img{height:31px;width:auto;display:block}
#top-left{flex:1 1 auto;display:flex;align-items:center;justify-content:flex-end;gap:var(--hdr-gap);min-width:0;float:none;width:auto;padding:0}
#topnavigation{display:flex;align-items:center;min-width:0}
.fw-Menu{display:flex;align-items:center}
.fwMenuwrapper{display:flex;align-items:center}
/* The nav items stretch to the full header height, so the <li> box reaches
   the same edge the mega panel starts from. Without this the label is a
   38px box centred in a 78px bar and the 20px of header below it belongs
   to nobody -- the pointer crossing it drops :hover and the panel shuts
   before the cursor arrives. The label itself keeps its natural height;
   only the hover target grows. */
#top-left{align-self:stretch}
#topnavigation,.fw-Menu,.fwMenuwrapper{height:100%}
#section-Homepage-level1{display:flex;align-items:stretch;height:100%;gap:clamp(18px,2vw,29px);margin:0;padding:0;list-style:none}
/* No position:relative here on purpose -- the mega panel has to resolve
   against #headerwrapper (see .gw-mega). The underline pseudo lives on the
   <a>, which sets its own position:relative, so nothing else needs this. */
#section-Homepage-level1 > li{display:flex;align-items:center;float:none;margin:0;padding:0;background:none;border:0}
/* Nav labels are set as uppercase micro-labels rather than 14px sentence case.
   Six sentence-case words in a row read as a sentence and made the header feel
   wordy; the same six as 12px tracked caps read as a nameplate, which is what
   a plant buyer expects to scan. */
#section-Homepage-level1 > li > a.gw-top-link{
  position:relative;display:inline-block;padding:11px 0;font-size:.75rem;font-weight:500;
  color:var(--ink-2);letter-spacing:.12em;text-transform:uppercase;transition:color .2s;
  border:0;background:none;
}
/* The rule under a nav item grows from the left on hover and stays put on the
   current section. It is drawn on the anchor, not the <li>, so its width
   follows the label rather than the dropdown box. */
#section-Homepage-level1 > li > a.gw-top-link::after{
  content:"";position:absolute;left:0;right:0;bottom:4px;height:1px;
  background:var(--accent);transform:scaleX(0);transform-origin:left center;
  transition:transform .28s cubic-bezier(.2,.7,.2,1);
}
#section-Homepage-level1 > li:hover > a.gw-top-link,
#section-Homepage-level1 > li:focus-within > a.gw-top-link{color:var(--ink)}
#section-Homepage-level1 > li:hover > a.gw-top-link::after,
#section-Homepage-level1 > li:focus-within > a.gw-top-link::after,
#section-Homepage-level1 > li.gw-current > a.gw-top-link::after{transform:scaleX(1)}
/* Solid rather than an outline pill: the header already has hairlines from the
   mega panels and the utility divider, and a third outline competed with them.
   A filled block also gives the bar one clear end point to scan to. */
#section-Homepage-level1 > li.gw-nav-cta > a.gw-top-link{
  color:#fff;padding:10px 20px;letter-spacing:.1em;
  background:var(--ink);border:1px solid var(--ink);border-radius:100px;
  transition:background .22s,color .22s,border-color .22s;
}
#section-Homepage-level1 > li.gw-nav-cta > a.gw-top-link::after{display:none}
#section-Homepage-level1 > li.gw-nav-cta > a.gw-top-link:hover{
  background:var(--accent);border-color:var(--accent);color:#fff;
}
#section-Homepage-level1 > li > a.gw-top-link span{white-space:nowrap}

/* Chinese has no uppercase, and every glyph already carries its own full-width
   sidebearing, so the 0.12em that spaces out the Latin labels only makes the
   characters float apart here. It needs the extra size instead. */
html[lang^="zh"] #section-Homepage-level1 > li > a.gw-top-link{
  font-size:.8125rem;letter-spacing:.04em;
}

/* mega dropdown */
/* The dropdown used to start 21px BELOW the nav item, which left a gap the
   pointer had to cross: crossing it dropped :hover on the <li> and the menu
   shut before the cursor arrived. The box now starts flush at 100% and the
   visual offset is produced by transparent padding on this element, so the
   whole 18px strip stays part of the hover target. */
/* The panel is anchored to #headerwrapper, not to its own nav item.

   It used to hang off the <li> at left:-24px, which is only correct while the
   label happens to be near the edge the panel grows toward. Measured on the
   live site, it was not: at 920px the panel ran 79px past the right edge, and
   in Arabic (where the nav is mirrored, so the rule flips to right:-24px) it
   started at x=-156 and lost a whole column off the left of the screen. A
   760px panel simply does not fit beside a nav label that sits 500px in.

   Anchored to the header and aligned to the content gutter instead, it cannot
   leave the page in either direction. The 18px top padding is still the
   transparent hover bridge -- it belongs to the panel, so the pointer never
   crosses dead space between the label and the box. Every nav label sits
   horizontally inside the panel's span, so moving straight down from a label
   always lands in the panel. */
.gw-mega{
  position:absolute;top:100%;right:var(--pad);left:auto;z-index:950;
  width:min(760px,calc(100vw - 2 * var(--pad)));background:none;border:0;
  padding:18px 0 0;display:none;
}
.gw-mega-inner{
  background:#fff;border:1px solid var(--line);padding:20px 26px;
  box-shadow:0 24px 48px -28px rgba(16,18,24,.28);
  /* Products carries fourteen entries; without a ceiling the panel ran to
     729px and off the bottom of a 900px window. */
  max-height:calc(100vh - var(--hdr-h) - 34px);overflow-y:auto;overscroll-behavior:contain;
}
#section-Homepage-level1 > li:hover > .gw-mega,
#section-Homepage-level1 > li:focus-within > .gw-mega,
#section-Homepage-level1 > li.gw-mega-open > .gw-mega{display:block}
#section-Homepage-level1 > li.gw-current > a.gw-top-link{color:var(--ink);font-weight:500}
/* The CTA is a filled pill painted in --ink, and the rule above paints every
   top-level link in --ink too. On /contact that put ink on ink and the label
   disappeared. Same specificity (1,2,1) decided by document order, so the pill
   needs one more class to keep its white label on the page it points to. */
#section-Homepage-level1 > li.gw-nav-cta.gw-current > a.gw-top-link{color:#fff}
body.gw-scrolled #headerwrapper{box-shadow:0 10px 26px -22px rgba(16,18,24,.5)}
/* Two columns that balance themselves, not a grid that fills row-wise.
   A row-wise grid put item 2 at the top of the second column, so with the
   products in catalogue order the three vacuum models landed at (row1,col1),
   (row1,col2), (row2,col1) -- never readable as one family. Columns flow down
   then across, so each column is one contiguous run of the catalogue, and the
   count of items no longer has to be hardcoded. */
.gw-mega-inner ul{
  column-count:2;column-gap:34px;
}
/* Separators are TOP borders, not bottom ones. With balanced columns the last
   item of the left column is not :last-child, so a bottom-border scheme left a
   stray hairline floating 63px above the panel's bottom edge -- it read as
   "there is more below". Top borders put the only removable edge at
   :first-child, which exists once, so both columns end clean. The single line
   above the second column's first entry reads as the column break, which is
   what it is. */
.gw-mega-inner li{border-top:1px solid var(--line);break-inside:avoid}
.gw-mega-inner li:first-child{border-top:0}
.gw-mega-inner li a{display:block;padding:8px 0}
.gw-mega-label{display:block;font-size:.82rem;color:var(--ink);line-height:1.3}
.gw-mega-desc{display:block;font-size:.72rem;color:var(--faint);line-height:1.4;margin-top:2px}
.gw-mega-inner li a:hover .gw-mega-label{color:var(--accent)}

/* language switcher */
.gw-langsw{position:relative;flex:0 0 auto}
/* Hairline between the page menu and the utility cluster (language, search).
   Without it the six nav labels, the CTA, "EN" and the magnifier all sat in one
   undifferentiated run and the bar read as nine words in a row. It hangs off
   the switcher rather than #topnavigation so that the header stays the only
   positioned ancestor of the mega panel.

   Offset is half the gap, not a fixed 22px: the gap is clamp(14px,2vw,34px),
   so a fixed offset drifts left as the viewport narrows and at 1024px the line
   landed on the CTA's right edge. Half the gap keeps it centred at every
   width, and -0.5px pulls the 1px stroke onto the exact midpoint instead of
   leaving it half a pixel to one side. */
.gw-langsw::before{
  content:"";position:absolute;left:calc(var(--hdr-gap) / -2 - .5px);top:50%;transform:translateY(-50%);
  width:1px;height:16px;background:var(--line-2);pointer-events:none;
}
.gw-langsw-btn{
  display:inline-flex;align-items:center;gap:7px;font-size:.8rem;color:var(--ink-2);
  padding:6px 0;
}
.gw-langsw-btn .fa:not(.gw-langsw-caret){display:none}
/* The trigger was as wide as its code: 32px for EN, 39px for 中文, 29px for AR.
   Because it sits at the right end of the utility cluster, switching language
   moved the header's right edge by 7px -- the whole nav row jumped. A fixed box
   sized to the widest code (中文, 26px at this size) keeps the cluster still;
   the shorter codes centre inside it. */
.gw-langsw-cur{
  letter-spacing:.1em;text-transform:uppercase;font-size:.75rem;
  display:inline-block;min-width:26px;text-align:center;
}
.gw-langsw-caret{
  width:6px;height:6px;border-right:1px solid var(--muted);border-bottom:1px solid var(--muted);
  transform:rotate(45deg) translateY(-2px);display:inline-block;
}
/* Same gap trap as the mega menu: the list sits 14px below the button, so the
   pointer crossed dead space and the :hover rule dropped it. The bridge is a
   transparent 14px pseudo-element that belongs to the list itself. */
/* 158px held the longest label (Русский, 53px) plus 70px of empty space, so the
   four rows looked pushed against the left edge of a box that was too wide for
   them, and the current-language dot floated far from the word it marked. 118px
   is 16 + 53 + 30 + the border, with a little air. */
.gw-langsw-list{
  position:absolute;top:calc(100% + 14px);right:0;min-width:118px;background:#fff;
  border:1px solid var(--line);padding:6px 0;display:none;z-index:960;
  box-shadow:0 20px 40px -26px rgba(16,18,24,.3);
}
.gw-langsw-list::before{
  content:"";position:absolute;left:0;right:0;top:-14px;height:14px;background:transparent;
}
.gw-langsw:hover .gw-langsw-list,
.gw-langsw:focus-within .gw-langsw-list,
.gw-langsw.is-open .gw-langsw-list{display:block}
/* The four entries have to start on one left edge, and they did not. Each label
   carries dir="<its own language>", so the Arabic entry's text-align resolved
   against its own rtl and العربية sat 88px to the right of the other three.
   Measured glyph x before: 17, 17, 17, 105.

   text-align is deliberately a PHYSICAL value here. Alignment has to follow the
   direction of the page, not of the entry, or the list goes ragged in exactly
   one language -- which is what a visitor sees. The dir attribute stays on the
   element so the Arabic word itself still shapes and connects right-to-left;
   only which edge it hangs off changes.

   The padding reserves 30px on the marked side for the dot below, so the labels
   of a marked and an unmarked entry still share a text box. */
.gw-langsw-list a,
.gw-langsw-list .is-current{
  position:relative;display:block;padding:9px 30px 9px 16px;
  font-size:.82rem;color:var(--ink-2);line-height:1.5;text-align:left;
}
body.is-rtl .gw-langsw-list a,
body.is-rtl .gw-langsw-list .is-current{padding:9px 16px 9px 30px;text-align:right}
.gw-langsw-list a:hover{background:var(--bg-soft);color:var(--accent)}
/* The current language used to be marked with a "·" that followed the label, so
   its position moved with the length of the word and the four rows read as
   four different things. A dot pinned to the row's trailing edge is the same
   distance from the edge in every language. The label itself goes one step
   darker than the links instead of one step lighter: the old --faint made the
   language you were reading look disabled. */
.gw-langsw-list .is-current{color:var(--ink)}
.gw-langsw-list .is-current::after{
  content:"";position:absolute;top:50%;right:16px;width:5px;height:5px;
  margin-top:-2.5px;border-radius:50%;background:var(--accent);
}
body.is-rtl .gw-langsw-list .is-current::after{right:auto;left:16px}
.gw-langsw.is-open .gw-langsw-caret{transform:rotate(225deg) translateY(-1px)}

/* header search */
.gw-search{display:flex;align-items:center;gap:0;position:relative;margin:0;padding:0;border:0;background:none}
.gw-search-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.gw-search-input{
  width:0;padding:0;border:0;border-bottom:1px solid transparent;background:none;
  font:inherit;font-size:.82rem;color:var(--ink);outline:none;
  transition:width .25s ease,padding .25s ease,border-color .25s;
}
.gw-search:focus-within .gw-search-input,
.gw-search:hover .gw-search-input{width:170px;padding:4px 4px 5px;border-bottom-color:var(--line-2)}
.gw-search-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;color:var(--ink-2);padding:0;
}
.gw-search-btn:hover{color:var(--accent)}
/* The header ships two copies of the search form: one inside #topnavigation
   for the mobile drawer, one in the desktop header bar. Both are plain block
   level, so on wide screens they rendered as two magnifiers side by side.
   The drawer copy is only ever wanted inside the mobile menu. */
#topnavigation .gw-search{display:none}
.gw-burger{display:none;width:30px;height:30px;position:relative;padding:0}
.gw-burger span{
  display:block;width:18px;height:1.5px;background:var(--ink);margin:4px auto;transition:.2s;
}
.gw-drawer-close{display:none}
.gw-scrim{display:none}

/* --------------------------------------------------------------------------
   2. Home hero -- copy on ink, photograph on the right

   The previous hero was a full-bleed photograph behind a 62% scrim, crossfading
   between three frames. Two things were wrong with it. The scrim was there to
   buy contrast for white type, but it also buried the only reason to look at the
   picture -- the tube bundles and pressure vessels -- and the file underneath was
   already underexposed at luma 54 with a blue cast, so the two together read as a
   dark blue rectangle. Splitting the band fixes that without a scrim: the
   photograph is shown at its own exposure, and the headline sits on a solid field
   where the contrast ratio is a fact rather than a hope.

   It also removes the carousel. Three 1920px frames meant three decodes before
   the page was interactive, and the first frame is the LCP element; slides two
   and three were seen by roughly nobody. One shot, one message.
   -------------------------------------------------------------------------- */
.gw-hero{
  position:relative;display:grid;grid-template-columns:minmax(0,44fr) 56fr;
  background:#101319;overflow:hidden;min-height:clamp(500px,72vh,660px);
}
.gw-hero-panel{
  display:flex;align-items:center;
  /* The left edge has to land on the same line as every .container heading below,
     so the offset is derived from the container formula rather than guessed. */
  padding:clamp(44px,5.4vw,76px) clamp(28px,3vw,52px) clamp(44px,5.4vw,76px)
          max(var(--pad),calc((100vw - var(--maxw)) / 2 + var(--pad)));
}
.gw-hero-copy{max-width:540px}
.gw-hero-shot{position:relative;background:#101319}
.gw-hero-shot img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:54% 50%;display:block;
}
.gw-hero-copy h1{
  color:#fff;font-size:clamp(2.05rem,3.05vw,3.05rem);line-height:1.08;
  letter-spacing:-.03em;font-weight:300;max-width:18ch;
  /* 15ch broke the headline into three lines with "specify" alone on the last
     one. The measure was the cause, not the copy: at 43.9px the panel gives
     450px and 15ch only asks for 377. At 18ch the line fits two words more, and
     balance then splits it 2/2 instead of 2/1. */
  text-wrap:balance;
}
.gw-hero-copy p{
  color:rgba(255,255,255,.74);font-size:clamp(.98rem,1.1vw,1.06rem);font-weight:300;
  line-height:1.62;max-width:46ch;margin-top:22px;
}
.gw-hero-eyebrow{
  display:block;color:rgba(255,255,255,.5);font-size:.7rem;font-weight:500;
  letter-spacing:.2em;text-transform:uppercase;margin-bottom:24px;
}
.gw-hero-actions{display:flex;align-items:center;gap:30px;margin-top:40px;flex-wrap:wrap}
.gw-hero-cta{
  display:inline-flex;align-items:center;gap:10px;
  padding:15px 30px;border:1px solid rgba(255,255,255,.82);border-radius:100px;
  color:#fff;font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;
  transition:background .2s,color .2s,border-color .2s;background:none;
}
/* One filled action and one underlined link. Two outlined pills of equal weight,
   which is what this used to be, leaves the visitor to guess which one the site
   wants them to press -- and neither of them was the thing a buyer actually does
   next, which is ask for a price. */
.gw-hero .gw-hero-cta{background:#fff;border-color:#fff;color:var(--ink);font-weight:500}
.gw-hero .gw-hero-cta:hover{background:transparent;color:#fff}
.gw-hero-more{
  display:inline-flex;align-items:center;gap:10px;padding-bottom:4px;
  color:rgba(255,255,255,.86);font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;
  border-bottom:1px solid rgba(255,255,255,.28);
  transition:color .2s,border-color .2s;
}
.gw-hero-more span{transition:transform .2s}
.gw-hero-more:hover{color:#fff;border-bottom-color:#fff}
.gw-hero-more:hover span{transform:translateX(4px)}
.gw-hero-cta:focus-visible,.gw-hero-more:focus-visible{outline:2px solid #fff;outline-offset:3px}

/* --------------------------------------------------------------------------
   3. Inner page hero (.full-width-banner from _hero.html)
   -------------------------------------------------------------------------- */
.full-width-banner{margin:0;padding:0;background:#fff;position:relative}
.full-width-banner-inner{
  position:relative;min-height:clamp(380px,46vh,520px);
  background-size:cover;background-position:center;
  display:flex;align-items:flex-end;
}
.full-width-banner-inner::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(90deg,rgba(16,18,24,.62) 0%,rgba(16,18,24,.40) 36%,rgba(16,18,24,.08) 68%,rgba(16,18,24,0) 90%),
    linear-gradient(0deg,rgba(16,18,24,.34) 0%,rgba(16,18,24,0) 55%);
}
.new-banner-mobi{display:none!important}
.full-width-banner-main{
  position:relative;z-index:2;width:100%;max-width:var(--maxw);margin:0 auto;
  padding:0 var(--pad) clamp(40px,6vh,72px);
}
.full-width-banner-content{max-width:900px}
.gw-hero-title{
  color:#fff;font-size:clamp(2.1rem,4.4vw,3.7rem);line-height:1.05;
  letter-spacing:-.032em;font-weight:300;margin:0;
  /* A two-line headline broken by the default greedy algorithm ends wherever the
     box runs out, which on the home page put "the" alone at the end of line one
     ("...built to the / class you specify"). balance splits it at the point that
     makes the two lines closest in length, so the break lands on a word the line
     can end on. */
  text-wrap:balance;
}
.gw-hero-subtitle{
  color:rgba(255,255,255,.9);font-size:clamp(.98rem,1.3vw,1.1rem);font-weight:300;
  line-height:1.6;max-width:560px;margin-top:20px;
}
.full-width-banner .button{margin-top:32px;display:block}
.module-cta-link{
  display:inline-flex;align-items:center;gap:11px;padding:13px 26px;
  border:1px solid rgba(255,255,255,.8);border-radius:100px;color:#fff;
  font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
  transition:background .2s,color .2s;
}
.module-cta-link:hover{background:#fff;color:var(--ink)}
.banner-down-arrow{display:none}

/* caption strip -> hairline tab row */
/* The caption strip is a quiet index of what the section covers, not a
   carousel nav (the source site used it for hero thumbnails; this build has a
   single hero and nothing here is clickable). English has to read as ONE line.
   Measured at 1440px the eight /cases captions total 899px, so the old
   column-gap of clamp(18px,2.6vw,40px) -- 37.4px there -- needed 1161px inside
   a 1159px container and pushed the eighth caption onto a second row, alone.
   Capping the gap at 28px brings the requirement to 1090px: one row on desktop,
   and below ~1100px it wraps compactly instead of leaving a stranded item.

   Russian and Arabic are a different case and wrap on purpose. The same eight
   labels measure 1241px in Russian -- 38% wider than English -- against roughly
   1120px of usable width, so no gap value fits them: even gap:0 needs 1241px.
   The only way to force one row is 11.5px type, which is smaller than the
   .8rem these labels are set in for a reason. Two rows it is; ru/cases breaks
   6+2 and ru/sol 6+1, neither of which strands a single label on its own. */
.full-width-banner .slider-nav-thumbnails{
  max-width:var(--maxw);margin:0 auto;padding:0 var(--pad);
  display:flex;flex-wrap:wrap;gap:2px clamp(14px,1.9vw,28px);
  border-bottom:1px solid var(--line);background:#fff;
}
.full-width-banner .slider-nav-thumbnails .thumb-box{
  padding:18px 0 15px;margin:0;float:none;width:auto;background:none;border:0;
  min-width:0;
}
/* the strip is a wrapping tab row, not a carousel: neutralise slick's track */
.full-width-banner .slider-nav-thumbnails .slick-list,
.full-width-banner .slider-nav-thumbnails .slick-track{
  overflow:visible!important;display:flex!important;flex-wrap:wrap;
  width:auto!important;max-width:none!important;transform:none!important;
}
.full-width-banner .slider-nav-thumbnails .slick-track{margin:0!important}
.full-width-banner .thumb-text{
  font-size:.8rem;letter-spacing:.02em;color:var(--muted);margin:0;
  white-space:nowrap;transition:color .18s;
}
/* There used to be a :first-child rule painting only the first caption in
   --ink. It carried no meaning -- there is no active slide -- and on /cases it
   made "Steel Industry" look like the selected filter when nothing was
   selected. Uniform now. */
.full-width-banner .thumb-box:hover .thumb-text{color:var(--ink)}

/* light variant for about / contact */
#about-hero-slider .full-width-banner-inner,
#contact-hero-slider .full-width-banner-inner{
  background-image:none!important;min-height:0;display:block;padding-top:clamp(46px,7vh,80px);
}
#about-hero-slider .full-width-banner-inner::after,
#contact-hero-slider .full-width-banner-inner::after{display:none}
#about-hero-slider .gw-hero-title,
#contact-hero-slider .gw-hero-title{color:var(--ink);font-size:clamp(2.3rem,4.8vw,3.9rem)}
#about-hero-slider .gw-hero-subtitle,
#contact-hero-slider .gw-hero-subtitle{color:var(--muted);margin-top:22px}
#about-hero-slider .module-cta-link,
#contact-hero-slider .module-cta-link{border-color:var(--ink);color:var(--ink)}
#about-hero-slider .module-cta-link:hover,
#contact-hero-slider .module-cta-link:hover{background:var(--ink);color:#fff}
#about-hero-slider .full-width-banner-main,
#contact-hero-slider .full-width-banner-main{padding-bottom:clamp(34px,5vh,54px)}

/* investors: indigo scrim */
#investors-hero-slider .full-width-banner-inner::after{
  background:
    linear-gradient(180deg,rgba(16,6,159,.62) 0%,rgba(16,6,159,.34) 45%,rgba(16,6,159,.66) 100%);
}

/* .page-hero (case, legal) and .hero-img (article) -> light heads */
.page-hero,.hero-img{
  padding:clamp(46px,7vh,84px) 0 clamp(28px,4vh,44px);
  background:#fff;border-bottom:1px solid var(--line);
}
.page-hero > *,.hero-img > *{max-width:var(--maxw);margin-left:auto;margin-right:auto;padding-left:var(--pad);padding-right:var(--pad)}
.page-hero h1,.hero-img h1{
  font-size:clamp(2.1rem,4.2vw,3.5rem);line-height:1.06;letter-spacing:-.032em;color:var(--ink);
}
.page-hero p,.hero-img p{color:var(--muted);font-size:1.02rem;margin-top:18px;max-width:620px}

/* Case pages keep their photo, but in a frame beside the headline instead of
   behind it. Both faults were visible in one screenshot: painted as a
   background it was cropped to a 3.4:1 strip, so every object in it lost its top
   and bottom, and because nothing set background-size the 800x582 file tiled --
   the same collage appeared twice across a 1440 viewport, at 35% black, under
   ink-coloured text. In a frame the photo keeps the ratio it was shot at and the
   headline stays dark on white like every other page here. */
.page-hero--case .container{
  display:grid;grid-template-columns:1.12fr .88fr;
  gap:clamp(26px,3.6vw,56px);align-items:center;
}
/* The headline size is set for the site's own short titles. A case title is a
   sentence -- "Oil-film bearing oil - steel mill" is 36 characters in English and
   56 in Russian -- so at the shared 3.5rem it broke into five lines and made the
   hero 693px tall. Measured: 2.7rem puts it back to three lines at 1440. */
.page-hero--case h1{font-size:clamp(1.85rem,3.15vw,2.7rem);max-width:22ch}
/* four columns of metadata need a full-width row; in half a row they collapse to
   three broken stubs */
.page-hero--case .meta-grid{
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:16px clamp(20px,2.4vw,32px);margin-bottom:0;
}
.page-hero--case .ph-figure{
  margin:0;aspect-ratio:4/3;overflow:hidden;background:var(--bg-soft);
  /* the photograph's own background fades to near-white at the bottom, so without
     an edge it dissolves into the page and the picture looks like it is floating */
  border:1px solid var(--line);
}
.page-hero--case .ph-figure img{display:block;width:100%;height:100%;object-fit:cover}
@media (max-width:900px){
  /* one column: the copy first, because the headline is what tells a visitor
     they followed the right link; the photo follows it rather than pushing it
     below the fold on a 390px screen */
  .page-hero--case .container{grid-template-columns:1fr;gap:22px}
  .page-hero--case{padding-bottom:clamp(26px,4vw,36px)}
  /* at 768 a full-width 4:3 frame is 528px tall and the hero reaches 964px;
     the photo is evidence, not a billboard */
  .page-hero--case .ph-figure{max-width:520px;margin-inline:auto;width:100%}
}

/* --------------------------------------------------------------------------
   4. Breadcrumbs
   -------------------------------------------------------------------------- */
.gw-breadcrumbs{
  max-width:var(--maxw);margin:0 auto;padding:20px var(--pad) 0;
  font-size:.76rem;color:var(--muted);letter-spacing:.02em;
}
/* --faint (#9a9da6) on white is 2.71:1 -- below AA for 12px text, and the crumb
   is the only in-page navigation a visitor has on a deep URL. --muted is 5.2:1
   and still quiet enough not to compete with the H1 underneath. */
.gw-breadcrumbs a{color:var(--muted)}
.gw-breadcrumbs a:hover{color:var(--ink)}
/* --line-2 is a hairline colour; as a glyph it measured 1.43:1 and the crumb
   read as "Home Cases" with no separator. --faint then measured 2.71:1, still
   under AA. It is aria-hidden decoration so this is a legibility call rather
   than a conformance one, but at 2.71 the slash was nearly invisible, so it
   now shares --muted with the crumb links (5.0:1). */
.gw-crumb-sep{margin:0 8px;color:var(--muted)}
/* A grouping segment such as /site-services has no page of its own, so its
   crumb keeps the label and loses the link. Same colour as the links so the
   trail still reads as one line, but no pointer and no underline on hover. */
.gw-crumb-group{color:var(--muted);cursor:default}
.gw-crumb-current{color:var(--ink-2)}

/* --------------------------------------------------------------------------
   5. Section shell + typography
   -------------------------------------------------------------------------- */
section{position:relative}
/* .gw-cgc is the case-grid wrapper in _sections.html. It was never listed
   here, so the home page case strip rendered with zero vertical padding and
   its last row of cards sat flush against the section boundary. */
.gw-txt,.gw-cg,.gw-cgc,.gw-pg,.gw-cap,.gw-ind,.gw-feat,.gw-faq,.gw-spec,.gw-stat,
.gw-it,.gw-cta-band,.gw-ls,.gw-section{
  padding:clamp(64px,8.5vw,124px) 0;
}
.gw-t-alt{background:var(--bg-soft)}
.gw-t-dark{background:var(--bg-soft)}
/* `soft` and `paper` exist because the theme string was doing two jobs at once: it
   picked the background, and for `alt` it also moved the photograph into the second
   column. The home page needed one block with a soft background and the photograph
   still on the left, and one with a white background and the photograph on the
   right, and no existing value gave either. Rather than change what `alt` means --
   five blocks on four other pages would have silently swapped sides -- these are new
   values that only the two home blocks use. */
.gw-t-soft{background:var(--bg-soft)}
/* A cut-out is delivered on #f7f7f7, and --bg-soft is #f6f6f3 -- one level apart.
   The product grid already hides that by painting its tile #f7f7f7; an image-text
   block had nothing behind the picture, so the backdrop sat four levels off the
   section and left a faint rectangle the size of the photograph. Matching the
   wrapper to the backdrop closes it to zero. Real photographs fill the wrapper
   completely, so the colour never shows behind one. */
.gw-it.gw-t-soft .gw-it-media{background:#f7f7f7}
/* A brand band paints the section #10069f. Every component in this file reads
   its text and rule colours from the light-theme tokens (--ink / --muted /
   --faint / --line) instead of hardcoding a hex, so re-pointing those tokens on
   the section fixes the whole subtree at once.
   Without this, .gw-feat-t rendered #15161a on #10069f -- measured 1.33:1, i.e.
   the row titles were invisible -- and .gw-feat-b sat at 2.7:1. The same bug
   hit .gw-card-title inside the brand bands on /products and /news, and
   .gw-ind-l on /news. Overriding per class would have to be repeated for every
   component added later; the tokens cannot be missed. */
.gw-t-brand{
  background:var(--indigo);color:rgba(255,255,255,.86);
  --ink:#fff;
  --ink-2:rgba(255,255,255,.92);
  --muted:rgba(255,255,255,.78);
  --faint:rgba(255,255,255,.55);
  --line:rgba(255,255,255,.22);
  --line-2:rgba(255,255,255,.34);
  --bg-soft:rgba(255,255,255,.07);
  --accent:rgba(255,255,255,.72);
}
.gw-t-brand .gw-h2,.gw-t-brand h2,.gw-t-brand h3{color:#fff}
.gw-t-brand .gw-lead{color:rgba(255,255,255,.82)}

.gw-h2{
  font-size:clamp(1.85rem,3.1vw,2.85rem);line-height:1.08;letter-spacing:-.028em;
  color:var(--ink);font-weight:300;margin:0;
}
.gw-lead{
  font-size:clamp(1rem,1.3vw,1.12rem);line-height:1.72;color:var(--muted);
  font-weight:300;max-width:760px;margin-top:20px;
}
.gw-lead-c{margin-left:auto;margin-right:auto;text-align:center}
.gw-sechead{display:flex;align-items:flex-end;justify-content:space-between;gap:40px;flex-wrap:wrap;margin-bottom:12px}
.gw-rich{color:var(--muted);font-size:.98rem;line-height:1.8;margin-top:22px;max-width:760px}
.gw-rich p{margin-bottom:18px}
.gw-rich p:last-child{margin-bottom:0}
.gw-rich a{color:var(--accent);border-bottom:1px solid rgba(16,6,159,.3)}
.muted{color:var(--muted)}
.prose{max-width:760px;font-size:1rem;line-height:1.85;color:var(--ink-2)}
.prose p{margin-bottom:22px}
/* Inline links inside an article body. The global a{color:inherit;
   text-decoration:none} leaves a link here the same colour as the sentence
   around it and with no underline, so it reads as plain text. Same idiom as
   .pd-copy-in a: ink, hairline underline, accent on hover. */
.prose a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--line-2);transition:color .2s,border-color .2s}
.prose a:hover{color:var(--accent);border-bottom-color:var(--accent)}
.prose h2{font-size:clamp(1.4rem,2.2vw,1.9rem);margin:42px 0 16px;font-weight:300}
.prose h3{font-size:1.1rem;font-weight:500;margin:30px 0 10px;color:var(--ink)}
.prose ul{margin:0 0 22px 20px;list-style:disc}
.prose li{margin-bottom:8px}
/* Markdown tables in article bodies. The markdown filter emits a bare <table>
   with no class, so the class-based rules below it never matched: cells sat
   against each other with no rules and no gutters. Measurements are copied from
   .gw-spec-table so an article table and a spec table read as one component. */
.prose table{width:100%;border-collapse:collapse;margin:30px 0 34px;font-size:.9rem;line-height:1.6}
.prose th,.prose td{text-align:left;padding:12px 18px 12px 0;border-bottom:1px solid var(--line);vertical-align:top}
.prose th{color:var(--muted);font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;font-weight:400}
.prose td{color:var(--ink);font-variant-numeric:tabular-nums}
.prose thead tr:first-child th{border-top:1px solid var(--line)}
@media(max-width:560px){
  .prose th,.prose td{padding:10px 10px 10px 0;font-size:.82rem}
  .prose th{letter-spacing:.06em}
}
body.is-rtl .prose th,body.is-rtl .prose td{text-align:right;padding-left:18px;padding-right:0}

/* buttons */
.gw-btn{
  display:inline-flex;align-items:center;gap:10px;padding:13px 26px;
  border:1px solid var(--ink);border-radius:100px;color:var(--ink);
  font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;
  transition:background .2s,color .2s,border-color .2s;background:none;
}
.gw-btn:hover{background:var(--ink);color:#fff}
.gw-btn-ghost{border-color:var(--line-2);color:var(--ink-2)}
.gw-btn-ghost:hover{background:none;border-color:var(--ink);color:var(--ink)}
.gw-btn-solid{background:var(--indigo);border-color:var(--indigo);color:#fff}
.gw-btn-solid:hover{background:var(--accent-ink);border-color:var(--accent-ink);color:#fff}
.gw-btn-outline{border-color:var(--indigo);color:var(--indigo)}
.gw-btn-outline:hover{background:var(--indigo);color:#fff}
.gw-btn-lg{padding:15px 30px;font-size:.8rem}
.gw-more{margin-top:44px}
.gw-t-brand .gw-btn{border-color:rgba(255,255,255,.75);color:#fff}
.gw-t-brand .gw-btn:hover{background:#fff;color:var(--indigo)}

/* --------------------------------------------------------------------------
   6. Text section
   -------------------------------------------------------------------------- */
/* heading left, body right — the editorial two-column measure used across the
   site, so a long paragraph never runs the full 1280px */
.gw-txt-in{
  max-width:var(--maxw);
  display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  column-gap:clamp(36px,5.5vw,88px);row-gap:clamp(24px,3vw,40px);align-items:start;
}
.gw-txt-in > .gw-h2,
.gw-txt-in > h2{margin:0;max-width:15ch}
.gw-txt-cols{margin-top:0}
.gw-txt-cols .gw-lead{
  max-width:none;color:var(--ink-2);
  font-size:clamp(1.02rem,1.32vw,1.16rem);line-height:1.74;letter-spacing:-.004em;
}
.gw-txt-cta{margin-top:0;grid-column:2}
.gw-txt-in > :only-child{grid-column:1/-1}

/* image + text split */
.gw-it{padding:clamp(56px,7vw,104px) 0}
.gw-it-in{
  max-width:var(--maxw);margin:0 auto;padding:0 var(--pad);
  display:grid;grid-template-columns:1.04fr .96fr;gap:clamp(32px,5.5vw,88px);align-items:center;
}
.gw-it-media img{width:100%;height:clamp(320px,42vw,540px);object-fit:cover;filter:saturate(.85)}
/* Two image-text blocks can end up adjacent (the oil samples and the membrane
   copy do). Both had the photograph on the left, so the pair read as the same
   block printed twice. Flipping the media side on the alt-theme one makes the
   two alternate without either template or content changing. */
.gw-it.gw-t-alt .gw-it-media{order:2}
/* The same flip, for a block that wants a white background rather than --bg-soft. */
.gw-it.gw-t-paper .gw-it-media{order:2}
/* The sample photograph is a four-bottle line-up on a plain backdrop, and the
   line runs from black to clear -- cropping either end destroys the argument.
   At the shared fixed height the panel came out 507x460 (AR 1.1) against a 4:3
   source, so cover ate 53px off each side and cut through the outer bottles.
   Letting the panel take the photo's own ratio means cover has nothing to
   remove, at any viewport width. aspect-ratio on the image itself rather than a
   percentage height on a wrapper: the wrapper has no definite height, so a
   percentage would not resolve. */
#home_samples .gw-it-media img{height:auto;aspect-ratio:4/3;object-fit:cover}
/* The membrane block holds a 900x900 cut-out of a tall machine. Under the shared
   rule (height clamp(320px,42vw,540px), cover) the panel was 562x540 on desktop and
   fine, but at 768px -- still single-column -- it became 704x323, an aspect of 2.18
   against a 1:1 source, and cover threw away 54% of the machine's height. The unit
   was cut in half on the one width where the picture is largest. A square panel
   gives cover nothing to remove, at every width. */
#home_core_tech .gw-it-media img{height:auto;aspect-ratio:1/1;object-fit:cover}
/* Same reason as the two above. The workshop frame is 4:3; the shared panel is
   590x540 (AR 1.09), so cover was taking 65px off each side -- through the trolley
   wheels and the end caps of the membrane skid, which are the part of the picture
   that says what the skid is. Panel takes the source ratio instead. */
#about_profile .gw-it-media img{height:auto;aspect-ratio:4/3;object-fit:cover}
/* /about now carries four photographs and none of them is a product cut-out, so all
   four need the same treatment: take the panel to the picture's ratio instead of
   cropping the picture into a fixed panel. The shared rule would give the lab frame
   (16:9) a 590x540 box and slice 12% off each side, which is where the second
   technician stands. */
#about_positioning .gw-it-media img,
#about_rd .gw-it-media img{height:auto;aspect-ratio:4/3;object-fit:cover}
/* Both new photo blocks are the only two-column blocks on the page where the
   picture carries the argument, and at the shared 1.04/.96 split the picture
   came out 507px wide inside a 1064px container -- a third of the row for the
   thing the block exists to show. 1.28/.72 gives the picture 635px and leaves
   the copy a 357px measure, which is a comfortable line length.
   Scoped to min-width 901 because the single-column rule lives in a 560px
   query and an ID selector would otherwise outrank it. */
@media (min-width:901px){
  /* Column widths are written per block because order changes which cell each
     child lands in. The media wrapper is the first DOM child on both blocks;
     the samples block pushes it right with order:2, so it takes the SECOND
     column, and the wide track has to be the second one there and the first
     one on the workshop block. Getting this backwards gave the photograph 394px
     and the paragraph 700px -- the exact opposite of the intent.

     1.16/.84 rather than 1.28/.72: at 1.28 the picture took 700px and the copy
     was squeezed to 394, which broke the heading across two lines in the middle
     of a phrase and left the paragraph as a narrow column beside a wall of
     photo. 634/460 is the same picture at a size that still carries, with a
     measure the heading fits. */
  #home_samples .gw-it-in{grid-template-columns:.84fr 1.16fr;gap:clamp(32px,4.5vw,72px)}
  /* The workshop block moved to the alt theme, which flips the photograph into
     the second column. The wide track has to move with it -- 1.16/.84 with the
     picture on the right hands 700px to the paragraph and 394px to the photo,
     which is the exact opposite of the intent. */
  #home_workshop .gw-it-in{grid-template-columns:.84fr 1.16fr;gap:clamp(32px,4.5vw,72px)}
}
/* Both headings in these blocks are one clause; letting the browser balance the
   break keeps "before and after" together instead of leaving "before" stranded. */
#home_samples .gw-h2,
#home_workshop .gw-h2{text-wrap:balance}
#home_workshop .gw-it-media img{height:auto;aspect-ratio:3/2;object-fit:cover}
.gw-it-text .gw-lead{max-width:460px}
/* the CTA sits in its own <p> straight after the lead; with no rule for it the
   button was touching the last line of the paragraph */
.gw-it-text > p:not(.gw-lead){margin-top:30px}
/* Three of these on the home page, at 104px of padding top and bottom each,
   put 624px of air between the photographs. The blocks are meant to read as
   one argument -- samples, technology, build floor -- so they are tightened to
   80 and the sequence closes up. */
#home_samples,#home_core_tech,#home_workshop{padding:clamp(46px,5.4vw,80px) 0}
/* The membrane block holds a product cut-out, and a cut-out is delivered on
   #f7f7f7 while --bg-soft is #f6f6f3. Four levels apart in one channel is
   enough to see the edge of a square that is meant to be invisible: the machine
   appeared to sit in a very faint box the size of the photograph. Painting the
   section the cut-out's own colour removes the box and leaves just the machine.
   Real photographs fill their wrapper, so this only matters on this block. */
#home_core_tech{background:#f7f7f7}

/* --------------------------------------------------------------------------
   7. Cards (gw-card) — editorial, hairline, no boxes
   -------------------------------------------------------------------------- */
.gw-cg-grid{
  display:grid;gap:0 clamp(32px,4.6vw,72px);margin-top:clamp(34px,4.5vw,56px);
  grid-template-columns:repeat(3,1fr);
}
.gw-cg-grid[data-cols="2"]{grid-template-columns:repeat(2,1fr)}
.gw-cg-grid[data-cols="4"]{grid-template-columns:repeat(4,1fr)}
.gw-card{
  display:flex;flex-direction:column;padding:clamp(24px,3vw,38px) 0 0;
  border-top:1px solid var(--line);background:none;color:inherit;
  transition:opacity .25s;
}
.gw-card:hover{opacity:.82}
.gw-card-media{display:block;overflow:hidden;background:var(--bg-soft);margin-bottom:22px}
.gw-card-media img{width:100%;height:clamp(190px,17vw,260px);object-fit:cover;filter:saturate(.85);transition:transform .7s ease}
/* There used to be a mix-blend-mode:multiply here, on the theory that the
   product cut-outs came on two different backdrops (#ffffff and #f7f7f7) and
   that multiplying would map both onto the section colour. Sampling every
   product image showed the premise was wrong: all of them are #f7f7f7, and the
   .gw-pg tile is already #f7f7f7, so the blend had nothing to reconcile.
   What it did instead was multiply 247 by 247 and render the tile at 239 on a
   246 section -- a grey rectangle where there had been a 1-level difference
   nobody could see. Removed. Verified by reading the composited pixels out of
   a screenshot, not by reading computed style: see _logo/sample_png.py. */
/* Product shots are 900x900 cut-outs on a flat #f7f7f7 backdrop. `cover` into a
   wide tile sliced the machine frames off at the edges, so the tile is square
   and the photo is contained, on the exact backdrop colour -- no visible
   rectangle inside the tile, and the whole machine at full size. */
.gw-pg .gw-card-media{background:#f7f7f7;height:auto;aspect-ratio:1/1}
.gw-pg .gw-card-media img{object-fit:contain;height:100%}
.gw-pg .gw-card:hover .gw-card-media img{transform:none}
.gw-card:hover .gw-card-media img{transform:scale(1.025)}

/* --- The home product grid, as a catalogue plate --------------------------
   Measured 1423px on a 1440 viewport. The length was never the problem; the
   tiles were. A cut-out is delivered on #f7f7f7 and this section is #f6f6f3 --
   four levels apart in the blue channel and nothing in the other two -- so the
   tile had no edge at all and six machines appeared to float in an empty field,
   each with 350px of nothing around it.
   One hairline gives the plate a frame and costs no height.
   A border, not an outline and not an inset shadow. Both of those were tried and
   both were painted *under* the picture: the image is object-fit:contain at
   height:100%, so it covers the whole box, and Chrome paints an element's
   outline before its descendants. A 4px red outline measured zero red pixels in
   the screenshot. A border cannot be covered, because it takes the space first --
   the image drops to 354x354 inside a 356px tile and the 1px of #f7f7f7 that
   shows through is the same colour as the cut-out's own backdrop. */
#home_products{padding:clamp(52px,5.8vw,88px) 0 clamp(56px,6.4vw,96px)}
#home_products .gw-cg-grid{gap:0 clamp(26px,3.2vw,50px);margin-top:clamp(28px,3.4vw,42px)}
#home_products .gw-card{padding-top:clamp(18px,2vw,26px)}
#home_products .gw-card-media{border:1px solid var(--line)}

.gw-card-body{display:block}
.gw-card-tag{
  /* Flex with the text pushed to the bottom of the reserved block, so a
     one-line label still sits 10px above its title and the slack lands between
     the photo and the label instead. */
  display:flex;align-items:flex-end;
  font-size:.68rem;letter-spacing:.15em;text-transform:uppercase;
  /* 10.9px at --faint measured 2.5:1 on the soft card background. Uppercase
     micro-type at that size needs the darker token to stay readable. */
  color:var(--muted);margin-bottom:10px;
  /* The labels are two-part ("Water / oil-film bearing oil"), so they run to
     one line in some cards and two in others -- and a wrapped label pushed its
     card's title 19px below the neighbours' in the same row. Reserving two
     lines makes every title in a row start on the same baseline, in every
     language, without depending on the copy being short. line-height is set
     explicitly so 2.7em is exactly two lines and not an estimate. */
  line-height:1.35;min-height:2.7em;
}
.gw-card-title{
  display:block;font-size:clamp(1.05rem,1.45vw,1.28rem);font-weight:300;line-height:1.28;
  color:var(--ink);letter-spacing:-.014em;
  /* Three wrapping modes were measured on the three home case titles by pulling the
     real line boxes out of the DOM, and natural wrapping won:
       wrap     "Phosphate-ester fire-resistant oil —" / "captive power station"
                "Hydraulic oil emulsified by water" / "ingress — steel plant, south-west" / "China"
       pretty   ...same, but breaks "south-west" as "south-" / "west China" -- worse
       balance  "Phosphate-ester fire-resistant" / "oil — captive power station"
                -- it removes the lone "China" and splits the technical term instead
     A one-word last line is a small blemish; splitting "fire-resistant oil" is a
     misreading risk for someone scanning for the fluid. Left natural. */}
.gw-card-text{display:block;font-size:.875rem;color:var(--muted);line-height:1.62;margin-top:10px}
.gw-card:hover .gw-card-title{color:var(--accent)}
/* The tag above reserves two lines for exactly this reason, but the title did not,
   and the title is the one that varies most: the three cards on the home page run
   to 2 / 1 / 2 lines in English and 3 / 2 / 4 in Russian. So the summary under
   each one began at a different height, and a row of three columns that do not
   line up reads as three unrelated blocks -- the commonest sign of a grid nobody
   looked at after it was filled.
   A fixed min-height cannot fix it: the right number is different in every
   language and it goes stale the first time a case is renamed. Subgrid can,
   because the title row and the summary row become shared, so both align to
   whatever the tallest title in the row happens to be, in any language, without
   pinning a height.
   Scoped to #home_cases on purpose. It is the only case grid on the site with no
   images, so there is exactly one row of tracks to share; a grid that also
   carries .gw-card-media would need three and this rule would misplace them.
   Where subgrid is unsupported the block falls back to the old ragged behaviour
   rather than breaking. */
@supports (grid-template-rows:subgrid){
  /* Three tracks, not two. This block used to hold text only, so a card was
     [title, summary]; the cases now carry their own photograph, which makes it
     [media, title, summary]. Left at two tracks the third child fell into an
     implicit row and the summary printed straight through the title -- visible
     in the render, not in any error. Every published case has a hero_image, so
     three is the right count for this grid. */
  #home_cases .gw-cg-grid{grid-template-rows:auto auto auto}
  #home_cases .gw-cg-grid .gw-card{
    grid-row:span 3;display:grid;grid-template-rows:subgrid;align-content:start;
  }
  /* .gw-card-body is display:block and carries no box of its own, so dissolving it
     hands the title and the summary straight to the card's tracks. */
  #home_cases .gw-cg-grid .gw-card-body{display:contents}
}
/* The case photographs are 800x600, and the shared card rule puts every image in
   a 245px-tall panel -- 1.45:1 -- so cover was trimming 17% off the top and
   bottom of each one, through the necks of the bottles that are the evidence.
   The panel takes the file's own ratio instead. */
#home_cases .gw-card-media img{height:auto;aspect-ratio:4/3;object-fit:cover}
/* The evidence block is the one section on the page with no photograph, so it
   reads as a pause. A pause does not need 122px above and below it. */
#home_cases{padding:clamp(52px,5.8vw,88px) 0}

/* --------------------------------------------------------------------------
   8. Stat strip (content kept, presentation calmed)
   -------------------------------------------------------------------------- */
.gw-stat{padding:clamp(44px,5.5vw,72px) 0;border-bottom:1px solid var(--line)}
.gw-stat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(20px,3vw,48px)}
.gw-stat-item{border-top:1px solid var(--line);padding-top:20px}
.gw-stat-v{
  display:block;font-size:clamp(1.3rem,1.9vw,1.62rem);font-weight:400;line-height:1.1;
  color:var(--ink);letter-spacing:-.01em;font-variant-numeric:tabular-nums;
}
.gw-stat-l{
  display:block;font-size:.8rem;letter-spacing:.01em;line-height:1.55;
  color:var(--muted);margin-top:10px;text-transform:none;max-width:230px;
}

/* news listing — a dated corporate index, not a blog card grid */
.news-grid{display:block;margin-top:clamp(24px,3vw,40px)}
/* The card is a block; the two-column split lives on .news-body. Putting the
   grid on the card meant the date/title block was the only grid child once the
   thumbnail was hidden, so it fell into the 190px column and the headline
   wrapped every two words. */
.news-grid > .news-card{
  display:block;
  border-top:1px solid var(--line);padding:clamp(20px,2.4vw,30px) 0;background:none;
}
.news-grid > .news-card .news-body{
  display:grid;grid-template-columns:190px minmax(0,1fr);
  gap:clamp(16px,2.4vw,44px);align-items:start;
}
.news-grid > .news-card .news-body > small.muted{grid-column:1;grid-row:1 / span 2}
.news-grid > .news-card .news-body > h2{grid-column:2;grid-row:1}
.news-grid > .news-card .news-body > p{grid-column:2;grid-row:2}
.news-grid > .news-card .news-img{display:none}
.news-grid > .news-card .news-body h2{
  font-size:clamp(1.05rem,1.45vw,1.24rem);line-height:1.34;font-weight:400;max-width:760px;
}
.news-grid > .news-card .news-body p{max-width:660px;margin-top:9px;font-size:.9rem;line-height:1.66}
.news-grid > .news-card .news-body small.muted{
  display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;
  /* 11.5px uppercase at --faint measured 2.71:1. This is the only line telling
     the reader the category and date, so it has to clear AA. */
  color:var(--muted);line-height:1.7;font-variant-numeric:tabular-nums;
}

/* --------------------------------------------------------------------------
   9. Industry index (21 items) — hairline numbered index
   -------------------------------------------------------------------------- */
.gw-ind-grid{
  display:grid;grid-template-columns:repeat(4,1fr);gap:0;
  margin-top:clamp(32px,4vw,48px);border-top:1px solid var(--line);
}
.gw-ind-item{
  display:flex;align-items:baseline;gap:12px;
  padding:16px 18px 16px 0;border-bottom:1px solid var(--line);
}
.gw-ind-n{font-size:.7rem;color:var(--muted);letter-spacing:.1em;font-variant-numeric:tabular-nums;flex:0 0 auto}
.gw-ind-l{font-size:.94rem;color:var(--ink-2);line-height:1.4}
.gw-ind-a{display:none}
/* The industry index is the only block on the home page that carries neither a
   photograph nor a number worth reading -- eight names and eight counters. On
   the soft grey it read as a footnote between two picture blocks. On ink it
   becomes the hinge of the page: the product half above, the evidence half
   below, and the eye gets a change of tone exactly where the subject changes.
   The theme value was already "dark" in the CMS; the token it mapped to was
   the same --bg-soft as "alt", so nothing showed. */
.gw-ind.gw-t-dark{background:var(--ink)}
.gw-ind.gw-t-dark .gw-h2{color:#fff}
.gw-ind.gw-t-dark .gw-lead{color:rgba(255,255,255,.56)}
.gw-ind.gw-t-dark .gw-ind-grid{border-top-color:rgba(255,255,255,.18)}
.gw-ind.gw-t-dark .gw-ind-item{border-bottom-color:rgba(255,255,255,.14);padding-top:20px;padding-bottom:20px}
.gw-ind.gw-t-dark .gw-ind-n{color:rgba(255,255,255,.4)}
/* 15px names on a full-bleed ink band read as a caption; the band is the hinge
   of the page, so the names carry a little more weight than they did on grey. */
.gw-ind.gw-t-dark .gw-ind-l{color:rgba(255,255,255,.9);font-size:1.02rem}

/* The band was a menu that was not one: every item rendered as a <div>, because
   no item carried a url, so eight names sat under a heading looking exactly like
   navigation and did nothing when pressed. Seven of them now point at industry
   landing pages that already exist (/cases/steel ... /cases/rail) and the eighth
   at the full case index. The arrow is the only affordance the row needs -- it
   is hidden on any item that still has no destination, so the rule degrades
   honestly instead of promising a link that is not there. */
.gw-ind-item[href] .gw-ind-a{
  /* Immediately after the label, not pushed to the cell's right edge. Right
     aligned, the arrow landed 18px from the NEXT cell's counter and the row read
     "Steel industry -> 02 Power generation". Inline, it belongs to the name it
     follows, and the gap between cells is the only thing between them. */
  display:block;margin-left:9px;font-size:.88rem;line-height:1;
  color:var(--faint);transition:transform .25s,color .25s;
}
.gw-ind.gw-t-dark .gw-ind-item[href] .gw-ind-a{color:rgba(255,255,255,.42)}
.gw-ind-item[href]:hover .gw-ind-a{transform:translateX(5px);color:var(--ink)}
.gw-ind.gw-t-dark .gw-ind-item[href]:hover .gw-ind-a{color:#fff}
.gw-ind.gw-t-dark .gw-ind-item[href]:hover .gw-ind-l{color:#fff}
/* The last cell is the way out to the full index rather than an eighth industry,
   so it keeps the arrow and drops the counter's emphasis. */
.gw-ind.gw-t-dark .gw-ind-item[href]:last-child .gw-ind-l{color:rgba(255,255,255,.62)}

/* --------------------------------------------------------------------------
   10. Feature rows
   -------------------------------------------------------------------------- */
.gw-feat-list{margin-top:clamp(30px,4vw,44px);border-top:1px solid var(--line)}
.gw-feat-item{
  display:grid;grid-template-columns:90px 1fr 1.15fr;gap:clamp(16px,3vw,44px);
  padding:clamp(20px,2.4vw,30px) 0;border-bottom:1px solid var(--line);align-items:start;
}
.gw-feat-n{font-size:.74rem;letter-spacing:.12em;color:var(--muted);font-variant-numeric:tabular-nums;padding-top:4px}
.gw-feat-t{font-size:clamp(1.05rem,1.5vw,1.25rem);font-weight:300;color:var(--ink);line-height:1.3}
.gw-feat-b{font-size:.88rem;color:var(--muted);line-height:1.65}

/* --------------------------------------------------------------------------
   11. Spec table
   -------------------------------------------------------------------------- */
.gw-spec-in{max-width:var(--maxw)}
.gw-spec-table{width:100%;border-collapse:collapse;margin-top:clamp(26px,3.4vw,40px)}
.gw-spec-table th,.gw-spec-table td{
  text-align:left;padding:14px 18px 14px 0;border-bottom:1px solid var(--line);
  font-size:.9rem;font-weight:400;vertical-align:top;
}
.gw-spec-table th{color:var(--muted);font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;width:34%}
.gw-spec-table td{color:var(--ink)}
.gw-spec-table tr:first-child th,.gw-spec-table tr:first-child td{border-top:1px solid var(--line)}

/* --------------------------------------------------------------------------
   12. FAQ
   -------------------------------------------------------------------------- */
.gw-faq-list{margin-top:clamp(28px,3.6vw,44px);border-top:1px solid var(--line)}
/* The markup is <details class="gw-faq-q"><summary>question</summary><div
   class="gw-faq-a">answer</div></details>, but these rules were written for a
   div-based accordion: display:flex with space-between went on the <details>
   itself, which made the <summary> one flex item and the answer another, side by
   side. The <summary> then had no padding and no font-size of its own, so it kept
   the browser's default marker -- measured on /contact at 390px: a black triangle,
   a 28px row, question text pushed past the container's left edge, and no
   plus/chevron at all because .gw-faq-ic is an empty span with nothing to draw.
   Styling the summary instead gives the row its padding, its size, its 44px+
   tap target and no marker; the answer goes back to being a block underneath. */
.gw-faq-q{padding:0;border-bottom:1px solid var(--line);cursor:default}
.gw-faq-q > summary{
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:20px 0;cursor:pointer;font-size:clamp(1rem,1.3vw,1.12rem);
  color:var(--ink);font-weight:400;list-style:none;
}
.gw-faq-q > summary::-webkit-details-marker{display:none}
.gw-faq-q > summary::marker{content:""}
/* the empty span needs a shape: a 14px plus that rotates to a cross when open */
.gw-faq-ic{
  position:relative;flex:0 0 auto;width:14px;height:14px;
  color:var(--faint);transition:transform .25s;
}
.gw-faq-ic::before,.gw-faq-ic::after{content:"";position:absolute;background:currentColor}
.gw-faq-ic::before{left:0;top:6.5px;width:14px;height:1px}
.gw-faq-ic::after{left:6.5px;top:0;width:1px;height:14px}
.gw-faq-q[open] .gw-faq-ic{transform:rotate(45deg)}
.gw-faq-a{padding:0 0 22px;color:var(--muted);font-size:.92rem;line-height:1.8;max-width:760px}

/* --------------------------------------------------------------------------
   13. Capability chips
   -------------------------------------------------------------------------- */
.gw-cap{padding:clamp(40px,5vw,64px) 0;border-bottom:1px solid var(--line)}
.gw-cap-in{display:flex;flex-wrap:wrap;gap:10px 12px}
.gw-chip{
  display:inline-flex;align-items:center;padding:9px 16px;
  border:1px solid var(--line-2);border-radius:100px;
  font-size:.78rem;color:var(--ink-2);background:none;
}

/* --------------------------------------------------------------------------
   14. Signpost band (.gw-ls) — colour preserved from the source site
   -------------------------------------------------------------------------- */
.gw-cta{padding:0;margin:0;background:var(--bg-soft)}
.gw-cta-inner{
  max-width:var(--maxw);margin:0 auto;padding:clamp(46px,5.5vw,76px) var(--pad);
  display:flex;align-items:center;justify-content:space-between;gap:40px;flex-wrap:wrap;
}
.gw-cta-inner h2{font-size:clamp(1.4rem,2.4vw,2rem);font-weight:300;line-height:1.15}
.gw-cta-inner p{color:var(--muted);font-size:.94rem;line-height:1.7;margin-top:12px;max-width:520px}
.gw-cta-inner .gw-hero-cta{border-color:var(--ink);color:var(--ink);margin:0}
.gw-cta-inner .gw-hero-cta:hover{background:var(--ink);color:#fff}
/* the signpost escapes the container to the viewport edge */
.gw-cta:has(.gw-ls){background:none}
.gw-cta:has(.gw-ls) .gw-cta-inner{max-width:none;padding:0;display:block}
.gw-ls,.gw-ls.single-large-signpost{
  display:grid;grid-template-columns:1fr 1fr;align-items:stretch;
  padding:0;margin:0;min-height:clamp(320px,34vw,460px);
  background:var(--pink);color:#fff;width:100%;
}
.gw-ls .gw-ls-media{
  order:2;min-height:clamp(260px,30vw,440px);
  background-size:cover;background-position:center;
}
.gw-ls[data-pos="left"] .gw-ls-media{order:1}
.gw-ls .gw-ls-content{order:1;display:flex;align-items:center}
.gw-ls[data-pos="left"] .gw-ls-content{order:2}
.gw-ls .gw-ls-text{
  padding:clamp(44px,6vw,84px) clamp(24px,4vw,64px);
  padding-left:max(var(--pad),calc((100vw - var(--maxw))/2 + var(--pad)));
  max-width:640px;
}
.gw-ls[data-pos="left"] .gw-ls-text{
  padding-left:clamp(24px,4vw,64px);
  padding-right:max(var(--pad),calc((100vw - var(--maxw))/2 + var(--pad)));
}
.gw-ls-h{color:#fff;font-size:clamp(1.75rem,3vw,2.6rem);line-height:1.07;letter-spacing:-.028em;font-weight:300}
.gw-ls-text > p{color:rgba(255,255,255,.92);font-size:.98rem;line-height:1.68;margin-top:18px;max-width:440px}
.gw-ls-act{margin-top:30px}
/* .7 white on #fa4692 is 3.0:1 -- the smallest type on the page at the lowest
   contrast. .82 puts it level with the body copy; the pink itself is the
   ceiling here, see the note on .gw-cta-note. */
.gw-ls-note{color:rgba(255,255,255,.82)!important;font-size:.76rem!important;margin-top:16px}
.gw-ls .gw-btn,.gw-ls .gw-btn-ghost,.gw-ls .gw-btn-solid{
  border:1px solid #fff;background:#fff;color:var(--ink);
}
.gw-ls .gw-btn:hover,.gw-ls .gw-btn-ghost:hover,.gw-ls .gw-btn-solid:hover{
  background:transparent;color:#fff;
}
/* Same specificity trap as .gw-ls-alt: the shared rule above is written
   .gw-ls.single-large-signpost (0,2,0), and the template always emits both
   classes, so a single-class variant never wins. Written with both forms. */
.gw-ls-blue,.gw-ls-blue.single-large-signpost{background:var(--indigo)}

/* The pink band keeps its brand colour, so the only lever left is the type.
   Measured on #fa4692: white is 3.33:1 at every size, which clears AA for the
   32px heading (large text needs 3:1) but fails the 15.7px body and the 12px
   note. Those two go to dark wine -- 5.46:1 and 4.90:1 on the same pink -- and
   the heading stays white, so the block still reads as "pink band, white
   headline", which is the part the brand carries.
   Scoped with :not(.gw-ls-blue) because the indigo variant already measures
   8.6:1 with white type and must not be touched. The note rule carries
   !important to beat .gw-ls-note's own !important above. */
.gw-ls:not(.gw-ls-blue):not(.gw-ls-paper) .gw-ls-text > p{color:#2a0a18}
.gw-ls:not(.gw-ls-blue):not(.gw-ls-paper) .gw-ls-note{color:#3a1220!important}
.gw-ls-pink,.gw-ls-pink.single-large-signpost{background:var(--pink)}

/* The paper variant exists because the pink band is a brand surface, not a
   layout device. On /solutions it sat directly on top of the indigo footer --
   #fa4692 over #10069f, two saturated blocks with no seam between them -- and
   it was the page's second call to action, 40px above the contact details
   repeated in the footer. As a white panel the block still carries "five
   details to size a unit" without shouting over the footer it touches.
   White rather than --bg-soft because the photograph on the left is shot on a
   white backdrop: on #f6f6f3 the two whites met at a visible vertical seam
   down the middle of the block, which read as a rendering fault rather than a
   design edge.
   .gw-ls hardcodes white for the button and the note, so both are re-pointed
   here; that block never reads the colour tokens. */
.gw-ls-paper,.gw-ls-paper.single-large-signpost{background:#fff}
.gw-ls-paper .gw-ls-h{color:var(--ink)}
.gw-ls-paper .gw-ls-text > p{color:var(--muted)}
.gw-ls-paper .gw-ls-note{color:var(--muted)!important}
.gw-ls-paper .gw-btn,.gw-ls-paper .gw-btn-ghost,.gw-ls-paper .gw-btn-solid{
  border:1px solid var(--ink);background:var(--ink);color:#fff;
}
.gw-ls-paper .gw-btn:hover,.gw-ls-paper .gw-btn-ghost:hover,.gw-ls-paper .gw-btn-solid:hover{
  background:transparent;color:var(--ink);
}
.fw-signpost-light,.fw-signpost-light.single-large-signpost{background:var(--bg-soft);color:var(--ink)}
.fw-signpost-light .gw-ls-h{color:var(--ink)}
.fw-signpost-light .gw-ls-text > p{color:var(--muted)}
.fw-signpost-light .gw-btn{border-color:var(--ink);background:none;color:var(--ink)}

/* --------------------------------------------------------------------------
   15. CTA band
   -------------------------------------------------------------------------- */
.gw-cta-band{background:var(--indigo);color:#fff;padding:clamp(48px,6vw,76px) 0}
.gw-cta-band-in{display:flex;align-items:center;justify-content:space-between;gap:40px;flex-wrap:wrap}
.gw-cta-band-txt h2,.gw-cta-band-txt .gw-h2{color:#fff;font-size:clamp(1.5rem,2.5vw,2.1rem)}
/* White on #fa4692 is 3.3:1 at best, so the small print here can never reach
   AA without either darkening the pink (which is a brand colour, deliberately
   kept) or switching to dark type. Raising the note to the same weight as the
   body at least stops it looking disabled. */
.gw-cta-note{color:rgba(255,255,255,.82);font-size:.9rem;margin-top:10px;max-width:520px}
.gw-cta-band-act{flex:0 0 auto}
.gw-cta-band .gw-btn{border-color:rgba(255,255,255,.75);color:#fff}
.gw-cta-band .gw-btn:hover{background:#fff;color:var(--indigo)}

/* --------------------------------------------------------------------------
   16. Products grid
   -------------------------------------------------------------------------- */
.products-grid-section{padding:clamp(40px,5.5vw,76px) 0 clamp(56px,7vw,96px)}
.products-grid{
  display:grid;grid-template-columns:1fr 1fr;gap:0 clamp(36px,5vw,84px);
}
.product-card{border-top:1px solid var(--line);padding:clamp(24px,3.2vw,42px) 0;margin:0;background:none}
/* Every card in a row stretches to the tallest one, so the arrow can be pinned
   to the bottom of the card rather than following the summary to wherever it
   happens to end. It used to follow: a card whose title ran to two lines put
   "View details" 88px below the card beside it, and a two-column grid of
   fifteen products had fifteen arrows at fifteen different heights. Measured on
   the render -- the first two cards on /products, 88px apart. */
.product-card{display:flex}
.product-card-link{display:flex;flex-direction:column;flex:1 1 auto;color:inherit}
/* Product shots are 900x900 cut-outs on a #f7f7f7 backdrop, and since
   _logo/normalise_products.py each one's content fills 86% of that frame.
   So the tile is square and the photo is contained on the exact backdrop
   colour: the whole machine shows, every machine shows at the same size, and
   the tile reads as one flat field because the photo's own margin is the same
   colour as the tile.

   The rule this replaces was a fixed 330px height with object-fit:cover, which
   on a square source keeps only the middle 61% -- measured, that clipped 39% of
   the drawn height and cut the top stack or the wheels off six of the eight
   photos. The tile is 78px shorter than it was worth being.

   The image is pinned with inset:0 rather than height:100%: a percentage height
   against a parent sized only by aspect-ratio does not resolve, and the image
   then keeps its natural height and gets clipped by the tile's overflow. */
.product-image{position:relative;overflow:hidden;background:#f7f7f7;aspect-ratio:1/1;height:auto}
.product-image img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;filter:saturate(.85);transition:transform .7s ease;
}
.product-card:hover .product-image img{transform:scale(1.025)}
.featured-badge{
  position:absolute;top:14px;left:14px;background:#fff;color:var(--ink);
  font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;padding:6px 11px;
}
.product-body{padding-top:22px;display:flex;flex-direction:column;flex:1 1 auto}
.product-body h2{font-size:clamp(1.12rem,1.6vw,1.38rem);font-weight:300;line-height:1.26;color:var(--ink)}
.product-subtitle{font-size:.8rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin-top:9px}
.product-summary{font-size:.88rem;color:var(--muted);line-height:1.62;margin-top:12px;max-width:440px}
/* 18px of margin under the summary so the auto margin above the arrow has a
   floor: on the tallest card in a row auto resolves to zero, and without this
   the link would sit on the last line of the paragraph. */
.product-body .product-summary{margin-bottom:18px}
.product-body .cta-arrow{margin-top:auto;align-self:flex-start}
.cta-arrow{
  display:inline-flex;align-items:center;gap:8px;font-size:.82rem;color:var(--ink);
  border-bottom:1px solid var(--ink);padding-bottom:2px;margin-top:18px;
}
.product-card:hover .cta-arrow{color:var(--accent);border-color:var(--accent)}
.products-cta{
  padding:clamp(56px,7vw,96px) 0;border-top:1px solid var(--line);background:var(--bg-soft);
}
.products-cta .container{display:grid;gap:18px;justify-items:start;max-width:var(--maxw)}
.products-cta h2{font-size:clamp(1.6rem,2.6vw,2.2rem)}
.products-cta p{color:var(--muted);max-width:520px}
.btn-primary{
  display:inline-flex;align-items:center;gap:10px;padding:14px 28px;
  background:var(--indigo);color:#fff;border:1px solid var(--indigo);border-radius:100px;
  font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;margin-top:10px;
}
.btn-primary:hover{background:var(--accent-ink);border-color:var(--accent-ink)}

/* --------------------------------------------------------------------------
   17. Product detail
   -------------------------------------------------------------------------- */
.pd{padding:clamp(40px,5vw,72px) 0 clamp(56px,7vw,96px)}
.pd-grid{
  display:grid;grid-template-columns:1.02fr .98fr;gap:clamp(32px,5vw,80px);align-items:start;
}
.pd-stage,.pd-main{background:var(--bg-soft);overflow:hidden}
.pd-gallery{display:block}
.pd-stage img,img.pd-main{
  width:100%;height:clamp(340px,42vw,560px);object-fit:contain;
  padding:clamp(18px,3vw,40px);filter:saturate(.94);background:var(--bg-soft);
}
.pd-thumbs{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px}
.pd-thumb{
  padding:0;border:1px solid transparent;background:var(--bg-soft);cursor:pointer;
  width:78px;flex:0 0 auto;
}
.pd-thumb img{width:100%;height:64px;object-fit:cover;filter:saturate(.85)}
.pd-thumb span{display:none}
.pd-thumb:hover,.pd-thumb.is-active{border-color:var(--line-2)}
.pd-highlights{margin-top:22px;border-top:1px solid var(--line)}
.pd-highlights li{
  display:flex;gap:11px;align-items:flex-start;padding:11px 0;
  border-bottom:1px solid var(--line);font-size:.9rem;color:var(--ink-2);line-height:1.55;
}
.pd-tick{width:14px;height:14px;flex:0 0 auto;margin-top:5px;fill:var(--accent)}
.pd-specs{padding:clamp(48px,6vw,84px) 0;border-top:1px solid var(--line)}
.pd-speci{max-width:900px}
.pd-spec-table{width:100%;border-collapse:collapse;margin-top:24px}
.pd-spec-table th,.pd-spec-table td{
  text-align:left;padding:13px 18px 13px 0;border-bottom:1px solid var(--line);
  font-size:.9rem;font-weight:400;vertical-align:top;
}
.pd-spec-table th{color:var(--muted);font-size:.74rem;letter-spacing:.1em;text-transform:uppercase;width:38%}
/* Below 560px the two columns squeeze the uppercase label into three lines.
   Stacking them keeps the label on one line and the value readable. */
@media (max-width:560px){
  .pd-spec-table th,.pd-spec-table td{display:block;width:auto;border-bottom:0;padding:0}
  .pd-spec-table th{padding-top:14px}
  .pd-spec-table td{padding-bottom:14px;border-bottom:1px solid var(--line)}
}
.pd-spec-table td{color:var(--ink)}
.pd-copy{padding:clamp(48px,6vw,84px) 0;border-top:1px solid var(--line)}
.pd-copy-in{max-width:760px}
.pd-copy-in h2{font-size:clamp(1.4rem,2.2vw,1.9rem);font-weight:300;margin-bottom:16px}
.pd-copy-in h2:not(:first-child){margin-top:clamp(34px,4.2vw,52px)}
.pd-copy-in h3{font-size:1rem;font-weight:500;color:var(--ink);margin:26px 0 10px}
.pd-copy-in p{color:var(--muted);font-size:.98rem;line-height:1.85;margin-bottom:18px}
.pd-copy-in p:last-child{margin-bottom:0}
.pd-copy-in ul,.pd-copy-in ol{margin:0 0 18px;padding:0;list-style:none}
.pd-copy-in li{position:relative;padding-left:22px;color:var(--muted);font-size:.98rem;line-height:1.85;margin-bottom:9px}
.pd-copy-in li:before{content:"";position:absolute;left:2px;top:.74em;width:5px;height:5px;border-radius:50%;background:var(--accent)}
.pd-copy-in strong{color:var(--ink);font-weight:500}
.pd-copy-in a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--line-2);transition:color .2s,border-color .2s}
.pd-copy-in a:hover{color:var(--accent);border-bottom-color:var(--accent)}
.pd-copy-in blockquote{margin:0 0 18px;padding-left:20px;border-left:2px solid var(--line-2);color:var(--muted)}

/* Question and answer block. <details> keeps every answer in the DOM: the
   FAQPage structured data points at this text, and collapsing it in JS would
   leave the markup describing content a crawler cannot read. */
.pd-faq{padding:clamp(48px,6vw,84px) 0;border-top:1px solid var(--line)}
.pd-faq-list{max-width:760px;margin-top:10px}
.pd-faq-item{border-bottom:1px solid var(--line)}
.pd-faq-q{
  position:relative;list-style:none;cursor:pointer;
  padding:20px 40px 20px 0;
  font-size:1rem;line-height:1.5;color:var(--ink);transition:color .2s;
}
.pd-faq-q::-webkit-details-marker{display:none}
.pd-faq-q:before,.pd-faq-q:after{
  content:"";position:absolute;right:2px;top:50%;width:12px;height:1px;
  background:var(--muted);transition:transform .25s,background .2s;
}
.pd-faq-q:after{transform:rotate(90deg)}
.pd-faq-item[open] .pd-faq-q:after{transform:rotate(0)}
.pd-faq-q:hover:before,.pd-faq-q:hover:after{background:var(--accent)}
.pd-faq-a{padding:0 0 22px}
.pd-faq-a p{color:var(--muted);font-size:.95rem;line-height:1.8;max-width:660px}
.pd-info .pd-eyebrow{
  font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--faint);margin-bottom:16px;
}
.pd-info h1{font-size:clamp(1.9rem,3.2vw,2.9rem);line-height:1.08;letter-spacing:-.03em}
.pd-subtitle{font-size:.84rem;letter-spacing:.05em;text-transform:uppercase;color:var(--accent);margin-top:14px}
.pd-summary{font-size:1rem;color:var(--muted);line-height:1.72;margin-top:18px;max-width:460px}
.pd-tags{display:flex;gap:8px;flex-wrap:wrap;margin-top:22px}
.pd-tag{
  font-size:.72rem;letter-spacing:.05em;color:var(--muted);
  border:1px solid var(--line);padding:6px 12px;
}
.pd-facts{border-top:1px solid var(--line);margin-top:28px}
.pd-facts > *{display:flex;justify-content:space-between;gap:20px;padding:13px 0;border-bottom:1px solid var(--line);font-size:.9rem}
.pd-actions{display:flex;gap:14px;flex-wrap:wrap;margin-top:30px}
.pd-cta,.pd-cta-solid{
  display:inline-flex;align-items:center;gap:10px;padding:14px 26px;border-radius:100px;
  font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;
  background:var(--indigo);border:1px solid var(--indigo);color:#fff;transition:background .2s;
}
.pd-cta:hover,.pd-cta-solid:hover{background:var(--accent-ink)}
.pd-cta-ghost{background:none;border-color:var(--line-2);color:var(--ink)}
.pd-cta-ghost:hover{background:none;border-color:var(--ink);color:var(--ink)}
.pd-inquiry{border-top:1px solid var(--line);margin-top:clamp(48px,6vw,80px);padding-top:clamp(36px,4.5vw,56px)}
.pd-inq-grid{display:grid;grid-template-columns:.9fr 1.1fr;gap:clamp(32px,5vw,80px);align-items:start}
.pd-inq-copy h2,.pd-h2{font-size:clamp(1.4rem,2.2vw,1.9rem);font-weight:300;margin-bottom:14px}
.pd-inq-copy p{color:var(--muted);font-size:.94rem;line-height:1.7;max-width:420px}
.pd-inq-hours{margin-top:22px;font-size:.84rem;color:var(--faint);line-height:1.8}

/* Product-page inquiry form. The markup is a flat run of .pd-inq-row
   (label + field) and nothing ever styled it, so the fields fell back to the
   browser default -- 1px boxes with the label sitting inline beside them, and
   a textarea that collapsed to about 150px with its placeholder clipped.
   The contact page solves the same problem with .form-row; these rules give
   the detail page the same visual language without touching its markup. */
.pd-inq-form form{display:grid;grid-template-columns:1fr 1fr;gap:20px 22px}
.pd-inq-form form > input[type=hidden]{display:none}
.pd-inq-row{display:flex;flex-direction:column;min-width:0}
.pd-inq-row label{
  display:block;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);margin-bottom:8px;
}
.pd-inq-row input,.pd-inq-row textarea{
  width:100%;border:1px solid var(--line);background:var(--bg-soft);
  padding:13px 14px;font:inherit;font-size:.92rem;color:var(--ink);outline:none;
  transition:border-color .2s,background .2s;
}
.pd-inq-row input:focus,.pd-inq-row textarea:focus{border-color:var(--accent);background:#fff}
.pd-inq-row textarea{min-height:132px;resize:vertical;line-height:1.6}
.pd-inq-row textarea::placeholder{color:var(--faint)}
/* The message box and the buttons run the full width of the two columns.
   :has() does it by content; the nth-last-of-type rule is the fallback for
   engines without it, and both resolve to the same row. */
.pd-inq-row:has(textarea),
.pd-inq-row:nth-last-of-type(2),
.pd-inq-actions{grid-column:1 / -1}
.pd-inq-actions{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:4px}

/* Form feedback. The template emits .alert/.alert-success/.alert-error and no
   rule existed for either, so a submitted inquiry thanked the visitor in
   default body text with no marker that anything had happened. */
.pd-inq-form .alert{
  padding:16px 18px;margin-bottom:24px;font-size:.92rem;line-height:1.65;
  border-left:3px solid var(--accent);background:var(--bg-soft);color:var(--ink-2);
}
.pd-inq-form .alert a{color:var(--accent);text-decoration:underline;text-underline-offset:2px}
.pd-inq-form .alert-error{border-left-color:var(--pink)}
.pd-related{border-top:1px solid var(--line);margin-top:clamp(48px,6vw,80px);padding-top:clamp(34px,4.5vw,54px)}
.pd-rel-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0 clamp(28px,4vw,56px);margin-top:30px}
.pd-rel-card{border-top:1px solid var(--line);padding-top:22px}
.pd-rel-media img{width:100%;height:170px;object-fit:cover;filter:saturate(.85)}
.pd-rel-title{display:block;font-size:1rem;font-weight:300;color:var(--ink);margin-top:14px;line-height:1.3}
.pd-rel-text{display:block;font-size:.82rem;color:var(--muted);line-height:1.55;margin-top:7px}

/* --------------------------------------------------------------------------
   18. Cases / news / article
   -------------------------------------------------------------------------- */
/* padding-block, not the shorthand: this element is also .container, and the
   shorthand was wiping the container's horizontal gutter, so case and article
   text sat flush against the viewport edge instead of lining up with the
   header and hero above it. */
.case-detail,.article{padding-block:clamp(40px,5vw,72px) clamp(56px,7vw,96px)}
.case-detail > .container,.article > .container{max-width:var(--maxw)}
.case-detail h1,.article h1{
  font-size:clamp(1.9rem,3.6vw,3rem);line-height:1.08;letter-spacing:-.03em;max-width:900px;
}
.meta-grid{
  display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(16px,3vw,40px);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:22px 0;margin:clamp(28px,4vw,44px) 0;
}
.meta-grid > *{font-size:.9rem;color:var(--ink)}
.meta-grid dt,.meta-grid .k{font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);margin-bottom:7px}

/* Case detail: the text column plus a sticky aside. A case study is three
   paragraphs, so on a wide screen the text alone left a third of the page
   empty; the aside puts the next thing the reader wants there. */
.case-aside{margin-top:clamp(36px,4.6vw,56px);border-top:1px solid var(--line);padding-top:clamp(26px,3vw,36px)}
.case-aside-h{font-size:.72rem;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
.case-aside-list{list-style:none;margin:0;padding:0}
.case-aside-list li{border-bottom:1px solid var(--line)}
.case-aside-list a{display:block;padding:16px 0;text-decoration:none;transition:opacity .2s}
.case-aside-list a:hover{opacity:.62}
.case-aside-t{display:block;font-size:.95rem;line-height:1.45;color:var(--ink)}
.case-aside-m{display:block;margin-top:6px;font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.case-aside-all{display:inline-block;margin-top:18px;font-size:.82rem;letter-spacing:.04em;color:var(--ink);text-decoration:none;border-bottom:1px solid var(--line-2);transition:color .2s,border-color .2s}
.case-aside-all:hover{color:var(--accent);border-bottom-color:var(--accent)}
@media (min-width:1024px){
  .case-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(250px,310px);gap:clamp(44px,5vw,88px);align-items:start}
  .case-aside{margin-top:0;border-top:0;padding-top:8px;position:sticky;top:96px}
}
body.is-rtl .case-aside-arrow{display:inline-block;transform:scaleX(-1)}

/* The return link from a case to the machine it was run on. Boxed like a spec
   row rather than a button: it is a reference, not a call to action. */
.case-equipment{
  display:block;margin-top:clamp(36px,4.4vw,52px);padding:22px 24px;
  border:1px solid var(--line);text-decoration:none;
  transition:border-color .25s,background .25s;
}
.case-equipment:hover{border-color:var(--line-2);background:var(--bg-soft)}
.case-equipment-k{display:block;font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.case-equipment-t{display:block;margin-top:9px;font-size:1.06rem;font-weight:300;line-height:1.35;color:var(--ink)}
.case-equipment-d{display:block;margin-top:7px;font-size:.88rem;line-height:1.65;color:var(--muted)}

.card-grid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:0 clamp(30px,4.4vw,64px);
  margin-top:clamp(26px,3.4vw,40px);
}
.featured-cases,.industry-strip{padding:clamp(48px,6vw,80px) 0}
/* Empty state for a scenario with no published rows. Four of the eight
   categories are in that state, so this is not an edge case -- it is what half
   the scenario grid resolves to. It reuses the card's top hairline so the
   block sits on the same rhythm as a populated list. */
.cases-empty{
  border-top:1px solid var(--line);
  margin-top:clamp(26px,3.4vw,40px);
  padding:clamp(30px,4vw,44px) 0 0;
  max-width:620px;
}
.cases-empty-title{font-size:1.06rem;font-weight:300;line-height:1.35;color:var(--ink)}
.cases-empty-body{font-size:.9rem;line-height:1.7;color:var(--muted);margin-top:12px}
.cases-empty .gw-btn{margin-top:26px}
.news-card,.card{
  display:block;border-top:1px solid var(--line);padding:clamp(22px,3vw,34px) 0;
  background:none;color:inherit;
}
.news-img,.card-img{
  overflow:hidden;background:var(--bg-soft);margin-bottom:18px;
  background-size:cover;background-position:center;
  height:clamp(170px,16vw,230px);
}
.news-img img,.card-img img{width:100%;height:100%;object-fit:cover;filter:saturate(.85);transition:transform .7s}
.news-card:hover .news-img{filter:saturate(1.05)}
.news-body h2,.news-body h3,.card-body h2,.card-body h3{
  font-size:1.08rem;font-weight:300;line-height:1.3;color:var(--ink);
}
.news-body p,.card-body p{font-size:.86rem;color:var(--muted);line-height:1.6;margin-top:9px}
.news-body small,.card-meta{
  display:block;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);margin-bottom:10px;
}
/* The category · year · location line above a case title is always rendered now,
   because one record has none of the three and its title otherwise sat a line
   higher than its neighbours'. Reserving the height here is what makes the empty
   case behave like a filled one, in every language. */
.card-body > small.muted{display:block;line-height:1.7;min-height:1.7em;margin-bottom:2px}
/* The case photographs are 800x600. The shared .card-img height gives them a
   1.55:1 panel, so cover was taking 12% off the top and bottom of every one --
   through the necks of the bottles that are the evidence. Panel takes the file's
   own ratio instead. Scoped: .news-img shares the rule and its thumbnails are
   already cropped to a fixed band on purpose. */
.featured-cases .card-img{height:auto;aspect-ratio:4/3}
.news-card:hover .news-body h2,.news-card:hover .news-body h3{color:var(--accent)}

/* list filters / search */
.filters{
  display:flex;gap:12px;flex-wrap:wrap;align-items:center;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:16px 0;margin:0 0 clamp(24px,3vw,36px);background:none;
}
.filters input[type="search"],.filters input[type="text"],.filters input:not([type]){
  flex:1 1 260px;min-width:200px;border:1px solid var(--line);background:var(--bg-soft);
  padding:11px 14px;font:inherit;font-size:.86rem;color:var(--ink);outline:none;
  transition:border-color .2s,background .2s;
}
.filters input:focus{border-color:var(--accent);background:#fff}
.filters select{
  border:1px solid var(--line);background:var(--bg-soft);padding:11px 14px;
  font:inherit;font-size:.86rem;color:var(--ink-2);outline:none;
}
.filters button{
  padding:11px 24px;border:1px solid var(--ink);border-radius:100px;
  font-size:.74rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink);
  background:none;transition:background .2s,color .2s;
}
.filters button:hover{background:var(--ink);color:#fff}

.industry-grid{
  display:grid;grid-template-columns:repeat(4,1fr);gap:0;
  border-top:1px solid var(--line);margin-top:clamp(28px,3.6vw,44px);
}
.industry-card{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:18px 18px 18px 0;border-bottom:1px solid var(--line);
}
.industry-card-label{font-size:.94rem;color:var(--ink-2)}
.industry-card-arrow{color:var(--muted)}
.industry-card:hover .industry-card-label{color:var(--accent)}

/* --------------------------------------------------------------------------
   19. Contact
   -------------------------------------------------------------------------- */
.contact-page{padding:clamp(36px,4.5vw,64px) 0 clamp(56px,7vw,96px)}
.contact-grid{display:grid;grid-template-columns:.86fr 1.14fr;gap:clamp(34px,5.5vw,92px);align-items:start}
.contact-info h2,.contact-form h2{font-size:1.1rem;font-weight:400;margin-bottom:18px;color:var(--ink)}
.contact-list{border-top:1px solid var(--line)}
.contact-list > *{display:grid;grid-template-columns:110px 1fr;gap:16px;padding:14px 0;border-bottom:1px solid var(--line);font-size:.9rem}
.contact-list dt,.contact-list .k{font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);padding-top:3px}
.contact-list dd,.contact-list .v{margin:0;color:var(--ink-2);line-height:1.6}
.contact-list a:hover{color:var(--accent)}

.form-row{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-bottom:20px}
.form-row.full,.inquiry-form .full{grid-template-columns:1fr}
.form-row label,.inquiry-form label{
  display:block;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);margin-bottom:8px;
}
.form-row input,.form-row select,.form-row textarea,
.inquiry-form input,.inquiry-form select,.inquiry-form textarea{
  width:100%;border:1px solid var(--line);background:var(--bg-soft);
  padding:13px 14px;font:inherit;font-size:.92rem;color:var(--ink);outline:none;
  transition:border-color .2s,background .2s;
}
.form-row input:focus,.form-row select:focus,.form-row textarea:focus,
.inquiry-form input:focus,.inquiry-form select:focus,.inquiry-form textarea:focus{
  border-color:var(--accent);background:#fff;
}
.form-row textarea,.inquiry-form textarea{min-height:130px;resize:vertical}
.form-row button,.inquiry-form button,.contact-form button[type=submit]{
  display:inline-flex;align-items:center;gap:10px;padding:14px 28px;border-radius:100px;
  background:var(--indigo);border:1px solid var(--indigo);color:#fff;
  font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;
}
.form-row button:hover,.inquiry-form button:hover{background:var(--accent-ink)}
.inquiry-form-section{padding:clamp(44px,5.5vw,72px) 0;background:var(--bg-soft);border-top:1px solid var(--line)}
.inquiry-form-section > *{
  max-width:var(--maxw);margin-left:auto;margin-right:auto;
  padding-left:var(--pad);padding-right:var(--pad);
}
.inquiry-form-section > h2{font-size:clamp(1.5rem,2.4vw,2rem);font-weight:300;margin-bottom:10px}
.inquiry-form-section > p.muted{color:var(--muted);font-size:.94rem;margin-bottom:26px}
.inquiry-form{max-width:760px}

/* --------------------------------------------------------------------------
   20. Empty state + section heads
   -------------------------------------------------------------------------- */
.gw-section{padding:clamp(52px,6.5vw,88px) 0}
.gw-section-head{margin-bottom:clamp(18px,2.4vw,28px)}
.gw-section-head h2{font-size:clamp(1.6rem,2.6vw,2.2rem);font-weight:300;letter-spacing:-.024em}
.gw-section-head p{color:var(--muted);font-size:.96rem;margin-top:12px;max-width:620px}
.report-list{border-top:1px solid var(--line)}
.report-list li{border-bottom:1px solid var(--line)}
.report-list a{display:block;padding:20px 0}
.report-list h3{font-size:1.05rem;font-weight:300;color:var(--ink)}
.report-list small{display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);margin-top:8px}
.report-list a:hover h3{color:var(--accent)}
.gw-empty{
  border:1px solid var(--line);background:var(--bg-soft);
  padding:clamp(36px,5vw,64px) clamp(22px,4vw,48px);text-align:center;margin-top:26px;
}
.gw-empty p{color:var(--muted);font-size:.92rem;max-width:440px;margin:0 auto}

/* --------------------------------------------------------------------------
   20b. 404 -- a lost visitor needs a way back, not an apology
   -------------------------------------------------------------------------- */
.gw-404-head{padding-bottom:clamp(22px,3.2vh,34px)}
.gw-404-code{
  display:block;font-size:.72rem;font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);margin-bottom:14px;
}
.gw-404-body{padding:clamp(32px,4.4vw,54px) 0 clamp(56px,7vw,96px)}
.gw-404-search{margin:0;max-width:760px}
.gw-404-label{
  display:block;font-size:.72rem;font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint);margin-bottom:16px;
}
/* The field is a hairline underline, not a bordered box: this site's grammar
   is rules and whitespace, and a 44px rounded input would be the only one on
   the whole site. The submit stays a pill because .gw-btn already is one. */
.gw-404-field{display:flex;align-items:flex-end;gap:20px;flex-wrap:wrap}
.gw-404-field input{
  flex:1 1 260px;min-width:0;border:0;border-bottom:1px solid var(--line-2);
  background:none;padding:10px 0;font:inherit;font-size:1.04rem;
  color:var(--ink);outline:none;transition:border-color .2s;
}
.gw-404-field input:focus{border-bottom-color:var(--ink)}
.gw-404-field input::placeholder{color:var(--faint)}
.gw-404-field .gw-btn{flex:0 0 auto}

/* Four destinations inside one ruled band. No vertical rules between cells:
   the same block has to survive two columns at 900 and one at 560, where a
   leading rule on the first cell of a row would sit against nothing. The
   separators are therefore added per breakpoint, by position. */
.gw-404-links{
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  margin-top:clamp(40px,5.2vw,66px);
}
.gw-404-links a{display:flex;flex-direction:column;gap:7px;padding:22px 0 24px}
.gw-404-links a:hover .gw-404-lk{color:var(--accent)}
.gw-404-lk{
  font-size:.76rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink);transition:color .2s;
}
/* break-word is enough here: the track is minmax(0,1fr), so the line box is
   already free to shrink below the longest word, which is the case
   break-word does handle. */
.gw-404-d{font-size:.86rem;line-height:1.6;color:var(--muted);overflow-wrap:break-word}
@media(max-width:900px){
  .gw-404-links{grid-template-columns:repeat(2,minmax(0,1fr))}
  .gw-404-links a{padding-inline-end:24px}
  .gw-404-links a:nth-child(n+3){border-top:1px solid var(--line)}
}
@media(max-width:560px){
  .gw-404-links{grid-template-columns:1fr;margin-top:36px}
  .gw-404-links a{padding:16px 0 18px}
  .gw-404-links a:nth-child(n+2){border-top:1px solid var(--line)}
  .gw-404-field{gap:14px}
}

/* --------------------------------------------------------------------------
   21. Footer — indigo #10069f
   -------------------------------------------------------------------------- */
.fw-footer-outer{background:var(--indigo);color:rgba(255,255,255,.82);margin-top:0}
.fw-footer-inner{max-width:var(--maxw);margin:0 auto;padding:clamp(56px,7vw,84px) var(--pad) 26px}
/* Five columns: brand, then Products / Solutions / Company / Contact.
   There used to be a sixth that repeated the header nav word for word.

   The ratios are measured, not chosen by eye. At 1440 the container gives
   1159px and four 26px gaps leave 1055 to divide. Each column's floor is the
   width of its longest entry, measured in the browser (see
   _logo/footer_widths.js):
     brand block                 275    "Weifang City, Shandong Province, P.R.
                                        China" is one address line and must not
                                        wrap, or the tail word sits alone
     Products  2 x 166 + 14 gap = 346   "FM-60/100 Fire-Resistant" needs 165
     Contact                     151    "gary@fengmingep.com"
     Solutions                   155    "Construction Machinery"
     Company                     103    "News & Insights"
   Sum 1030 of 1055, so every column clears its floor by a few pixels rather
   than by luck. Every label then holds one line, and one line is the point:
   the products list runs in sub-columns, so a single wrapped entry pushes
   every row below it out of line with the column beside it.

   That budget is why this layout needs about 1270px of viewport. Below it the
   five columns cannot all meet their floor at once and the list starts to
   stagger, so the footer collapses to three columns there. Change a ratio here
   and re-run the width probe before trusting it. */
.fw-footer-top{
  display:grid;grid-template-columns:1.33fr 1.63fr .75fr .51fr .75fr;
  gap:clamp(16px,1.8vw,26px);
  padding:clamp(34px,4vw,52px) 0 clamp(30px,3.8vw,44px);
  border-top:1px solid rgba(255,255,255,.16);
  border-bottom:1px solid rgba(255,255,255,.18);
}
/* the stay-in-touch block always sits as a slim full-width strip under the
   link columns, whatever the admin has published above it */
.fw-footer-top > *:last-child{
  grid-column:1/-1;border-top:1px solid rgba(255,255,255,.12);
  padding-top:22px;margin-top:6px;
}
.fw-box4{display:flex;align-items:center;gap:clamp(20px,3vw,40px);flex-wrap:wrap}
.fw-box4 .ftr-ttl{margin-bottom:0}
.gw-ftr-stay{display:flex;gap:clamp(18px,2.4vw,32px);flex-wrap:wrap}
.gw-ftr-stay p{margin-bottom:0}
.fw-box3{display:contents}
.fw-box3 .ftr-col{min-width:0}
.fw-box3 ul{list-style:none;margin:0;padding:0}
.fw-box3 li{margin-bottom:10px;font-size:.85rem;line-height:1.5}
.fw-box3 a{color:rgba(255,255,255,.82);line-height:1.45;transition:color .18s}
.fw-box3 a:hover{color:#fff}
/* Fifteen product labels, laid out as "as many columns as fit, each at least
   166px". A fixed column-count:2 was wrong at every width but one: the count
   stayed two while the column narrowed, so labels started wrapping and the two
   halves stopped lining up row for row. column-width lets the list drop to one
   column when two will not fit, and go to three when there is room for three,
   so no entry ever wraps and the rows always agree. 166 is the width of the
   longest label ("FM-60/100 Fire-Resistant", measured at 165).
   The gap is tighter than the grid gap on purpose: these are sub-columns of one
   list, and 14px keeps them reading as one block while still buying the brand
   block the width its address needs. */
.fw-box3 .ftr-col:first-child ul{column-width:166px;column-gap:14px}
.fw-box3 .ftr-col:first-child li{break-inside:avoid}
.fw-box1 .lead-line{color:rgba(255,255,255,.82);font-size:.92rem;line-height:1.7;max-width:300px;margin-top:0}
.fw-box1 .footer-logo,.fw-box1 img{height:26px;width:auto;margin-bottom:20px}
.gw-ftr-addr,.gw-ftr-hours{color:rgba(255,255,255,.6);font-size:.8rem;line-height:1.7;margin-top:14px;max-width:300px}
.copyright-line{color:rgba(255,255,255,.5);font-size:.76rem;margin-top:22px;max-width:300px;line-height:1.6}
/* an item the admin left without a URL: text, not a link that goes nowhere */
.ftr-txt{color:rgba(255,255,255,.82)}
.ftr-ttl{
  display:block;color:#fff;font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;
  font-weight:500;margin-bottom:16px;
}
/* The columns are grid items already, so the grid's row-gap is the only space
   they need. A margin-bottom on top of that added 26px of dead height to the
   row -- the footer was taller than its tallest column by exactly that much. */
.ftr-col{margin-bottom:0}
.gw-ftr-stay p{margin-bottom:11px}
.gw-ftr-stay a{display:inline-flex;align-items:center;gap:9px;font-size:.85rem;color:rgba(255,255,255,.82)}
.gw-ftr-stay a:hover{color:#fff}
.gw-ftr-ico{flex:0 0 auto;opacity:.8}
.fw-footer-bottom{
  display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap;
  padding-top:24px;
}
/* the copyright moved out of the brand column into this row, so it loses the
   column's stacking margin and its 300px measure */
.fw-footer-bottom .copyright-line{margin-top:0;max-width:none}
.fw-ftr-links ul{display:flex;gap:22px;flex-wrap:wrap;list-style:none;margin:0;padding:0}
.fw-ftr-links a{font-size:.76rem;color:rgba(255,255,255,.6)}
.fw-ftr-links a:hover{color:#fff}

/* --------------------------------------------------------------------------
   22. Language / RTL adjustments

   Direction is switched by <html dir="rtl"> plus body.is-rtl (base.html), and
   `direction:rtl` on its own already mirrors every flex and grid axis: the
   header row, the two-column signpost, the card grids, the icon+text feature
   rows and the footer columns all flip with no rule here.

   What direction does NOT mirror is anything written in physical coordinates.
   That is the whole list below: absolute left/right offsets, transform-origin,
   one-sided borders and padding, and the two 90deg scrim gradients that assume
   the headline sits on the left.

   The previous version of this block also pushed the right padding of
   .gw-hero-inner and .full-width-banner-main out to the viewport gutter. Both
   containers are already symmetric (`padding:0 var(--pad)`) and sit inside a
   centred max-width wrapper, so that override dragged every inner-page
   headline off the container axis. Removed.
   -------------------------------------------------------------------------- */
body.is-rtl{direction:rtl;text-align:right}

/* Arabic does not join under tracking: the .04em-.2em applied to every small
   caps label in this sheet (.gw-hero-eyebrow, .product-subtitle, spec table
   headers, footer headings) turns a connected word into disconnected letters.
   Those values are Latin-tuned, so tracking is dropped wholesale on Arabic
   pages rather than patched rule by rule. */
body.lang-ar *{letter-spacing:normal!important}
/* Arabic sits on a deeper baseline than Latin and needs more leading; the
   Latin 1.06-1.12 heading ratios collide on ascenders and diacritics. */
body.lang-ar{line-height:1.9}
body.lang-ar h1,body.lang-ar h2,body.lang-ar h3,body.lang-ar h4,body.lang-ar h5{line-height:1.4}

/* Scrims. The inner-page banner still darkens the left 66% because that is where
   the headline sits in LTR; in RTL the headline is on the right, so without this
   reversal white type lands on the bright half of the photograph. The home hero
   no longer needs a ramp at all -- its copy sits on a solid panel. */
body.is-rtl .full-width-banner-inner::after{
  background:
    linear-gradient(270deg,rgba(16,18,24,.62) 0%,rgba(16,18,24,.40) 36%,rgba(16,18,24,.08) 68%,rgba(16,18,24,0) 90%),
    linear-gradient(0deg,rgba(16,18,24,.34) 0%,rgba(16,18,24,0) 55%);
}

/* Header. The mega panel is pulled 24px to the left so its inner padding lines
   up with the nav label; the language list hangs off the button's right edge
   because the button sits at the right end of the bar. Both mirror. */
body.is-rtl .gw-mega{right:auto;left:var(--pad)}
body.is-rtl .gw-langsw::before{left:auto;right:calc(var(--hdr-gap) / -2 - .5px)}
body.is-rtl .gw-langsw-list{right:auto;left:0}
/* the nav underline grows away from the reading edge */
body.is-rtl #section-Homepage-level1 > li > a.gw-top-link::after{transform-origin:right center}

/* Signpost. `direction:rtl` already places the photograph in the right column
   and the copy in the left one, so the order rules that used to live here were
   redundant (and one of them targeted .large-signpost-textbox, which is not a
   grid item at all, so it never did anything). What does not follow is the
   copy's asymmetric padding: the outer gutter has to stay on the left, which
   is exactly what the LTR default already sets. The [data-pos="left"] variant
   is overridden too, because it would otherwise move the gutter to the wrong
   side. */
body.is-rtl .gw-ls .gw-ls-text{
  padding-left:max(var(--pad),calc((100vw - var(--maxw))/2 + var(--pad)));
  padding-right:clamp(24px,4vw,64px);
}

/* Spec tables: the th label column reads first, so alignment and the cell
   gutter both flip. */
body.is-rtl .gw-spec-table th,body.is-rtl .gw-spec-table td,
body.is-rtl .pd-spec-table th,body.is-rtl .pd-spec-table td{
  text-align:right;padding-left:18px;padding-right:0;
}
/* Stacked layout on a phone: the 18px gutter above has nothing left to
   separate, so it would just push the value off the edge. */
@media (max-width:560px){
  body.is-rtl .pd-spec-table th,body.is-rtl .pd-spec-table td{padding-left:0;padding-right:0}
}

/* Corner-pinned badge and the one-sided accent bar on form feedback. */
body.is-rtl .featured-badge{left:auto;right:14px}
/* Product body copy: the list marker is absolutely positioned at a physical
   left offset, so direction:rtl alone does not move it to the right gutter. */
body.is-rtl .pd-copy-in li{padding-left:0;padding-right:22px}
body.is-rtl .pd-copy-in li:before{left:auto;right:2px}
body.is-rtl .pd-copy-in blockquote{padding-left:0;padding-right:20px;border-left:0;border-right:2px solid var(--line-2)}
/* The plus/minus glyph is absolutely positioned, so direction:rtl does not
   move it -- both the padding and the anchor have to be mirrored by hand. */
body.is-rtl .pd-faq-q{padding:20px 0 20px 40px}
body.is-rtl .pd-faq-q:before,body.is-rtl .pd-faq-q:after{right:auto;left:2px}
body.is-rtl .pd-inq-form .alert{border-left:0;border-right:3px solid var(--accent)}
body.is-rtl .pd-inq-form .alert-error{border-right-color:var(--pink)}
/* The industry card is a link with a "go" arrow at the far end. direction:rtl
   already moves the arrow to the left end, but the glyph itself is &rarr; and
   still points right -- i.e. backwards against the reading direction. Flipping
   it is the whole fix; the asymmetric padding has to be mirrored by hand
   because it is written in physical (right/left) terms, not logical ones. */
body.is-rtl .industry-card{padding:18px 0 18px 18px}
body.is-rtl .industry-card-arrow{transform:scaleX(-1)}

/* --------------------------------------------------------------------------
   23. Responsive
   -------------------------------------------------------------------------- */
/* The footer is the only block here that gives up a column this early. Five
   columns need about 1270px to hold every footer label on one line (the arithmetic
   is above .fw-footer-top); under that the products list starts to stagger,
   which looks worse than a looser three-column grid. Brand block and Products
   keep the first row, the three short columns take the second. */
@media(max-width:1270px){
  .fw-footer-top{grid-template-columns:1.15fr 1.45fr 1fr}
  .fw-box4{grid-column:1/-1}
}

/* Two columns from here down, with the brand block and the product list each
   taking a full row. Products needs the full width: at 800px a half-column
   holds 343px, which is one 166px sub-column and a lot of empty space, and the
   list would run to fifteen rows. Full width it lays out three or four across
   and stays four rows deep. */
@media(max-width:1000px){
  .fw-footer-top{grid-template-columns:1fr 1fr}
  .fw-box1{grid-column:1/-1}
  .fw-box3 .ftr-col:nth-child(1){grid-column:1/-1}
}

@media(max-width:1100px){
  .gw-ind-grid{grid-template-columns:repeat(3,1fr)}
  .industry-grid{grid-template-columns:repeat(3,1fr)}
  .gw-cg-grid,.card-grid{grid-template-columns:repeat(2,1fr)}
  .gw-cg-grid[data-cols="4"]{grid-template-columns:repeat(2,1fr)}
}

@media(max-width:900px){
  :root{--hdr-h:66px}
  /* backdrop-filter creates a containing block for the fixed drawer — drop it on mobile */
  #headerwrapper{backdrop-filter:none;background:#fff}
  body.gw-nav-open #headerwrapper{z-index:1001}
  #logo img{height:24px}
  .gw-burger{display:block}
  #topnavigation{
    position:fixed;top:0;left:0;right:0;bottom:auto;z-index:1000;
    height:100vh;height:100dvh;
    background:#fff;flex-direction:column;align-items:stretch;justify-content:flex-start;
    padding:64px 22px 30px;overflow-y:auto;transform:translateX(-100%);
    /* Closed has to mean gone, not just off-screen. translateX(-100%)
       parks the drawer outside the viewport and leaves every one of its
       links, the close button and the search field in the tab order, so a
       keyboard user walks through the whole invisible menu before reaching
       the page and a screen reader reads it out. visibility:hidden takes
       the subtree out of both without changing layout. It flips after the
       280ms exit so the slide still reads, and instantly on the way in. */
    visibility:hidden;
    transition:transform .28s ease,visibility 0s linear .28s;
    display:flex;
  }
  body.gw-nav-open{overflow:hidden}
  body.gw-nav-open #topnavigation{transform:none;visibility:visible;
    transition:transform .28s ease,visibility 0s}
  /* 44x44 as a real box, not a pseudo-element: this one is absolutely
     positioned, so growing it moves nothing. The glyph stays where it was --
     top:5px + a 44px box centres a 26px glyph on the old 14px baseline, and
     right:10px keeps the 24px glyph 18px from the drawer edge. */
  .gw-drawer-close{
    display:flex;align-items:center;justify-content:center;
    position:absolute;top:5px;right:10px;width:44px;height:44px;
    font-size:1.5rem;line-height:1;color:var(--ink);
  }
  .fw-Menu,.fwMenuwrapper{display:block;width:100%}
  #top-left{align-self:auto}
  /* #topnavigation is NOT in this reset: it is the drawer itself and carries
     height:100dvh from the rule above. Resetting it to auto collapsed the
     drawer to its content height (~515px), so the page showed through below
     the search field while body.gw-nav-open had scroll locked. Only the two
     wrappers need their desktop height:100% undone. */
  .fw-Menu,.fwMenuwrapper{height:auto}
  #section-Homepage-level1{display:block;height:auto;width:100%}
  #section-Homepage-level1 > li{display:block;border-bottom:1px solid var(--line)}
  /* The drawer is a touch target, not a nameplate: undo the desktop
     uppercase micro-label treatment and go back to 1rem sentence case. */
  #section-Homepage-level1 > li > a.gw-top-link{
    display:block;padding:15px 0;font-size:1rem;color:var(--ink);
    font-weight:400;letter-spacing:0;text-transform:none;
  }
  #section-Homepage-level1 > li.gw-nav-cta{border-bottom:0}
  #section-Homepage-level1 > li.gw-nav-cta > a.gw-top-link{
    margin:16px 0 4px;padding:14px 20px;font-size:1rem;letter-spacing:0;text-align:center;
  }
  .gw-langsw::before{display:none}
  /* mobile: top-level links only — tapping goes to the section page */
  #section-Homepage-level1 > li > .gw-mega,
  #section-Homepage-level1 > li:hover > .gw-mega,
  #section-Homepage-level1 > li:focus-within > .gw-mega,
  #section-Homepage-level1 > li.gw-mega-open > .gw-mega{display:none}
  /* ...except that nav.js has always done the opposite: on a tap it cancels the
     navigation and toggles .gw-mega-open, which the four rules above then
     overrode in every state. So tapping Products, Solutions or Company did
     nothing at all -- no submenu, no page load -- and fifteen products were
     unreachable from the menu on a phone. The accordion is the behaviour the
     markup is built for (aria-expanded, .gw-has-mega), so the drawer keeps it
     and the floating desktop panel becomes an indented list. */
  #section-Homepage-level1 > li.gw-mega-open > .gw-mega{display:block}
  .gw-mega{position:static;width:auto;padding:0;margin:0 0 4px}
  .gw-mega-inner{
    border:0;box-shadow:none;background:none;max-height:none;overflow:visible;
    padding:2px 0 6px 14px;
  }
  .gw-mega-inner ul{column-count:1;column-gap:0}
  .gw-mega-inner li a{padding:10px 0}
  .gw-mega-label{font-size:.92rem}
  .gw-mega-desc{font-size:.8rem}
  .gw-search{width:100%;margin-top:18px;border-top:1px solid var(--line);padding-top:18px}
  #top-left > .gw-search{display:none}
  #topnavigation .gw-search{display:flex;position:static;width:100%;margin-top:18px}
  #topnavigation .gw-search .gw-search-input,
  .gw-search .gw-search-input{width:100%;padding:10px 0;border-bottom-color:var(--line-2)}
  .gw-langsw{position:relative;margin-left:auto}
  /* The drawer is a fixed panel at z-index 1000 living INSIDE #top-left, and the
     switcher is its sibling at z-index auto. So when the menu opened, the panel
     painted over the language control and the control was unreachable on a
     phone: elementFromPoint at its centre returned DIV.topnavigation, and the
     only visible thing in the top bar was the close button. One level above the
     panel puts the switcher back in the top bar, beside that close button.
     Same stacking context (#headerwrapper, z-index 1001), so the number only
     has to beat 1000. */
  body.gw-nav-open .gw-langsw{position:relative;z-index:1002}
  .gw-langsw-btn{font-size:.78rem}
  .gw-langsw-list{right:0;top:calc(100% + 10px);min-width:118px}
  .gw-langsw-list::before{top:-10px;height:10px}
  /* RTL: the drawer parks off the right edge and slides in from there, its
     close button moves to the top-left, and the language list hangs left. */
  body.is-rtl #topnavigation{transform:translateX(100%)}
  /* This has to be more specific than the rule above, not just later. Both
     "body.is-rtl #topnavigation" and "body.gw-nav-open #topnavigation" are
     (1,1,1), so on an Arabic page the closed-state transform won on source
     order and the drawer never slid in -- the mobile menu was unreachable in
     Arabic only. Two classes on <body> puts this at (1,2,1). */
  body.is-rtl.gw-nav-open #topnavigation{transform:none}
  body.is-rtl .gw-drawer-close{right:auto;left:18px}
  body.is-rtl .gw-langsw{margin-left:0;margin-right:auto}
  body.is-rtl .gw-langsw-list{right:auto;left:0}
  .gw-scrim{display:none}
  body.gw-nav-open .gw-scrim{display:block;position:fixed;inset:0;background:rgba(16,18,24,.4);z-index:999}

  .news-grid > .news-card .news-body{grid-template-columns:1fr;row-gap:8px}
  .news-grid > .news-card .news-body > small.muted,
  .news-grid > .news-card .news-body > h2,
  .news-grid > .news-card .news-body > p{grid-column:1;grid-row:auto}
  .gw-txt-in{grid-template-columns:1fr;row-gap:20px}
  .gw-txt-in > .gw-h2,.gw-txt-in > h2{max-width:none}
  .gw-txt-cta{grid-column:1}
  .gw-hero-cta{min-width:0}
  /* Stacked below 900: photograph first, then the copy. The panel keeps its own
     dark field so the CTA never sits on the image, which is where it would lose
     contrast at exactly the width where the image is cropped hardest. */
  .gw-hero{grid-template-columns:1fr;min-height:0}
  .gw-hero-shot{order:-1;min-height:clamp(240px,38vh,380px)}
  .gw-hero-panel{padding:34px var(--pad) 46px}
  .gw-hero-copy{max-width:none}
  .gw-hero-copy h1{max-width:none}
  .gw-it-in,.pd-grid,.pd-inq-grid,.contact-grid{grid-template-columns:1fr}
  .pd-inq-form form{grid-template-columns:1fr}
  .gw-stat-grid{grid-template-columns:1fr 1fr;gap:22px 26px}
  .gw-ind-grid{grid-template-columns:1fr 1fr}
  .gw-feat-item{grid-template-columns:52px 1fr;gap:10px 16px}
  .gw-feat-b{grid-column:2}
  .products-grid{grid-template-columns:1fr}
  .meta-grid{grid-template-columns:1fr 1fr}
  .pd-rel-grid{grid-template-columns:1fr 1fr}
  .gw-ls .single-large-signpost{grid-template-columns:1fr}
  .gw-ls .large-signpost-image{order:2;min-height:260px}
  .gw-ls .large-signpost-textbox{padding-left:var(--pad);padding-right:var(--pad)}
  /* full-width on mobile, so the RTL outer gutter has to go back to --pad */
  body.is-rtl .gw-ls .gw-ls-text{padding-left:var(--pad);padding-right:var(--pad)}
  .form-row{grid-template-columns:1fr}

  /* Touch targets. Measured on a 390px render: the drawer close button came out
     28x26, the burger 30x30, the search button 28x28, the language trigger 39x33,
     and every footer link was 16px tall -- the line box only, with the 10px
     between links belonging to the li, so a thumb aimed between two links hit
     neither. The icons keep their drawn size and only the box around them grows,
     so nothing moves; the footer rows get their space back from the li margin,
     which keeps the footer the same height.
     inset:-6px was not enough: on a 28px button it lands at 40x38, still short of
     the 44px a thumb needs. The hit box is now a fixed 44x44 centred on the
     glyph, which works whatever size the glyph happens to be drawn at.
     .gw-drawer-close is deliberately NOT in this list. It is absolutely
     positioned, and adding position:relative to it here silently undid its own
     position:absolute -- same specificity, later in the file -- so the button
     dropped out of the drawer corner and its 44px box landed in the middle of a
     346px-wide button, nowhere near the glyph. It gets a real 44x44 box instead. */
  .gw-burger,.gw-search-btn,.gw-langsw-btn{position:relative}
  .gw-burger::after,.gw-search-btn::after,.gw-langsw-btn::after{
    content:"";position:absolute;left:50%;top:50%;
    width:44px;height:44px;transform:translate(-50%,-50%);
  }
  /* the logo is 24px tall here and the link is exactly that box; the hero's
     "Browse products" is a 26px line of text with a rule under it */
  #logo a,.gw-hero-more{position:relative}
  #logo a::after,.gw-hero-more::after{content:"";position:absolute;inset:-11px -6px}
  .gw-langsw-btn{padding:11px 0}
  .fw-box3 li{margin-bottom:0}
  .fw-box3 a{display:inline-block;padding:6px 0}
  .fw-ftr-links a{display:inline-block;padding:8px 0}
}

/* The product grid dropped to one column at 900px and stayed there, so on a 900px
   viewport each card's 1:1 product shot filled the entire 824px content width.
   Measured: the grid alone came to 16,066px for fifteen products, and /products
   reached 26,988px -- a third longer than it is on a 390px phone, which is the
   wrong way round.
   Two columns were first restored from 700px, which left 561-699 as the worst
   band on the site: one 550-640px square photo per card. Measured at 600px the
   grid alone came to 11,845px and /products to 23,940px -- still longer than the
   same page on a 390px phone. Two columns fit from 561px, where the card is
   257px; below that the card would be narrower than the 160px that ruled two
   columns out on a phone, so the grid stays single and the card goes horizontal
   instead (see the 560px block). */
@media (min-width:561px) and (max-width:900px){
  .products-grid{grid-template-columns:1fr 1fr}
}

@media(max-width:560px){
  .gw-cg-grid,.card-grid,
  .gw-ind-grid,.industry-grid,
  .gw-stat-grid,.pd-rel-grid,.meta-grid,.fw-footer-top{grid-template-columns:1fr}
  /* stacked columns need more separation than the 16px row gap the grid uses
     at this width, now that .ftr-col no longer carries its own margin */
  .fw-footer-top{row-gap:32px}
  .gw-hero-copy h1{font-size:1.82rem}
  .gw-hero-actions{gap:18px;margin-top:30px}
  .gw-hero-cta{padding:13px 24px}
  .gw-hero-shot{min-height:200px}
  .gw-txt,.gw-cg,.gw-cgc,.gw-pg,.gw-cap,.gw-ind,.gw-feat,.gw-faq,.gw-spec,.gw-stat,.gw-it,.gw-ls,.gw-section{padding:52px 0}
  /* On a narrow screen the section head wraps, and the "All products" / "All
     cases" button -- which is meant to sit beside the heading -- drops onto its
     own line BETWEEN the heading and the paragraph that explains it. Measured
     on the home page at 390px: heading, then a 44px pill, then "Seven series,
     from a single cartridge filter...".
     Dissolving the head with display:contents lets the heading, the lead, the
     grid and the button be ordered as one column, so the action lands where it
     belongs on mobile -- after the thing it acts on. */
  .gw-pg > .container,.gw-cgc > .container{display:flex;flex-direction:column}
  .gw-pg .gw-sechead,.gw-cgc .gw-sechead{display:contents}
  .gw-pg .gw-sechead > .gw-h2,.gw-cgc .gw-sechead > .gw-h2{order:1}
  .gw-pg > .container > .gw-lead,.gw-cgc > .container > .gw-lead{order:2}
  .gw-pg > .container > .gw-cg-grid,.gw-cgc > .container > .gw-cg-grid{order:3}
  .gw-pg .gw-sechead > .gw-btn,.gw-cgc .gw-sechead > .gw-btn{order:4;align-self:flex-start;margin-top:30px}
  /* Mobile keeps the flex row. Measured at 390px on the live pages the eight
     industry tabs come out as 2 rows / 89px in Chinese, 3 / 133px in Arabic,
     4 / 177px in English and 5 / 221px in Russian -- compact, no overlap, no
     clipping (collide 0, text overflow 0). Forcing two columns to even them out
     would make the Chinese strip 177px, twice what it needs, so the ragged
     right edge is the cheaper of the two.
     What this block does fix is the row divider. It used to be a border-top on
     each cell, which in a wrapping flex row spans only its own label plus 16px
     and renders as a dashed line -- there is no row element to hang it on. A
     repeating gradient on the container draws one continuous rule every 44px.
     That is exact rather than approximate: every label fits on one line at
     390px (widest measured 183px against 350px of content width), so every row
     is exactly the 44px min-height below. */
  .full-width-banner .slider-nav-thumbnails{
    gap:0 16px;overflow:visible;padding-bottom:0;
    background-image:linear-gradient(to bottom,var(--line) 0 1px,transparent 1px);
    background-size:100% 44px;
    background-repeat:repeat-y;
  }
  .full-width-banner .slider-nav-thumbnails .thumb-box{
    padding:0;min-height:44px;display:flex;align-items:center;
  }
  .full-width-banner .thumb-text{white-space:normal;font-size:.84rem;line-height:1.32}
  /* Micro-labels are set at 10.9-11.8px, which is fine for an eyebrow on a
     1440px screen and not fine on a phone. The split is by job, not by size:
     these carry information the reader has to act on -- form labels, spec table
     keys, case meta keys, contact keys, footer column titles, filter pills --
     so they get 12px. The purely decorative ones (.gw-card-tag, .pd-eyebrow,
     dates, index numbers) keep their size, because raising them too would flatten
     the hierarchy between a label and the 14.7px body text it labels. */
  .gw-spec-table th,.pd-spec-table th,.meta-grid dt,.meta-grid .k,
  .contact-list dt,.contact-list .k,.case-equipment-k,.ftr-ttl,.filters button,
  .pd-inq-row label,.form-row label,.inquiry-form label{font-size:.75rem}
  /* .gw-card-tag was on the "decorative" side of that split until /cases showed
     what it actually holds: "NAS 3 / 39 ppm", "66.7 -> 26 · 800 ppm", "200 L ·
     2.2 t" -- the measured result of the installation, which is the one thing on
     a case card worth reading. 10.9px uppercase does not survive that. It is a
     real label, so it gets the same 12px. min-height:2.7em scales with it, so the
     two-line reservation the grid depends on still holds. */
  .gw-card-tag{font-size:.75rem}
  /* Fifteen product cards stacked one per row, each a 350px square tile plus
     200px of copy: 622px per card, 9,325px of grid, 24,482px of page. Measured
     on 390px. The tile is square because the shots are 900x900 cut-outs contained
     on #f7f7f7 -- a 4:3 box was tried and rejected, it only adds empty margin and
     makes every machine look smaller.
     Moving the tile beside the heading instead turns the card into a list row:
     112px of photo, 224px of copy, 225px per card, 3,377px of grid, 18,535px of
     page. Nothing is cut -- title, spec line, summary and link all stay. */
  .product-card{padding:18px 0}
  .product-card-link{flex-direction:row;gap:14px;align-items:flex-start}
  .product-image{width:112px;flex:0 0 112px}
  .product-body{padding-top:0}
  .product-body h2{font-size:1rem;line-height:1.26}
  /* The spec line is 0.8rem uppercase at 0.06em tracking. Against 224px it wrapped
     to three lines and out-shouted the title above it, so it loses a little size
     and a little tracking here -- it is a qualifier, not a heading. */
  .product-subtitle{font-size:.66rem;letter-spacing:.04em;line-height:1.3;margin-top:5px}
  .product-summary{font-size:.8rem;line-height:1.48;margin-top:7px;max-width:none}
  .product-body .product-summary{margin-bottom:9px}
  .product-body .cta-arrow{font-size:.74rem;margin-top:0;padding-bottom:1px}
  /* The badge keeps its desktop type size. "FEATURED" at 0.64rem with 0.1em
     tracking is about 78px, which still clears the 112px tile -- it only needed
     its padding and inset trimmed. Shrinking the type to fit would have put it at
     8px, under the 10.9px floor the other decorative eyebrows sit on. */
  .featured-badge{top:6px;left:6px;font-size:.64rem;padding:4px 7px;letter-spacing:.1em}
  /* At 320px the copy column is only 154px, which pushed the spec line to four
     lines and the card to 286px. A 92px tile gives the copy 174px back. */
  @media(max-width:360px){
    .product-image{width:92px;flex:0 0 92px}
    .product-body h2{font-size:.94rem}
    .product-subtitle{font-size:.62rem}
    .product-summary{font-size:.76rem}
  }
  /* An auto-layout table sizes each column to its min-content width, and Russian
     spec keys are long single words ("гидравлический", "производительность"). On
     /products?lang=ru at 320px the table grew to 370px inside a 280px wrapper and
     took the page 93px past the viewport; at 390px it was still 23px over. Fixed
     layout honours the 34% key column from the rule above and lets the long words
     break, so the table stays at 100% whatever the language. */
  .gw-spec-table{table-layout:fixed}
  .gw-spec-table th,.gw-spec-table td{overflow-wrap:break-word;padding-right:12px}
  /* Grid tracks are minmax(auto,1fr), so their floor is the item's min-content
     width -- one long unbreakable word widens the whole column and takes the page
     with it. Russian does exactly that: /products?lang=ru ran 93px past a 320px
     viewport, two 180px cards sitting in a 280px container. min-width:0 lets the
     item shrink to the track; overflow-wrap:anywhere (unlike break-word) also
     lowers the min-content floor, so a long word breaks only when it must and
     the two-up sections marked data-cols="2"/"4" keep their two columns. */
  .gw-cg-grid > *{min-width:0}
  .gw-cg-grid .gw-card *{overflow-wrap:anywhere}
  /* Below 360px two tracks leave 124px each, which is narrower than the words
     inside them can usefully wrap at. Those sections go single there. */
  @media(max-width:360px){
    .gw-cg-grid[data-cols="2"],.gw-cg-grid[data-cols="4"]{grid-template-columns:1fr}
  }
  .fw-footer-bottom{flex-direction:column;align-items:flex-start}
}

/* print / motion */
@media(prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important;scroll-behavior:auto!important}
}

/* --------------------------------------------------------------------------
   iOS will not focus a field whose text is under 16px without zooming the
   whole page in, and it does not zoom back out afterwards -- the visitor ends
   up finishing the form on a magnified page with the right half off-screen.
   Every field on this site was below the line: the drawer search at .82rem
   (13.1px), the list filters at .86rem (13.8px) and both inquiry forms at
   .92rem (14.7px). This states the threshold once for all of them instead of
   nudging four rules and hoping they stay in step. Selectors match the
   originals so specificity ties and this wins on order; desktop is untouched.
   -------------------------------------------------------------------------- */
@media(max-width:900px){
  .gw-search-input,
  .gw-search .gw-search-input,
  .filters input[type="search"],
  .filters input[type="text"],
  .filters input:not([type]),
  .filters select,
  .pd-inq-row input,
  .pd-inq-row textarea,
  .form-row input,
  .form-row select,
  .form-row textarea,
  .inquiry-form input,
  .inquiry-form select,
  .inquiry-form textarea{font-size:16px}
}

/* --------------------------------------------------------------------------
   Skip link (base.html). The header carries six top-level rows plus four mega
   menus, so a keyboard user otherwise tabs through the whole navigation on
   every page before reaching the content -- WCAG 2.4.1, level A.

   Hidden with clip-path, not with a negative offset: under RTL a negative
   left edge extends the scroll area to the left, which is how the honeypot
   field once gave the Arabic pages a 10389px scrollWidth at a 390px viewport.
   Neutral colours on purpose -- #10069f is the footer's brand colour and must
   not appear outside the footer.
   -------------------------------------------------------------------------- */
.gw-skip{
  position:absolute;inset-block-start:0;inset-inline-start:0;z-index:2147483003;
  padding:.7rem 1.1rem;background:#111;color:#fff;border-radius:0 0 .5rem 0;
  /* No font shorthand here: "inherit" is not a valid family inside it, so
     the whole declaration would be dropped and the size would silently
     fall back to the body default. Inherit the family, state the rest. */
  font-size:.95rem;font-weight:600;line-height:1.1;
  text-decoration:none;white-space:nowrap;
  clip-path:inset(50%);overflow:hidden;
}
.gw-skip:focus,.gw-skip:focus-visible{
  clip-path:none;outline:3px solid #fff;outline-offset:-6px;
}
