/* ==========================================================================
   THALEON GLOBAL N.V. — v3.0 "Motion"
   Sourcing · Trade · Logistics
   --------------------------------------------------------------------------
   Stack: GSAP 3 + ScrollTrigger  ·  Lenis smooth scroll  ·  Three.js (WebGL)
   Token families:
     THEMED  — flip between dark / light (chrome + body sections)
     MEDIA   — fixed light-on-dark, used over photography + WebGL
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */
:root{
  /* MEDIA tokens — identical in both themes */
  --on-media:#F4F6FA;
  --on-media-2:#C2CAD8;
  --on-media-3:#8C93A6;
  --accent-media:#2DD4E8;
  --media-bg:#04060D;
  --media-hair:rgba(244,246,250,.12);
  --media-hair-2:rgba(244,246,250,.08);

  --violet:#7A3FF2;
  --cyan:#2DD4E8;
  --teal-deep:#062F33;

  --f-ui:"Jost", system-ui, -apple-system, sans-serif;
  --f-serif:"Cormorant Garamond", Georgia, serif;
  /* Two typefaces, at the client's request: Jost carries every piece of
     information on the site and Cormorant is reserved for quotes and taglines.
     The label token is kept rather than removed so the hundred-odd rules that
     ask for it keep their sizes and letter-spacing — only the face changes. */
  --f-mono:"Jost", system-ui, -apple-system, sans-serif;

  --wrap:1440px;
  --gut:clamp(20px,4.5vw,72px);
  --r-lg:clamp(14px,2vw,28px);

  --ease:cubic-bezier(.16,.84,.34,1);
  --slow:cubic-bezier(.65,0,.35,1);
}

/* White, not beige. White leaves the logo gradient free to be the only
   colour on the page and keeps the photography the warmest thing on screen. */
:root{
  --bg:#FFFFFF;  --bg-2:#F5F7FA;  --bg-3:#E9EEF4;
  --tx:#0C0F16;  --tx-2:#2C3444;  --tx-3:#59627A;  --tx-4:#98A1B2;
  --accent:#0B6C7D;
  --hair:rgba(12,15,22,.14);
  --hair-2:rgba(12,15,22,.065);
  --stroke:rgba(12,15,22,.30);
  --panel:rgba(255,255,255,.95);
  --scrim:rgba(12,15,22,.58);
  --field:#F5F7FA;
  --btn-bg:#0C0F16; --btn-tx:#FFFFFF;
  --grain-op:.02;
}

/* ==========================================================================
   2. BASE
   ========================================================================== */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html.lock,body.lock{overflow:hidden}

body{
  margin:0; background:var(--bg); color:var(--tx);
  font-family:var(--f-ui); font-weight:300; font-size:16px; line-height:1.7;
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
  transition:background .6s var(--ease), color .6s var(--ease);
}
/* Lenis drives scroll; keep native behaviour predictable */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto !important}
.lenis.lenis-stopped{overflow:hidden}

img{display:block; max-width:100%}
/* the img rule above outranks the UA sheet, so restate [hidden] explicitly */
[hidden]{display:none !important}
a{color:inherit; text-decoration:none}
button{
  font:inherit; cursor:pointer; background:transparent; border:0;
  color:inherit; padding:0; margin:0; text-align:inherit;
  -webkit-appearance:none; appearance:none;
}
:focus-visible{outline:2px solid var(--accent); outline-offset:4px}
.wrap{max-width:var(--wrap); margin:0 auto; padding:0 var(--gut)}
.sr{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap}

/* Film grain. Deliberately static and without mix-blend-mode: a blended,
   animated, full-viewport fixed layer forces the compositor to re-blend the
   whole screen on every scroll frame, which is expensive for an effect nobody
   consciously sees. A still, low-opacity tile costs nothing. */
.grain{
  position:fixed; inset:0; z-index:190; pointer-events:none;
  opacity:var(--grain-op);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   3. TYPE
   ========================================================================== */
.kicker{
  font-family:var(--f-mono); font-size:10px; font-weight:400;
  letter-spacing:.34em; text-transform:uppercase; color:var(--accent);
  margin:0 0 18px; display:flex; align-items:center; gap:14px;
}
.kicker::before{content:""; width:34px; height:1px; background:currentColor; opacity:.55; flex:none}
.h-caps{
  font-family:var(--f-ui); font-weight:200;
  font-size:clamp(2.1rem,6.2vw,5.4rem); line-height:1.02;
  letter-spacing:.06em; text-transform:uppercase; margin:0;
}
.h-serif{
  font-family:var(--f-serif); font-weight:300; font-style:italic;
  font-size:clamp(1.4rem,3vw,2.6rem); line-height:1.3; color:var(--tx-2); margin:0;
}
.body-t{color:var(--tx-3); font-size:15.5px; max-width:56ch; font-weight:300}
.grad{
  background:linear-gradient(100deg,var(--tx) 10%,var(--accent));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.grad-m{
  background:linear-gradient(100deg,#F4F6FA 10%,#2DD4E8);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}

/* --- text-splitting primitives (used by main.js) --- */
.sp-line{display:block; overflow:hidden}
.sp-line > span{display:block; will-change:transform}
.sp-word{display:inline-block; overflow:hidden; vertical-align:top}
.sp-word > span{display:inline-block; will-change:transform}
.sp-char{display:inline-block; will-change:transform}

/* ==========================================================================
   4. PRELOADER
   ========================================================================== */
#load{
  position:fixed; inset:0; z-index:200; background:var(--bg);
  display:grid; place-items:center; overflow:hidden;
}
#load .lcol{
  position:absolute; top:0; bottom:0; width:calc(100% / 5 + 1px);
  background:var(--bg); will-change:transform;
}
#load .lcol:nth-child(1){left:0}
#load .lcol:nth-child(2){left:20%}
#load .lcol:nth-child(3){left:40%}
#load .lcol:nth-child(4){left:60%}
#load .lcol:nth-child(5){left:80%}
/* "Too much empty space" — the block was set on viewport-height gaps, which on
   a tall desktop window pushed the lockup and the line a long way apart. The
   gaps are tighter and no longer grow with the window. */
.load-in{
  position:relative; z-index:3; width:min(680px,88vw);
  display:flex; flex-direction:column; align-items:center;
  gap:clamp(14px,1.6vw,22px);
}
/* The supplied lockup, cropped just below the disciplines line: the artwork's
   own "Where Trust Moves Trade" would otherwise repeat the headline that the
   timeline spells out underneath it. The wrapper's aspect ratio does the
   cropping, so there is still only one logo file on the site. */
.load-logo{
  display:block; width:min(240px,54vw); aspect-ratio:1280/1010;
  overflow:hidden; opacity:0;
}
.load-logo img{width:100%; height:auto; display:block}

/* the headline assembles a word at a time, a hairline drawing between each */
/* The line is revealed by one wipe travelling across it, rather than a word at
   a time with a hairline drawn between each pair. --rev runs 0 -> 1 and moves
   a soft edge from before the first letter to past the last, so the sentence
   arrives as a single movement. At 0 the mask is entirely transparent, at 1
   entirely opaque, and the 24% soft band is what keeps the edge from reading
   as a hard shutter. */
.load-line{
  --rev:0;
  margin:0; display:flex; flex-wrap:wrap; align-items:baseline; justify-content:center;
  gap:.06em clamp(10px,1.4vw,18px);
  font-family:var(--f-ui); font-weight:200; letter-spacing:-.012em;
  font-size:clamp(1.9rem,5.4vw,3.6rem); line-height:1.1; color:var(--tx);
  -webkit-mask-image:linear-gradient(96deg,
    #000 calc(var(--rev) * 148% - 30%),
    rgba(0,0,0,0) calc(var(--rev) * 148% - 6%));
  mask-image:linear-gradient(96deg,
    #000 calc(var(--rev) * 148% - 30%),
    rgba(0,0,0,0) calc(var(--rev) * 148% - 6%));
}
.load-line .lw-em{
  background:linear-gradient(96deg,var(--violet),var(--cyan));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.load-line .lw{display:inline-block}
@media (prefers-reduced-motion:reduce){
  /* nothing to travel: the line is simply there */
  .load-line{--rev:1; -webkit-mask-image:none; mask-image:none}
}

.load-bar{width:100%; align-self:stretch; height:1px; background:var(--hair); position:relative; overflow:hidden}
.load-bar i{
  position:absolute; inset:0; transform-origin:left; transform:scaleX(0);
  background:linear-gradient(90deg,var(--violet),var(--cyan));
}

/* ==========================================================================
   5. CHROME — progress bar, cursor, header
   ========================================================================== */
.prog{position:fixed; top:0; left:0; right:0; height:2px; z-index:130; pointer-events:none}
.prog i{
  display:block; height:100%; width:100%; transform:scaleX(0); transform-origin:left;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
}

/* The cursor carries the logo gradient rather than a neutral dot. A drop
   shadow rather than mix-blend-mode, so it stays legible on white, on the
   dark media sections and over photography alike — difference blending
   inverts the gradient into colours that are not the brand's. */
.cur,.cur-d{
  position:fixed; top:0; left:0; z-index:195; pointer-events:none;
  border-radius:50%; will-change:transform;
}
.cur{
  width:9px; height:9px; margin:-4.5px 0 0 -4.5px;
  background:linear-gradient(140deg,var(--violet),var(--cyan));
  box-shadow:0 0 0 1px rgba(255,255,255,.28), 0 2px 10px rgba(12,15,22,.35);
}
.cur-d{
  width:38px; height:38px; margin:-19px 0 0 -19px;
  border:1px solid var(--cyan); opacity:.55;
  transition:width .35s var(--ease), height .35s var(--ease), margin .35s var(--ease),
             border-color .35s, opacity .35s;
}
.cur-d.hot{width:64px; height:64px; margin:-32px 0 0 -32px; border-color:var(--violet); opacity:.9}
@media (hover:none),(pointer:coarse){.cur,.cur-d{display:none}}

.hdr{
  position:fixed; inset:0 0 auto 0; z-index:100; padding:26px 0;
  border-bottom:1px solid transparent;
  transition:padding .5s var(--ease), background .5s var(--ease),
             border-color .5s, transform .55s var(--ease);
}
.hdr.stuck{
  padding:14px 0; background:var(--panel);
  backdrop-filter:blur(12px) saturate(1.25); -webkit-backdrop-filter:blur(12px) saturate(1.25);
  border-bottom-color:var(--hair-2);
}
.hdr.hide{transform:translateY(-102%)}
.hdr .wrap{display:flex; align-items:center; justify-content:space-between; gap:22px}
/* header floats over the dark hero until stuck → media tokens up top */
.hdr .wm,.hdr .menu a{color:var(--on-media)}
.hdr .tag{color:var(--on-media-3)}
.hdr.stuck .wm,.hdr.stuck .menu a{color:var(--tx)}
.hdr.stuck .tag{color:var(--tx-4)}

.mark{display:flex; align-items:center; gap:14px}
.mark svg{width:32px; height:36px; flex:none}
/* The client's own artwork, used as supplied wherever the ground is white. */
.mark-i{width:34px; height:auto; flex:none}
.mark-w{width:118px; height:auto; display:block}
.mark-i,.mark-w{transition:filter .5s var(--ease)}
/* Over the hero it is a different problem. The wordmark's gradient runs from
   dark violet to mid blue — built for a white page — so on photography it
   effectively vanishes, which is exactly how the header read once the hero
   became the catalogue. While the header floats it is drawn in white; the
   monogram keeps its colour and gains a shadow to hold its edge. The moment
   the header sticks to the light panel both revert to the supplied artwork.
   Inner pages carry `.is-inner`, which pins the header solid from the first
   pixel, so this only ever applies over the homepage hero. */
.hdr:not(.stuck) .mark-w{
  filter:brightness(0) invert(1) drop-shadow(0 1px 12px rgba(4,6,13,.5));
}
.hdr:not(.stuck) .mark-i{
  filter:drop-shadow(0 1px 10px rgba(4,6,13,.55)) saturate(1.15) brightness(1.28);
}
.mark .wm{font-size:15px; font-weight:300; letter-spacing:.52em; line-height:1; padding-left:2px; transition:color .4s}
.mark .tag{
  font-family:var(--f-mono); font-size:7.5px; letter-spacing:.26em;
  text-transform:uppercase; margin-top:6px; display:block; transition:color .4s;
}
.menu{display:flex; align-items:center; gap:32px}
.menu a{
  font-size:12.5px; letter-spacing:.2em; text-transform:uppercase;
  position:relative; padding:8px 0; opacity:.82;
  transition:color .35s, opacity .35s;
}
.menu a::after{
  content:""; position:absolute; left:0; bottom:2px; height:1px; width:0;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
  transition:width .45s var(--ease);
}
.menu a:hover{opacity:1}
.menu a:hover::after,.menu a.on::after{width:100%}

.hdr-tools{display:flex; align-items:center; gap:10px}
.hdr-cta{
  background:transparent; border:1px solid var(--media-hair); color:var(--on-media);
  padding:12px 22px; min-height:44px; font-size:11.5px; letter-spacing:.22em;
  text-transform:uppercase; position:relative; overflow:hidden;
  display:inline-flex; align-items:center; transition:color .4s, border-color .4s;
}
.hdr.stuck .hdr-cta{border-color:var(--hair); color:var(--tx)}
.hdr-cta span{position:relative; z-index:2}
.hdr-cta::before{
  content:""; position:absolute; inset:0;
  background:linear-gradient(100deg,var(--violet),var(--cyan));
  transform:scaleX(0); transform-origin:left; transition:transform .5s var(--ease);
}
.hdr-cta:hover,.hdr.stuck .hdr-cta:hover{color:#04060D; border-color:transparent}
.hdr-cta:hover::before{transform:scaleX(1)}

.burger{display:none; color:var(--on-media); padding:11px; z-index:120}
.hdr.stuck .burger{color:var(--tx)}

/* ==========================================================================
   6. HERO — WebGL port world + oversized display type
   ========================================================================== */
/* Full viewport, edge to edge. `vh` first for browsers without `svh`; `svh`
   then wins on mobile, where it excludes the collapsing browser chrome. */
.hero{
  position:relative; height:100vh; height:100svh; min-height:600px;
  overflow:hidden; background:var(--media-bg);
}
.hero-gl{
  position:absolute; inset:0; z-index:0; overflow:hidden; background:var(--media-bg);
}
.hero-gl canvas{display:block; width:100%; height:100%}
/* The catalogue frames are graded here rather than in the files, so the same
   photography serves both a bright category tile and this dark hero. Product
   colour is left further up than the old footage allowed — the point of the
   section is that there is product behind the line — while brightness and
   contrast do the work of keeping the type legible over any frame. */
.hero-slides{position:absolute; inset:0; overflow:hidden; transform-origin:50% 50%; will-change:transform}
.hero-sl{
  position:absolute; inset:0; display:block;
  width:100%; height:100%; object-fit:cover; object-position:50% 22%;
  opacity:0; transform:scale(1.06); transform-origin:50% 50%;
  filter:saturate(.9) brightness(.6) contrast(1.03);
  will-change:transform,opacity;
}
/* The first frame is up before any script runs, so the hero is never an empty
   box and stays correct if JavaScript never arrives. */
.hero-sl.is-on{opacity:1}
@media (prefers-reduced-motion:reduce){
  /* one frame, held: nothing cycles and nothing drifts */
  .hero-sl{transform:none}
  .hero-sl:not(.is-on){display:none}
}
.hero-veil{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  /* The catalogue frames vary from a dark showroom to bright produce, so the
     type can no longer rely on the picture being dark. A soft ellipse sits
     directly under the line and does that job locally, which lets the frames
     themselves keep their colour instead of being crushed flat. */
  background:
    radial-gradient(56% 40% at 50% 47%,rgba(4,6,13,.22) 0%,rgba(4,6,13,0) 100%),
    radial-gradient(125% 80% at 50% 6%,rgba(4,6,13,0) 40%,rgba(4,6,13,.30) 100%),
    linear-gradient(180deg,rgba(4,6,13,.44) 0%,rgba(4,6,13,0) 32%,rgba(4,6,13,0) 56%,rgba(4,6,13,.58) 100%);
}
.hero-noise{position:absolute; inset:0; z-index:2; pointer-events:none; opacity:.5;
  background:repeating-linear-gradient(0deg,rgba(4,6,13,.16) 0 1px,transparent 1px 3px)}

/* the 25-style display lockup */
/* .hero-type — display words removed at the client's request */
/* Display lockup, sized and weighted against the reference.
   Size: the reference word runs ~80px per glyph. Matching its total WIDTH
   made ours far bigger per letter, because "THALEON" is 7 glyphs where
   "Twenty five" is 11 — so these are set by letter size (~8vw), not by how
   much of the viewport the word spans.
   Weight: the reference sets its display type solid, not hairline. 600 for
   the sans and 600 for the serif give it that presence; the rest of the page
   keeps its light 200 headings, so the hero stays the loudest thing on it. */
.hero-word{
  position:absolute; font-weight:600; line-height:.88;
  text-transform:uppercase; letter-spacing:-.005em; color:var(--on-media);
  font-size:clamp(2.3rem,8vw,8.6rem); white-space:nowrap;
}
.hero-word.a{top:clamp(92px,12vh,140px); left:var(--gut)}
.hero-word.b{
  right:var(--gut); bottom:clamp(100px,12.5vh,150px);
  font-family:var(--f-serif); font-weight:600; font-style:italic;
  text-transform:lowercase; letter-spacing:-.015em;
  /* the serif carries a smaller x-height, so it needs a touch more size to
     read at the same visual weight as the sans opposite it */
  font-size:clamp(2.6rem,9.4vw,10rem);
}
.hero-foot{
  position:absolute; z-index:5; left:0; right:0; bottom:clamp(96px,12vh,140px);
  pointer-events:none;
}
/* A pool of shade under the lede only. The full-width scrim was lightened so
   the render reaches the bottom edge, so contrast is bought back locally
   instead of by darkening the whole frame. */
.hero-foot::before{
  content:""; position:absolute; z-index:-1; pointer-events:none;
  inset:-70px -20% -90px -12%;
  background:radial-gradient(70% 110% at 26% 55%,rgba(4,6,13,.78) 0%,rgba(4,6,13,.42) 45%,rgba(4,6,13,0) 72%);
}
.hero-foot .wrap{pointer-events:auto; max-width:var(--wrap)}
.hero-lede{
  font-size:clamp(1.05rem,1.95vw,1.65rem); font-weight:300; line-height:1.2;
  letter-spacing:.01em; color:var(--on-media); margin:0 0 14px; max-width:20ch;
}
.hero-lede b{font-weight:500}
.hero-meta{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.26em;
  text-transform:uppercase; color:var(--on-media-3); margin:0; line-height:2.1;
}
.hero-meta b{color:var(--on-media-2); font-weight:400}
.hero-act{display:flex; flex-wrap:wrap; gap:14px; margin-top:26px}

/* centred at the very bottom so it can never collide with the display type */
.scrollcue{
  position:absolute; z-index:6; left:50%; transform:translateX(-50%); bottom:30px;
  display:flex; align-items:center; gap:14px; font-family:var(--f-mono);
  font-size:9.5px; letter-spacing:.3em; text-transform:uppercase; color:var(--on-media-3);
}
.scrollcue i{display:block; width:52px; height:1px; background:var(--media-hair); position:relative; overflow:hidden}
.scrollcue i::after{
  content:""; position:absolute; top:0; left:-50%; width:50%; height:1px;
  background:var(--accent-media); animation:sweep 2.4s var(--ease) infinite;
}
@keyframes sweep{to{left:100%}}

/* ==========================================================================
   7. BUTTONS
   ========================================================================== */
.btn{
  display:inline-flex; align-items:center; gap:14px; justify-content:center;
  padding:16px 30px; min-height:48px; font-size:11.5px; letter-spacing:.24em;
  text-transform:uppercase; background:var(--btn-bg); color:var(--btn-tx);
  border:1px solid var(--btn-bg); position:relative; overflow:hidden;
  transition:color .45s, border-color .45s; will-change:transform;
}
.btn span{position:relative; z-index:2}
.btn svg{
  position:relative; z-index:2; width:15px; height:9px;
  stroke:currentColor; fill:none; stroke-width:1.2; transition:transform .45s var(--ease);
}
.btn::before{
  content:""; position:absolute; inset:0;
  background:linear-gradient(100deg,var(--violet),var(--cyan));
  transform:translateY(101%); transition:transform .5s var(--ease);
}
.btn:hover::before{transform:translateY(0)}
.btn:hover svg{transform:translateX(6px)}
.btn-line{background:transparent; color:var(--tx); border-color:var(--hair)}
.btn-line:hover{color:#04060D; border-color:transparent}
/* buttons over media keep fixed colours in both themes */
.hero .btn,.bleed .btn,.on-media .btn{background:#F4F6FA; color:#04060D; border-color:#F4F6FA}
.hero .btn:hover,.bleed .btn:hover,.on-media .btn:hover{color:#04060D}
.hero .btn-line,.bleed .btn-line,.on-media .btn-line{background:transparent; color:#F4F6FA; border-color:rgba(244,246,250,.3)}
.hero .btn-line:hover,.bleed .btn-line:hover,.on-media .btn-line:hover{color:#04060D; border-color:transparent}

/* ==========================================================================
   8. MARQUEE BAND (velocity-reactive)
   ========================================================================== */
.band{
  border-top:1px solid var(--hair-2); border-bottom:1px solid var(--hair-2);
  padding:26px 0; overflow:hidden; background:var(--bg-2);
}
.track{display:flex; width:max-content; will-change:transform}
.track span{
  font-family:var(--f-ui); font-weight:200; font-size:clamp(1.5rem,3.6vw,3rem);
  letter-spacing:.16em; text-transform:uppercase; color:transparent;
  -webkit-text-stroke:.6px var(--stroke); padding:0 26px; white-space:nowrap;
}
.track span.fill{color:var(--tx); -webkit-text-stroke:0}
.track span.dot{color:var(--accent); -webkit-text-stroke:0}

/* ==========================================================================
   9. SECTION SHELL
   ========================================================================== */
.sec{padding:clamp(96px,12vw,180px) 0; position:relative}
.sec-hd{display:grid; grid-template-columns:1fr auto; gap:34px; align-items:end; margin-bottom:clamp(44px,6vw,80px)}
.sec-hd .body-t{margin:22px 0 0}

/* ==========================================================================
   10. MANIFESTO — pinned, word-by-word scrubbed reveal
   ========================================================================== */
.manifesto{background:var(--bg); padding:clamp(90px,11vw,150px) 0; position:relative; overflow:hidden}
.manifesto .wrap{max-width:1180px; position:relative; z-index:2}
/* current-field canvas — sits behind the type, fades in from the edges */
.mf-gl{position:absolute; inset:0; z-index:0; pointer-events:none; opacity:0}
.mf-gl canvas{display:block; width:100%; height:100%}
.mf-gl{opacity:0; mix-blend-mode:multiply}

.mf-body{position:relative; padding-left:clamp(22px,3.4vw,46px)}
/* thread that draws down beside the paragraph as it is read */
.mf-thread{position:absolute; left:0; top:6px; bottom:6px; width:1px; background:var(--hair-2)}
.mf-thread i{
  position:absolute; inset:0; transform:scaleY(0); transform-origin:top;
  background:linear-gradient(180deg,var(--violet),var(--cyan));
}
.mf-thread b{
  position:absolute; left:-3px; top:0; width:7px; height:7px; margin-top:-3.5px;
  border-radius:50%; background:var(--cyan); opacity:0;
  box-shadow:0 0 12px 2px rgba(45,212,232,.6);
}
.mf-h{
  font-weight:200; font-size:clamp(1.9rem,5.4vw,4.4rem); line-height:1.06;
  letter-spacing:.02em; text-transform:uppercase; margin:0 0 44px;
}
.mf-h em{
  font-family:var(--f-serif); font-style:italic; font-weight:300;
  text-transform:none; letter-spacing:0;
}
.mf-p{
  font-size:clamp(1.05rem,2.15vw,1.85rem); line-height:1.5; font-weight:300;
  max-width:34ch; margin:0; color:var(--tx-4);
}
.mf-p .sp-char{transition:none}
.mf-foot{
  display:grid; grid-template-columns:repeat(3,1fr); gap:30px;
  margin-top:clamp(52px,7vw,92px); padding-top:34px;
  border-top:1px solid var(--hair-2); position:relative;
}
.mf-stat{position:relative; padding-top:4px}
/* rule injected by main.js so GSAP can scale it */
.mf-stat .mf-rule{
  position:absolute; top:-35px; left:0; right:0; height:1px;
  transform:scaleX(0); transform-origin:left;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
}
.mf-foot .n{
  font-family:var(--f-ui); font-weight:200; font-size:clamp(2.2rem,4.6vw,3.6rem);
  line-height:1; letter-spacing:-.01em; margin:0 0 10px; display:block;
  background:linear-gradient(160deg,var(--tx) 30%,var(--accent));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.mf-foot .n i{font-style:normal}
.mf-foot .l{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.22em;
  text-transform:uppercase; color:var(--tx-4);
}

/* ==========================================================================
   11. EXPANDING MEDIA — the "grows to full-bleed on scroll" block
   ========================================================================== */
.grow{background:var(--bg); padding:0 0 clamp(70px,9vw,120px)}
/* The window opens by CLIPPING, never by resizing. Animating width/height
   forces a layout pass on every scroll frame — that was the source of the
   stutter — while clip-path only repaints, so the expansion stays smooth. */
.grow-stage{
  position:relative; height:100svh; min-height:560px; overflow:hidden;
}
.grow-frame{
  position:absolute; inset:0; margin:0; width:100%; height:100%;
  background:var(--media-bg); will-change:clip-path;
  /* opening state — overwritten by main.js, kept here so the first paint is
     already the small card rather than a full-bleed flash */
  clip-path:inset(18% 7% round 26px);
}
.grow-frame > img,.grow-frame > video{
  width:100%; height:100%; object-fit:cover; will-change:transform;
  /* The grade here was set for the old production-line clip, which was shot at
     dawn and needed pulling down. The client's globe footage is already a dark
     night scene lit only by city light, so the same treatment buried it. It is
     left close to as-shot, with a touch of contrast to hold the network lines. */
  filter:saturate(1.02) contrast(1.06) brightness(.96);
}
/* the clip sits over the still and cross-fades in once it can actually play */
.grow-frame > video{position:absolute; inset:0; opacity:0; transition:opacity .9s var(--ease)}
.grow-frame > video.on{opacity:1}
/* Colour grade that lifts as the window opens. `overlay` tints while keeping
   the footage's own luminance — `color` would replace the hue outright and
   flatten the sunrise to grey. */
.grow-grade{
  position:absolute; inset:0; z-index:2; pointer-events:none; opacity:.42;
  background:linear-gradient(180deg,rgba(20,86,102,.85),rgba(4,6,13,.25) 48%,rgba(122,63,242,.5));
  mix-blend-mode:overlay;
}
/* fine broadcast lines, strongest while the frame is still a small window */
.grow-scan{
  position:absolute; inset:0; z-index:2; pointer-events:none; opacity:.5;
  background:repeating-linear-gradient(0deg,rgba(4,6,13,.28) 0 1px,transparent 1px 3px);
}
.grow-tc{font-variant-numeric:tabular-nums; color:var(--on-media-2)}
.grow-frame::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg,rgba(4,6,13,.45),rgba(4,6,13,.15) 45%,rgba(4,6,13,.8));
}
.grow-cap{
  position:absolute; z-index:3; left:0; right:0; bottom:18%;
  padding:clamp(24px,3.4vw,52px) clamp(30px,8vw,110px); color:var(--on-media);
  display:flex; justify-content:space-between; align-items:flex-end; gap:26px; flex-wrap:wrap;
  will-change:bottom;
}
.grow-cap h3{
  font-weight:200; font-size:clamp(1.5rem,3.6vw,3rem); letter-spacing:.05em;
  text-transform:uppercase; margin:0; line-height:1.08;
}
.grow-cap h3 em{font-family:var(--f-serif); font-style:italic; text-transform:none; letter-spacing:0}
.grow-cap .rt{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.22em;
  text-transform:uppercase; color:var(--on-media-3); text-align:right; line-height:2;
}
/* ==========================================================================
   12. CAPABILITIES — pinned horizontal scroll
   ========================================================================== */
.cap{background:var(--bg); color:var(--tx); overflow:hidden}
.cap-pin{position:relative; height:100svh; min-height:620px; display:flex; align-items:center}
.cap-rail{display:flex; align-items:center; gap:clamp(18px,2.4vw,34px); padding:0 var(--gut); will-change:transform}
.cap-intro{flex:none; width:min(420px,74vw)}
.cap-intro .kicker{color:var(--accent)}
.cap-intro h2{color:var(--tx)}
.cap-intro p{color:var(--tx-4); font-size:15px; margin:22px 0 0; max-width:38ch}
.cap-card{
  flex:none; position:relative; width:min(500px,80vw); height:min(70vh,660px);
  border-radius:var(--r-lg); overflow:hidden; background:#080C17;
  display:flex; flex-direction:column; justify-content:flex-end;
  padding:clamp(26px,3vw,44px); isolation:isolate;
}
.cap-card .ci{position:absolute; inset:0; z-index:-2; overflow:hidden}
.cap-card .ci img{
  position:absolute; left:0; top:-14%;
  width:100%; height:128%; object-fit:cover;
  filter:saturate(.72) brightness(.62); will-change:transform;
}
.cap-card::after{
  content:""; position:absolute; inset:0; z-index:-1;
  background:linear-gradient(180deg,rgba(4,6,13,.25) 0%,rgba(4,6,13,.55) 45%,rgba(4,6,13,.95) 100%);
}
.cap-card .no{
  position:absolute; top:clamp(24px,3vw,40px); left:clamp(26px,3vw,44px);
  font-family:var(--f-mono); font-size:11px; letter-spacing:.24em; color:var(--accent-media);
}
.cap-card .core{
  position:absolute; top:clamp(24px,3vw,40px); right:clamp(26px,3vw,44px);
  font-family:var(--f-mono); font-size:9px; letter-spacing:.22em; text-transform:uppercase;
  color:#04060D; background:linear-gradient(100deg,var(--violet),var(--cyan)); padding:5px 11px;
}
.cap-card h3{
  font-weight:200; font-size:clamp(1.7rem,3vw,2.6rem); letter-spacing:.12em;
  text-transform:uppercase; margin:0 0 6px; color:var(--on-media);
}
.cap-card .zh{
  font-family:var(--f-ui); font-style:normal; font-weight:300; font-size:1.08rem;
  letter-spacing:.005em; color:var(--accent-media); margin:0 0 18px; display:block;
}
.cap-card p{color:var(--on-media-2); font-size:14.5px; margin:0; max-width:40ch}
.cap-card ul{list-style:none; margin:22px 0 20px; padding:0}
.cap-card li{
  font-family:var(--f-mono); font-size:10.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--on-media-3); padding:8px 0; border-bottom:1px solid var(--media-hair-2);
}
.cap-link{
  display:inline-flex; align-items:center; gap:12px; min-height:44px;
  color:var(--on-media); font-size:11px; letter-spacing:.24em; text-transform:uppercase;
}
.cap-link svg{width:20px; height:9px; stroke:var(--accent-media); fill:none; stroke-width:1.2; transition:transform .4s var(--ease)}
.cap-link:hover svg{transform:translateX(7px)}
.cap-count{
  position:absolute; right:var(--gut); bottom:clamp(30px,5vh,58px); z-index:5;
  font-family:var(--f-mono); font-size:10px; letter-spacing:.26em; color:var(--tx-4);
}
.cap-count b{color:var(--tx); font-weight:400}
.cap-track{
  position:absolute; left:var(--gut); right:var(--gut); bottom:clamp(24px,4vh,44px);
  height:1px; background:var(--hair-2); z-index:5;
}
.cap-track i{display:block; height:100%; width:100%; transform:scaleX(0); transform-origin:left; background:linear-gradient(90deg,var(--violet),var(--cyan))}
/* ==========================================================================
   12b. THE CATALOGUE — 36-category mosaic + the category detail view
   Tiles always carry their own scrim, so captions stay legible in both
   themes from one set of rules. Every third card spans two rows, which puts
   the cell count at 48 — it tiles exactly at 6, 4, 3 and 2 columns, so the
   dense packing never leaves a hole.
   ========================================================================== */
.cat-shell{position:relative}
.cat-grid{
  display:grid; gap:clamp(8px,0.9vw,14px);
  grid-template-columns:repeat(6,1fr);
  grid-auto-rows:clamp(112px,10.6vw,168px);
  grid-auto-flow:dense;
  perspective:1400px;
}
.cat-card{
  position:relative; overflow:hidden; isolation:isolate;
  border-radius:calc(var(--r-lg) * .5); background:#080C17;
  display:flex; flex-direction:column; justify-content:flex-end;
  padding:clamp(13px,1.15vw,20px);
  transform-style:preserve-3d; will-change:transform,opacity;
}
.cat-card.is-tall{grid-row:span 2}
.cat-card .ci{position:absolute; inset:0; z-index:-2; overflow:hidden}
.cat-card .ci img{
  position:absolute; left:0; top:-4%;
  width:100%; height:108%; object-fit:cover;
  filter:saturate(.8) brightness(.88) contrast(1.02);
  will-change:transform; transition:filter .6s var(--ease);
}
/* The scrim used to start fully transparent, which left the index number
   sitting on bare photograph. On the pale cards — Wood, Renewable Energy,
   Paper, Construction — that number was effectively invisible, which is what
   the client meant by "I can barely read the number '8' or '9'" (02-09,
   re-flagged 03-09). It now carries a short top fade as well as the bottom
   one, so the number always has a dark ground under it whatever the picture
   does, and the middle of the image is left alone. */
.cat-card::after{
  content:""; position:absolute; inset:0; z-index:-1;
  background:linear-gradient(180deg,
    rgba(4,6,13,.58) 0%,
    rgba(4,6,13,.22) 15%,
    rgba(4,6,13,.10) 30%,
    rgba(4,6,13,.28) 52%,
    rgba(4,6,13,.92) 100%);
  transition:opacity .5s var(--ease);
}
.cat-card .cn{
  position:absolute; top:clamp(11px,1.1vw,18px); left:clamp(13px,1.15vw,20px);
  font-family:var(--f-mono); font-size:10.5px; font-weight:500; letter-spacing:.22em;
  color:var(--accent-media);
  text-shadow:0 1px 3px rgba(4,6,13,.85);
  transition:transform .55s var(--ease);
}
.cat-card .ct{
  margin:0; color:var(--on-media);
  font-weight:300; font-size:clamp(.8rem,1.02vw,1.06rem);
  letter-spacing:.045em; text-transform:uppercase; line-height:1.18;
}
.cat-card .cc{
  display:block; margin-top:7px;
  font-family:var(--f-mono); font-size:9px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--on-media-3);
  opacity:0; transform:translateY(8px);
  transition:opacity .45s var(--ease), transform .45s var(--ease);
}
/* the subcategory list lives in the markup for search engines and for the
   detail view to read — it is never drawn in the grid itself */
.cat-card .cs{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}
.cat-hit{
  position:absolute; inset:0; z-index:2; cursor:pointer;
  background:none; border:0; padding:0; border-radius:inherit;
}
.cat-hit:focus-visible{outline:2px solid var(--accent-media); outline-offset:-3px}

.cat-card .ci{transition:transform .9s var(--ease)}
.cat-card:hover .ci,
.cat-card:focus-within .ci{transform:scale(1.05)}
.cat-card:hover .ci img,
.cat-card:focus-within .ci img{filter:saturate(1) brightness(1.02) contrast(1.04)}
.cat-card:hover .cc,
.cat-card:focus-within .cc{opacity:1; transform:none}
.cat-card:hover .cn,
.cat-card:focus-within .cn{transform:translateX(3px)}

/* running position indicator, mirrors the capabilities rail */
.cat-count{
  position:sticky; bottom:clamp(18px,3vh,34px); float:right;
  margin:14px var(--gut) 0 0;
  font-family:var(--f-mono); font-size:10px; letter-spacing:.26em; color:var(--tx-3);
  pointer-events:none;
}
.cat-count b,.cat-count span{color:var(--tx); font-weight:400}

.cat-foot{
  margin-top:clamp(38px,4.6vw,68px);
  display:grid; grid-template-columns:1fr auto; gap:34px; align-items:end;
}
.cat-note{color:var(--tx-3); font-size:15px; font-weight:300; max-width:52ch; margin:0}

/* --------------------------------------------------------- detail view --- */
.cat-view{
  position:fixed; inset:0; z-index:260;
  display:grid; grid-template-columns:52fr 48fr;
}
.cat-view[hidden]{display:none}
.cv-scrim{
  position:absolute; inset:0; z-index:0; border:0; padding:0;
  background:var(--scrim); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  opacity:0;
}
/* the media block is positioned in JS: it starts life exactly over the card
   that was clicked and travels to this slot, so the two views feel continuous */
.cv-media{
  position:fixed; margin:0; z-index:2; overflow:hidden;
  border-radius:calc(var(--r-lg) * .5); background:#080C17;
  will-change:top,left,width,height;
}
/* Client, 05-09: on the card the picture reads fine, but opening it showed a
   cropped version. The expanded view is where you go to look at the picture,
   so it shows the whole of it — contain, on the card ground, rather than a
   cover crop. */
.cv-media img{width:100%; height:100%; object-fit:contain; display:block}
.cv-media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg,rgba(4,6,13,.1),rgba(4,6,13,.5));
}
.cv-panel{
  position:relative; z-index:3; grid-column:2;
  align-self:center; padding:clamp(28px,4vw,72px) clamp(24px,4.5vw,80px);
  max-height:100vh; overflow-y:auto; overscroll-behavior:contain;
}
.cv-back{
  display:inline-flex; align-items:center; gap:12px; min-height:44px;
  background:none; border:0; padding:0; cursor:pointer;
  color:var(--on-media-2); font-family:var(--f-mono);
  font-size:10px; letter-spacing:.22em; text-transform:uppercase;
}
.cv-back svg{width:20px; height:10px; fill:none; stroke:var(--accent-media); stroke-width:1.2; transition:transform .4s var(--ease)}
.cv-back:hover svg{transform:translateX(-6px)}
/* the panel moves focus here on open, so suppress the ring for pointer users
   and keep it for keyboard ones */
.cv-back:focus{outline:none}
.cv-back:focus-visible{outline:1px solid var(--accent-media); outline-offset:6px}
.cv-no{
  display:block; margin-top:clamp(22px,3vw,40px);
  font-family:var(--f-mono); font-size:10px; letter-spacing:.26em; color:var(--accent-media);
}
.cv-title{
  margin:12px 0 0; color:var(--on-media);
  font-weight:200; font-size:clamp(1.6rem,3.5vw,3.1rem);
  letter-spacing:.045em; text-transform:uppercase; line-height:1.06;
}
.cv-meta{
  display:block; margin-top:14px;
  font-family:var(--f-serif); font-style:italic; font-size:1.05rem; color:var(--accent-media);
}
.cv-sub{
  list-style:none; margin:clamp(22px,3vw,38px) 0 clamp(26px,3.4vw,44px); padding:0;
  columns:2; column-gap:26px;
}
.cv-sub li{
  break-inside:avoid;
  font-family:var(--f-mono); font-size:10.5px; letter-spacing:.13em; text-transform:uppercase;
  color:var(--on-media-2); padding:9px 0;
  border-bottom:1px solid var(--media-hair-2);
}
.cat-view .btn{background:var(--btn-bg); color:var(--btn-tx)}
/* the panel always sits on dark glass, so it keeps the media palette in
   light theme too rather than inheriting the page's paper tones */
.cv-scrim{background:rgba(4,6,13,.82)}
.cat-view .btn{background:#F4F6FA; color:#04060D}

@media (max-width:1200px){
  .cat-grid{grid-template-columns:repeat(4,1fr); grid-auto-rows:clamp(112px,14vw,168px)}
}
@media (max-width:900px){
  .cat-view{grid-template-columns:1fr; grid-template-rows:38vh 1fr}
  .cv-panel{grid-column:1; grid-row:2; align-self:start; padding-top:clamp(20px,4vw,32px)}
  .cv-sub{columns:1}
}
@media (max-width:760px){
  .cat-grid{grid-template-columns:repeat(3,1fr); grid-auto-rows:clamp(104px,20vw,150px)}
  .cat-card{padding:11px}
  .cat-card .ct{font-size:clamp(.66rem,2.4vw,.84rem); letter-spacing:.03em}
  .cat-card .cn{top:9px; left:11px; font-size:9.5px}
  /* touch has no hover — the count is simply always shown */
  .cat-card .cc{opacity:1; transform:none; font-size:8px; margin-top:5px}
  .cat-foot{grid-template-columns:1fr}
  .cat-count{display:none}
}
@media (max-width:460px){
  .cat-grid{grid-template-columns:repeat(2,1fr); grid-auto-rows:clamp(120px,30vw,168px)}
  .cat-card .ct{font-size:clamp(.74rem,3.4vw,.95rem)}
}
/* ==========================================================================
   13. BLEED (parallax statement panels)
   ========================================================================== */
.bleed{
  position:relative; min-height:clamp(560px,90vh,900px);
  display:grid; place-items:center; overflow:hidden; text-align:center;
  padding-block:clamp(72px,9vh,120px);
  background:var(--media-bg);
}
.bleed.is-cta{min-height:clamp(520px,82vh,860px)}
.bleed-img{position:absolute; inset:-16% 0; z-index:0; will-change:transform}
.bleed-img img{width:100%; height:100%; object-fit:cover; filter:saturate(.3) brightness(.46)}
.bleed::after{
  content:""; position:absolute; inset:0; z-index:1;
  background:radial-gradient(ellipse at center,rgba(4,6,13,.4) 0%,rgba(4,6,13,.94) 78%);
}
.bleed.is-cta::after{
  background:radial-gradient(ellipse at center,
    rgba(4,6,13,.72) 0%, rgba(4,6,13,.82) 42%, rgba(4,6,13,.96) 84%);
}
.bleed.is-cta .bleed-img img{filter:saturate(.22) brightness(.34)}
.bleed .wrap{position:relative; z-index:3}
.bleed .kicker{color:var(--accent-media); justify-content:center}
.bleed .neg{
  font-weight:200; font-size:clamp(1.5rem,4.4vw,3.6rem); line-height:1.22;
  letter-spacing:.05em; text-transform:uppercase; margin:0 auto; max-width:20ch;
  color:var(--on-media);
}
.bleed .neg s{color:var(--on-media-3); text-decoration-color:rgba(122,63,242,.75); text-decoration-thickness:2px}
.bleed .neg em{
  font-family:var(--f-serif); font-style:italic; text-transform:none;
  letter-spacing:0; font-weight:300;
}
.bleed .body-t{margin:32px auto 0; text-align:center; max-width:58ch; color:var(--on-media-2)}

/* ---- POSITION — WebGL displacement over the still ---- */
.pos{min-height:clamp(620px,100svh,1000px)}
.pos-gl{position:absolute; inset:0; z-index:2; opacity:0; transition:opacity .8s var(--ease)}
.pos-gl.on{opacity:1}
.pos-gl canvas{display:block; width:100%; height:100%}
/* the canvas already grades the image, so the shared scrim is dialled back */
.pos::after{background:radial-gradient(ellipse at center,rgba(4,6,13,.18) 0%,rgba(4,6,13,.72) 82%)}
.pos .wrap{z-index:4}
.pos .neg{display:flex; flex-direction:column; gap:.1em; align-items:center; max-width:none}
/* outer span is the mask, inner span is what slides */
.pos .neg > span{display:block; overflow:hidden; padding-bottom:.06em}
.pos .neg > span > span{display:block; will-change:transform}
.pos .neg-b s{
  text-decoration:none; position:relative; color:var(--on-media-3);
  display:inline-block;
}
/* the strike is drawn by GSAP rather than rendered by the browser */
.pos .neg-b s .strike{
  position:absolute; left:-.04em; right:-.04em; top:52%; height:3px;
  transform:scaleX(0); transform-origin:left;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
  box-shadow:0 0 14px 1px rgba(122,63,242,.55);
}
.pos .neg-c em{
  font-family:var(--f-serif); font-style:italic; font-weight:300;
  text-transform:none; letter-spacing:0;
  background:linear-gradient(100deg,#F4F6FA 20%,#2DD4E8);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}

/* ==========================================================================
   14. HERITAGE
   ========================================================================== */
.her{background:var(--bg-2)}
.her-grid{display:grid; grid-template-columns:1fr 1fr; gap:clamp(34px,6vw,90px); align-items:start}
.her-sticky{position:sticky; top:110px}
.her-fig{position:relative; overflow:hidden; border-radius:var(--r-lg); border:1px solid var(--hair-2)}
.her-fig img{
  width:100%; aspect-ratio:4/5; object-fit:cover; will-change:transform,filter;
  /* archival state — GSAP scrubs this back to a clean modern image */
  filter:sepia(.85) saturate(.35) contrast(1.3) brightness(.62);
}
/* slats that lift away to uncover the plate */
.her-slats{position:absolute; inset:0; z-index:2; display:flex; pointer-events:none}
.her-slats i{flex:1 1 20%; background:var(--bg-2); transform-origin:bottom}
/* a developing bar that sweeps down once, like a plate being exposed */
.her-scan{
  position:absolute; left:0; right:0; top:0; height:26%; z-index:3; pointer-events:none; opacity:0;
  background:linear-gradient(180deg,transparent,rgba(45,212,232,.16) 60%,rgba(244,246,250,.5));
  mix-blend-mode:screen;
}
.her-meta{
  display:flex; justify-content:space-between; align-items:baseline; gap:16px;
  margin-top:16px; font-family:var(--f-mono); font-size:9px; letter-spacing:.26em;
  text-transform:uppercase; color:var(--tx-4);
}
.her-meta .her-yr{color:var(--accent); letter-spacing:.2em}
.her-fig figcaption{
  position:absolute; left:0; right:0; bottom:0; padding:20px 24px;
  background:linear-gradient(180deg,transparent,rgba(4,6,13,.94));
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em; text-transform:uppercase;
  color:var(--on-media-2); display:flex; justify-content:space-between; gap:14px;
}
.bignum{
  font-family:var(--f-ui); font-weight:200; font-size:clamp(5rem,13vw,11rem);
  line-height:.82; letter-spacing:-.02em; margin:0;
  background:linear-gradient(160deg,var(--tx) 20%,var(--accent));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.bignum-l{
  font-family:var(--f-mono); font-size:10px; letter-spacing:.3em; text-transform:uppercase;
  color:var(--tx-3); display:block; margin-top:14px;
}
.tl{list-style:none; margin:52px 0 0; padding:0}
.tl li{
  display:grid; grid-template-columns:120px 1fr; gap:26px;
  padding:24px 0; border-top:1px solid var(--hair-2); position:relative;
}
/* accent rule injected by main.js so GSAP can scale it */
.tl .tl-rule{
  position:absolute; top:-1px; left:0; height:1px; width:100%;
  transform:scaleX(0); transform-origin:left;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
}
.tl b{font-family:var(--f-mono); font-size:12px; letter-spacing:.14em; color:var(--accent); font-weight:400}
.tl span{color:var(--tx-3); font-size:14.5px}

/* ==========================================================================
   15. PROCESS — scrubbed progress spine
   ========================================================================== */
.proc{position:relative; padding-bottom:0}

/* ---- pinned assembly ---- */
.sec.proc{padding-bottom:0}
.proc-pin{position:relative; height:100svh; min-height:620px; overflow:hidden}
.proc-inner{
  height:100%; max-width:var(--wrap); margin:0 auto; padding:0 var(--gut);
  display:grid; grid-template-columns:1.15fr .85fr; gap:clamp(20px,4vw,64px); align-items:center;
}
.proc-stage{
  position:relative; height:min(80%,760px); border-radius:var(--r-lg); overflow:hidden;
  /* the assembly is drawn in pale greys; on a white page it needs a ground
     of its own or the whole left column reads as empty space */
  background:
    radial-gradient(ellipse 70% 55% at 50% 62%, var(--bg) 0%, var(--bg-2) 55%, var(--bg-3) 100%);
  border:1px solid var(--hair-2);
}
.proc-stage canvas{display:block; width:100%; height:100%}

/* stage rail */
.proc-panel{position:relative}
/* The rail is now the only place a stage number appears — the title used to
   repeat it, which read as the same "01" three times on one screen. So the
   rail has to do the counting visibly: the live stage steps up in size and
   takes the brand gradient, the ones behind it stay as plain marks. */
.proc-rail{
  list-style:none; margin:0 0 clamp(22px,3vw,38px); padding:0 0 18px;
  display:flex; align-items:baseline; gap:clamp(12px,1.8vw,26px);
  position:relative; border-bottom:1px solid var(--hair-2);
}
.proc-rail li{
  font-family:var(--f-mono); font-size:10.5px; letter-spacing:.24em; color:var(--tx-4);
  transition:color .45s var(--ease);
}
/* Size, not transform: a scaled glyph grows away from its own baseline and
   ends up floating above the row, where a font-size change keeps every
   number sitting on the same line. */
.proc-rail li span{
  display:inline-block; font-size:10.5px;
  transition:font-size .5s var(--ease), letter-spacing .5s var(--ease);
}
.proc-rail li.on{color:var(--accent)}
.proc-rail li.on span{
  font-size:20px; letter-spacing:.1em;
  background:linear-gradient(110deg,var(--violet),var(--cyan));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.proc-rail li.done{color:var(--tx-2)}
.proc-fill{
  position:absolute; left:0; bottom:-1px; height:1px; width:100%;
  transform:scaleX(0); transform-origin:left;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
}

/* cards are stacked; only the active stage is shown */
.proc-cards{position:relative; min-height:clamp(230px,30vh,300px)}
/* The handoff is deliberately not a crossfade. Two stacked cards fading
   through each other put the same sentence on screen twice, a few pixels
   apart — which is what read as a shudder on stage change. The outgoing card
   now clears before the incoming one starts. */
.stp{
  position:absolute; inset:0; opacity:0; pointer-events:none;
  transform:translate3d(0,10px,0);
  transition:opacity .26s var(--ease), transform .4s var(--ease);
}
.stp.is-on{
  opacity:1; transform:none; pointer-events:auto;
  transition:opacity .4s var(--ease) .12s, transform .5s var(--ease) .12s;
}
.stp h4{
  font-weight:300; font-size:clamp(1.5rem,3vw,2.4rem); letter-spacing:.04em;
  text-transform:uppercase; margin:0 0 16px; line-height:1.1; color:var(--tx);
}
.stp p{color:var(--tx-3); font-size:15px; margin:0 0 24px; max-width:40ch}
.stp .out{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--tx-4); border-top:1px solid var(--hair-2); padding-top:14px; max-width:40ch;
}
.stp .out b{display:block; color:var(--tx-2); font-weight:400; margin-top:5px}

/* no-JS / reduced motion: fall back to a readable five-column list */
.no-motion .proc-pin{height:auto; overflow:visible}
.no-motion .proc-inner{grid-template-columns:1fr; padding-bottom:60px}
.no-motion .proc-stage{height:52vh}
.no-motion .proc-cards{position:static; min-height:0; display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:26px}
.no-motion .stp{position:static; opacity:1; transform:none; pointer-events:auto}

/* ==========================================================================
   16. CORRIDORS — WebGL globe
   ========================================================================== */
.corr{background:var(--bg-2); position:relative; overflow:hidden}
.corr-grid{display:grid; grid-template-columns:.9fr 1.1fr; gap:clamp(34px,6vw,80px); align-items:center}
.globe-stage{
  position:relative; aspect-ratio:1/1; width:100%; max-height:78vh;
  margin-inline:auto; border-radius:50%;
}
.globe-stage canvas{display:block; width:100%; height:100%}
.globe-stage::after{
  content:""; position:absolute; inset:0; pointer-events:none; border-radius:50%;
  /* soft vignette that hides the square canvas corners without clipping the globe */
  background:radial-gradient(circle at 50% 50%,transparent 68%,var(--bg-2) 97%);
}
/* corridor node captions — positioned by webgl.js, so no layout properties here */
.glabel{
  position:absolute; top:0; left:0; z-index:3; pointer-events:none;
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em; text-transform:uppercase;
  color:var(--on-media-2); white-space:nowrap; opacity:0;
  padding:5px 9px 5px 16px; margin:-14px 0 0 12px;
  background:rgba(4,6,13,.55); backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px);
  border:1px solid var(--media-hair-2); border-radius:2px;
  transition:opacity .45s var(--ease);
  will-change:transform,opacity;
}
.glabel::before{
  content:""; position:absolute; left:6px; top:50%; transform:translateY(-50%);
  width:4px; height:4px; border-radius:50%; background:var(--accent-media);
}
/* the three anchors: same row shape as the flag index below, just weighted */
.corr-net{margin-top:36px}
.netrow{list-style:none; padding:0; margin:0 0 34px}
.netrow li{
  display:grid; grid-template-columns:34px 1fr auto; gap:18px; align-items:center;
  padding:18px 0; border-bottom:1px solid var(--hair-2); cursor:default;
  transition:padding-left .4s var(--ease);
}
.netrow li:first-child{border-top:1px solid var(--hair-2)}
.netrow li:hover{padding-left:10px}
.netrow img{
  width:34px; height:25px; object-fit:cover; flex:none;
  border:1px solid var(--hair-2); border-radius:2px;
}
.netrow b{font-size:15px; letter-spacing:.06em; font-weight:400; color:var(--tx)}
.netrow i{
  font-style:normal; font-family:var(--f-mono); font-size:9.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--tx-4);
}
/* Narrow screens cannot hold name and role on one line without them running
   into each other, so the role drops under the name. */
@media (max-width:760px){
  .netrow li{grid-template-columns:34px 1fr; gap:6px 16px; padding:16px 0}
  .netrow i{grid-column:2; line-height:1.6}
}
/* the anchor is what the globe focuses, so it gets the accent tick */
.netrow .is-anchor b{position:relative}
.netrow li.is-anchor i::before{
  content:""; display:inline-block; vertical-align:middle;
  width:4px; height:4px; border-radius:50%; margin-right:9px;
  background:linear-gradient(120deg,var(--violet),var(--cyan));
}

/* ==========================================================================
   17. VISION / MISSION
   ========================================================================== */
.vm{position:relative; overflow:hidden; background:var(--media-bg)}
.vm-img{position:absolute; inset:-14% 0; z-index:0; will-change:transform}
.vm-img img{width:100%; height:100%; object-fit:cover; filter:saturate(.3) brightness(.4)}
.vm-img::after{content:""; position:absolute; inset:0; background:linear-gradient(90deg,rgba(4,6,13,.95),rgba(4,6,13,.6))}
.vm .wrap{position:relative; z-index:2}
.vm .kicker{color:var(--accent-media)}
.vm .h-caps{color:var(--on-media)}
.vm-grid{display:grid; grid-template-columns:1fr 1fr; gap:2px; background:var(--media-hair-2); border:1px solid var(--media-hair-2); border-radius:var(--r-lg); overflow:hidden}
.vm-grid > div{background:rgba(8,12,23,.84); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px); padding:clamp(30px,4vw,60px)}
.vm-grid h3{font-family:var(--f-mono); font-size:10px; letter-spacing:.32em; text-transform:uppercase; color:var(--accent-media); margin:0 0 26px; font-weight:400}
.vm-grid .q{font-family:var(--f-serif); font-style:italic; font-weight:300; font-size:clamp(1.25rem,2.1vw,1.75rem); line-height:1.45; color:var(--on-media); margin:0}
.vm-grid .m{color:var(--on-media-2); font-size:15px; margin:0; line-height:1.75}
.vm-grid .m strong{color:var(--on-media); font-weight:400}

/* ==========================================================================
   18. RAIL / QUICK BAR / MODAL / FOOTER
   ========================================================================== */
.rail{position:fixed; right:16px; top:50%; transform:translateY(-50%); z-index:95; display:flex; flex-direction:column; gap:2px}
.rail a{
  width:48px; height:48px; display:grid; place-items:center; position:relative;
  background:var(--panel); border:1px solid var(--hair-2);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  transition:background .35s, border-color .35s;
}
.rail a:hover{background:var(--bg-3); border-color:var(--hair)}
.rail svg{width:17px; height:17px; stroke:var(--tx-2); fill:none; stroke-width:1.2}
.rail a:hover svg{stroke:var(--accent)}
.rail a::after{
  content:attr(data-t); position:absolute; right:56px; top:50%; transform:translateY(-50%);
  background:var(--bg-3); border:1px solid var(--hair-2); padding:7px 12px; white-space:nowrap;
  font-family:var(--f-mono); font-size:9px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--tx-2); opacity:0; pointer-events:none; transition:opacity .3s;
}
.rail a:hover::after{opacity:1}

.qbar{
  position:fixed; left:0; right:0; bottom:0; z-index:96; background:var(--panel);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  border-top:1px solid var(--hair-2); padding:14px 0; transform:translateY(110%);
}
.qbar .wrap{display:flex; align-items:center; justify-content:space-between; gap:20px}
.qbar p{margin:0; font-family:var(--f-serif); font-style:italic; font-size:1.1rem; color:var(--tx-2)}
.qbar .btn{padding:13px 26px; min-height:46px}

.modal{position:fixed; inset:0; z-index:400; display:none}
.modal.open{display:block}
.modal-bg{position:absolute; inset:0; background:var(--scrim); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px)}
.modal-panel{
  position:absolute; right:0; top:0; bottom:0; width:min(560px,100%);
  background:var(--bg-2); border-left:1px solid var(--hair-2);
  overflow-y:auto; padding:clamp(28px,4vw,52px);
}
.modal-x{position:absolute; top:22px; right:22px; width:44px; height:44px; border:1px solid var(--hair-2); color:var(--tx); display:grid; place-items:center}
.modal-x:hover{border-color:var(--accent)}
.modal h3{font-weight:200; font-size:1.9rem; letter-spacing:.1em; text-transform:uppercase; margin:0 0 10px}
.modal .sub{color:var(--tx-3); font-size:14.5px; margin:0 0 34px}
/* the category carried in from the catalogue, shown above the fields */
.m-chip{display:flex; align-items:center; gap:14px; margin:-18px 0 30px;
  padding:10px 12px 10px 10px; border:1px solid var(--hair-2); background:var(--field)}
.m-chip[hidden]{display:none}
.m-chip img{width:52px; height:52px; object-fit:cover; flex:none; background:#080C17}
.mchip-tx{display:flex; flex-direction:column; gap:4px; min-width:0; flex:1}
.mchip-tx em{font-family:var(--f-mono); font-style:normal; font-size:9.5px;
  letter-spacing:.22em; color:var(--accent)}
.mchip-tx b{font-weight:300; font-size:15px; color:var(--tx); line-height:1.25;
  overflow:hidden; text-overflow:ellipsis}
.mchip-x{width:30px; height:30px; flex:none; display:grid; place-items:center;
  color:var(--tx-4); border:1px solid transparent; transition:color .3s, border-color .3s}
.mchip-x:hover{color:var(--tx); border-color:var(--hair-2)}

.f{margin-bottom:20px}
.f label{display:block; font-family:var(--f-mono); font-size:9.5px; letter-spacing:.22em; text-transform:uppercase; color:var(--tx-3); margin-bottom:9px}
.f input,.f select,.f textarea{
  width:100%; min-height:48px; background:var(--field); border:1px solid var(--hair-2);
  color:var(--tx); padding:13px 15px; font-family:var(--f-ui); font-weight:300;
  font-size:15px; border-radius:0; transition:border-color .3s, background .3s;
}
.f textarea{min-height:110px; resize:vertical}
.f select optgroup{background:var(--bg-2); color:var(--tx-3); font-weight:400}
.f select option{background:var(--bg-2); color:var(--tx)}
.f input:focus,.f select:focus,.f textarea:focus{border-color:var(--accent); outline:none}
.f2{display:grid; grid-template-columns:1fr 1fr; gap:16px}
.modal .btn{width:100%; margin-top:8px}
.modal .fine{font-family:var(--f-mono); font-size:9.5px; letter-spacing:.14em; text-transform:uppercase; color:var(--tx-4); text-align:center; margin:18px 0 0}

.ft{background:var(--bg-2); border-top:1px solid var(--hair-2); padding:clamp(60px,8vw,110px) 0 130px}
.ft .wm{color:var(--tx)} .ft .tag{color:var(--tx-4)}
.ft-grid{display:grid; grid-template-columns:1.7fr 1fr 1fr 1.2fr; gap:40px}
.ft h5{font-family:var(--f-mono); font-size:9.5px; letter-spacing:.26em; text-transform:uppercase; color:var(--accent); margin:0 0 22px; font-weight:400}
.ft ul{list-style:none; margin:0; padding:0}
.ft li{margin-bottom:13px}
.ft a{color:var(--tx-3); font-size:14px; transition:color .3s}
.ft a:hover{color:var(--tx)}
.ft .bl{color:var(--tx-3); font-size:14px; max-width:34ch; margin:24px 0 0}
.ft-btm{
  display:flex; flex-wrap:wrap; justify-content:space-between; gap:16px;
  margin-top:60px; padding-top:26px; border-top:1px solid var(--hair-2);
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.16em; text-transform:uppercase; color:var(--tx-4);
}
.ft button.js-open{color:var(--tx-3); font-size:14px; letter-spacing:.03em; text-transform:none; font-family:var(--f-ui); font-weight:300}
.ft button.js-open:hover{color:var(--tx)}

/* ==========================================================================
   19. RESPONSIVE
   ========================================================================== */
@media (max-width:1100px){
  /* the build stacks: model on top, stage copy beneath it */
  .proc-inner{
    grid-template-columns:1fr; grid-template-rows:auto auto;
    gap:clamp(14px,3vw,28px); align-content:center;
  }
  .proc-stage{height:min(42vh,400px)}
  .proc-cards{min-height:clamp(215px,28vh,270px)}
  .stp h4{font-size:clamp(1.35rem,5.4vw,1.9rem)}
  .stp p{font-size:14.5px; max-width:none}
  .stp .out{max-width:none}
  .her-grid,.corr-grid,.vm-grid,.sec-hd{grid-template-columns:1fr}
  .her-sticky{position:static}
  .ft-grid{grid-template-columns:1fr 1fr}
  .rail{display:none}
  .hero-word{font-size:clamp(3rem,13vw,7rem)}
}
@media (max-width:860px){
  /* The panel is sized in viewport units rather than with inset:0.
     .hdr.stuck carries a backdrop-filter, and a filtered ancestor becomes the
     containing block for its fixed children — so inset:0 resolved to the
     header's own 84px-tall box and the menu came out as four links floating
     over the page with no panel behind them. Anchoring at the header's
     top-left corner (which is the viewport's) and taking the size from the
     viewport gives a real full-screen panel under either header state. */
  .menu{
    position:fixed; inset:auto; top:0; left:0;
    width:100vw; height:100svh; z-index:110;
    background:var(--bg);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    flex-direction:column; justify-content:center; gap:30px;
    transform:translateX(100%); transition:transform .6s var(--ease);
  }
  .menu.open{transform:none}
  .menu a,.hdr .menu a{font-size:22px; font-weight:200; letter-spacing:.24em; color:var(--tx); opacity:1}
  .burger{display:block}
  .hdr-cta{display:none}
  .scrollcue{display:none}
  /* the strapline wraps to two lines at this width and doubles the header
     height, which is what pushed the display type into the logo */
  .mark .tag{display:none}
  .mark svg{width:28px; height:32px}
  .hero-word{font-size:clamp(2rem,8.6vw,3.4rem)}
  .hero-word.b{font-size:clamp(2.1rem,9.6vw,3.8rem)}
  .hero-word.a{top:92px; left:var(--gut)}
  .hero-word.b{bottom:auto; top:150px; right:var(--gut)}
  .hero-foot{bottom:clamp(56px,8vh,96px)}
  .hero-lede{max-width:20ch; font-size:clamp(1.15rem,5.6vw,1.6rem)}
  .hero-act{gap:10px}
  .hero-act .btn{padding:14px 20px; font-size:10.5px; letter-spacing:.16em}
  .mf-foot{grid-template-columns:1fr; gap:26px}
  /* .grow-frame carried width:92vw here. It is inset:0 inside its stage, so
     the left edge won and the remaining 8vw was left blank down the right —
     the client's "video is not covering full screen, space on right but left
     is okay". The frame fills its stage; the clip-path is what draws the
     card, and it insets both sides equally. */
  .f2{grid-template-columns:1fr}
  .ft-grid{grid-template-columns:1fr}
  .tl li{grid-template-columns:1fr; gap:6px}
  .qbar p{display:none}
  .qbar .btn{width:100%}
  .grow-cap{flex-direction:column; align-items:flex-start}
  .grow-cap .rt{text-align:left}
}

/* ==========================================================================
   20. REDUCED MOTION — everything resolves to its end state
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .grain{display:none}
  .bleed-img,.vm-img{transform:none !important}
}
/* JS sets this when the visitor asks for reduced motion */
.no-motion .sp-line > span,
.no-motion .sp-word > span,
.no-motion .sp-char{transform:none !important; opacity:1 !important}

/* ==========================================================================
   23. INNER PAGES — the catalogue index and the thirty-five category pages
   --------------------------------------------------------------------------
   These pages carry no WebGL on purpose. The home page spends its budget on
   the hero world; an inner page is something a buyer arrives at from a search
   result and needs to read, so it stays fast and typographic. All the motion
   here is transform/opacity on a handful of elements.
   ========================================================================== */
.is-inner{opacity:1}                        /* no preloader to fade out of */
.cpage{padding-top:clamp(96px,11vw,132px)}
.h-sub{
  font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.5rem,3.4vw,2.9rem); line-height:1.14;
  letter-spacing:.02em; margin:0;
}
.lede{
  color:var(--tx-2); font-size:clamp(16px,1.35vw,19px); font-weight:300;
  line-height:1.65; max-width:62ch; margin:24px 0 0;
}

/* --- breadcrumb --------------------------------------------------------- */
.crumb{
  max-width:var(--wrap); margin:0 auto; padding:0 var(--gut) 26px;
  font-family:var(--f-mono); font-size:10px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--tx-4);
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
}
.crumb a{color:var(--tx-3); transition:color .3s}
.crumb a:hover{color:var(--accent)}
.crumb i{font-style:normal; opacity:.45}
.crumb span{color:var(--tx-2)}

/* --- category hero ------------------------------------------------------ */
.cp-hero{padding:clamp(18px,3vw,40px) 0 clamp(64px,8vw,110px)}
.cp-hero-in{display:grid; grid-template-columns:1fr 0.86fr; gap:clamp(32px,5vw,80px); align-items:center}
.cp-hero .h-caps{margin-top:6px; font-size:clamp(2rem,5.2vw,4.4rem)}

.cp-facts{display:flex; flex-wrap:wrap; gap:clamp(26px,3.4vw,54px); margin:38px 0 0}
.cp-facts span{display:flex; flex-direction:column; gap:6px}
.cp-facts b{
  font-family:var(--f-ui); font-weight:200; font-size:clamp(1.7rem,2.6vw,2.4rem); line-height:1;
  background:linear-gradient(100deg,var(--tx) 30%,var(--accent));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.cp-facts span{font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--tx-4)}

.cp-act{display:flex; flex-wrap:wrap; gap:14px; margin:44px 0 0}

.cp-shot{margin:0; position:relative}
.cp-shot-in{
  display:block; overflow:hidden; border-radius:var(--r-lg);
  background:var(--bg-3); aspect-ratio:4/5;
  /* the reveal: the mask opens, the picture settles back to rest */
  clip-path:inset(0 0 100% 0);
}
/* The resting state must be scale 1: the reveal animates 1.14 -> 1 and then
   clears the inline transform, so a scaled base silently snapped every hero
   back to 14% zoomed — which is why the pictures read as cut off. */
.cp-shot img{width:100%; height:100%; object-fit:cover; will-change:transform}
.cp-shot::after{
  content:""; position:absolute; left:-1px; bottom:-1px; width:44%; height:1px;
  background:linear-gradient(90deg,var(--violet),var(--cyan)); transform-origin:left;
  transform:scaleX(0); transition:transform .95s var(--ease);
}
.cp-shot.drawn::after{transform:scaleX(1)}

/* --- the taxonomy list -------------------------------------------------- */
.cp-subs{padding:clamp(64px,8vw,120px) 0; border-top:1px solid var(--hair-2)}
.cp-tally{font-family:var(--f-mono); font-size:10px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--tx-4); white-space:nowrap}
.cp-tally b{color:var(--accent); font-weight:400}

/* --- supplier reference photography ------------------------------------- */
.cp-ref{padding:clamp(64px,8vw,110px) 0; background:var(--bg-2)}
.cp-shots{display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:clamp(14px,2vw,26px)}
.cp-shots figure{margin:0}
.cp-shots img{
  width:100%; aspect-ratio:4/3; object-fit:cover;
  border-radius:calc(var(--r-lg) * .55); background:var(--bg-3);
  transition:transform .8s var(--ease);
}
.cp-shots figure:hover img{transform:scale(1.03)}
.cp-shots figcaption{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.18em;
  text-transform:uppercase; color:var(--tx-4); margin-top:14px;
}

/* --- the five stages ---------------------------------------------------- */
.cp-flow{padding:clamp(64px,8vw,120px) 0}
.cp-stages{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(5,1fr); gap:clamp(14px,1.8vw,26px);
}
.cp-stages li{
  display:flex; flex-direction:column; gap:12px;
  padding:26px 20px 30px; border-top:1px solid var(--tx); position:relative;
}
.cp-stages li::after{
  content:""; position:absolute; top:-1px; left:0; width:100%; height:1px;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
  transform:scaleX(0); transform-origin:left; transition:transform .7s var(--ease);
}
.cp-stages li:hover::after{transform:scaleX(1)}
.cp-stages em{font-family:var(--f-mono); font-style:normal; font-size:10px;
  letter-spacing:.2em; color:var(--tx-4)}
.cp-stages b{font-weight:400; font-size:15.5px; letter-spacing:.02em; color:var(--tx)}
.cp-stages span{font-size:13.5px; line-height:1.6; color:var(--tx-3)}

/* --- nearby categories -------------------------------------------------- */
.cp-near{padding:clamp(64px,8vw,120px) 0; background:var(--bg-2)}
.cp-near-grid{display:grid; grid-template-columns:repeat(4,1fr); gap:clamp(12px,1.6vw,22px)}
.near-card{
  display:grid; gap:4px; padding:0 0 22px; position:relative;
  border-bottom:1px solid var(--hair-2);
}
.nc-img{
  display:block; overflow:hidden; border-radius:calc(var(--r-lg) * .5);
  aspect-ratio:5/4; background:var(--bg-3); margin-bottom:18px;
}
.nc-img img{width:100%; height:100%; object-fit:cover; transition:transform .9s var(--ease)}
.near-card:hover .nc-img img{transform:scale(1.06)}
.nc-no{font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em; color:var(--tx-4)}
.nc-ttl{font-weight:300; font-size:16.5px; color:var(--tx); transition:color .3s}
.near-card:hover .nc-ttl{color:var(--accent)}
.nc-n{font-family:var(--f-mono); font-size:9.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--tx-4)}

/* --- closing band ------------------------------------------------------- */
.cp-cta{
  padding:clamp(76px,10vw,150px) 0; text-align:center;
  border-top:1px solid var(--hair-2);
}
.cp-cta .h-caps{font-size:clamp(1.7rem,4.4vw,3.6rem)}
.cp-cta .lede{margin:22px auto 38px; text-align:center}
.cp-cta .btn{margin:0 auto}

/* ==========================================================================
   24. CATALOGUE INDEX
   ========================================================================== */
.cx-hero{padding:clamp(24px,4vw,56px) 0 clamp(56px,7vw,96px)}
.cx-facts{display:flex; flex-wrap:wrap; gap:clamp(28px,4vw,66px); margin:46px 0 0}
.cx-facts span{display:flex; flex-direction:column; gap:7px;
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--tx-4)}
.cx-facts b{
  font-family:var(--f-ui); font-weight:200; font-size:clamp(2rem,3.4vw,3.2rem); line-height:1;
  background:linear-gradient(100deg,var(--tx) 30%,var(--accent));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}

.cx-list{padding:0 0 clamp(70px,9vw,130px)}
.cx-rows{list-style:none; margin:0; padding:0; border-top:1px solid var(--hair)}
.cx-row{position:relative; border-bottom:1px solid var(--hair-2)}
.cx-hit{
  display:grid; grid-template-columns:auto 1fr auto auto; align-items:center;
  gap:clamp(18px,3vw,52px); padding:clamp(20px,2.4vw,32px) 4px;
}
.cx-row::before{
  content:""; position:absolute; inset:0 -18px; z-index:-1;
  background:var(--bg-2); opacity:0; transition:opacity .4s var(--ease);
}
.cx-row:hover::before{opacity:1}
.cx-no{font-family:var(--f-mono); font-size:11px; letter-spacing:.14em; color:var(--tx-4)}
.cx-main{display:grid; gap:7px; min-width:0}
.cx-ttl{
  font-weight:200; font-size:clamp(1.25rem,2.6vw,2.1rem); letter-spacing:.01em;
  color:var(--tx); transition:transform .5s var(--ease), color .35s;
}
.cx-row:hover .cx-ttl{transform:translateX(12px); color:var(--accent)}
.cx-subs{
  font-size:12.5px; line-height:1.6; color:var(--tx-4);
  overflow:hidden; text-overflow:ellipsis; display:-webkit-box;
  -webkit-line-clamp:1; -webkit-box-orient:vertical;
  transition:transform .5s var(--ease), color .35s;
}
.cx-row:hover .cx-subs{transform:translateX(12px); color:var(--tx-3)}
/* the remainder of the taxonomy, as a count rather than a truncated name */
.cx-more{
  font-style:normal; font-family:var(--f-mono); font-size:10px;
  letter-spacing:.1em; color:var(--tx-4); margin-left:12px;
  padding:2px 7px; border:1px solid var(--hair-2); border-radius:99px;
  transition:border-color .35s, color .35s;
}
.cx-row:hover .cx-more{border-color:var(--accent); color:var(--accent)}
.cx-n{font-family:var(--f-mono); font-size:10px; letter-spacing:.16em; color:var(--tx-4)}
.cx-go svg{width:18px; height:10px; stroke:var(--tx-4); fill:none; stroke-width:1.2;
  transition:transform .45s var(--ease), stroke .3s}
.cx-row:hover .cx-go svg{transform:translateX(7px); stroke:var(--accent)}

/* the thumbnail rides the pointer — a preview without a layout cost */
.cx-shot{
  position:fixed; top:0; left:0; z-index:60; width:210px; height:150px;
  overflow:hidden; border-radius:calc(var(--r-lg) * .4);
  pointer-events:none; opacity:0; will-change:transform;
  box-shadow:0 22px 60px -24px rgba(12,15,22,.45);
}
.cx-shot img{width:100%; height:100%; object-fit:cover}
@media (hover:none),(pointer:coarse){.cx-shot{display:none}}

/* ==========================================================================
   25. INNER PAGE BREAKPOINTS
   ========================================================================== */
@media (max-width:1100px){
  .cp-stages{grid-template-columns:repeat(3,1fr)}
  .cp-near-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:900px){
  .cp-hero-in{grid-template-columns:1fr; gap:38px}
  .cp-shot{order:-1}
  .cp-shot-in{aspect-ratio:16/10}
  .cx-hit{grid-template-columns:auto 1fr auto; gap:20px}
  .cx-go{display:none}
}
@media (max-width:640px){
  .cp-stages{grid-template-columns:1fr}
  .cp-near-grid{grid-template-columns:1fr 1fr}
  .cx-subs{-webkit-line-clamp:2}
  .cx-n{display:none}
  .cp-facts{gap:22px}
}


/* ==========================================================================
   26. COMPANY PAGES — capabilities, about, process, corridors, contact, legal
   --------------------------------------------------------------------------
   Built from the same parts as the category pages; only the blocks that had
   nowhere to borrow from are new. Still no WebGL on any of them.
   ========================================================================== */

/* the logo gradient used as a text fill — the one place colour appears */
.grad-brand{
  background:linear-gradient(100deg,var(--violet) 5%,var(--cyan) 85%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
  font-style:normal;
}

/* --- numbered feature blocks -------------------------------------------- */
.pg-num{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(2,1fr); gap:1px;
  background:var(--hair-2); border:1px solid var(--hair-2);
}
.pg-num li{
  display:grid; gap:12px; align-content:start;
  padding:clamp(26px,3.2vw,44px); background:var(--bg); position:relative;
}
.pg-num li::after{
  content:""; position:absolute; inset:auto 0 0 0; height:1px;
  background:linear-gradient(90deg,var(--violet),var(--cyan));
  transform:scaleX(0); transform-origin:left; transition:transform .7s var(--ease);
}
.pg-num li:hover::after{transform:scaleX(1)}
.pg-num em{
  font-family:var(--f-mono); font-style:normal; font-size:10px;
  letter-spacing:.24em; text-transform:uppercase; color:var(--accent);
}
.pg-num b{font-weight:300; font-size:clamp(1.15rem,1.9vw,1.5rem); letter-spacing:.01em; color:var(--tx)}
.pg-num span{font-size:14.5px; line-height:1.72; color:var(--tx-3)}
.pg-num a{color:var(--accent); border-bottom:1px solid currentColor}

/* --- the position statement, without the strikethrough ------------------- */
.pg-neg{
  margin:0 0 40px; display:grid; gap:6px;
  font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.5rem,4vw,3rem); line-height:1.16; letter-spacing:.01em;
}
.pg-neg span:not(.grad-brand){color:var(--tx-4)}

/* --- heritage timeline --------------------------------------------------- */
.pg-tl{list-style:none; margin:0; padding:0; border-top:1px solid var(--hair-2)}
.pg-tl li{
  display:grid; grid-template-columns:minmax(140px,180px) 1fr;
  gap:clamp(18px,3vw,50px); padding:clamp(20px,2.4vw,30px) 0;
  border-bottom:1px solid var(--hair-2);
}
.pg-tl b{
  font-family:var(--f-mono); font-weight:400; font-size:11px;
  letter-spacing:.2em; color:var(--accent); padding-top:5px;
}
.pg-tl span{font-size:15.5px; line-height:1.7; color:var(--tx-2); max-width:62ch}

/* --- vision -------------------------------------------------------------- */
/* One statement, centred, with a hairline that opens outward from the middle
   as the section arrives. The line is the momentum the review asked for — no
   photograph, nothing behind the type, just the rule drawing itself.
   The section is centred on purpose: every other band on these pages runs its
   header hard left, so centring this one marks it as the still point rather
   than one more row of content. */
.vis .sec-hd{grid-template-columns:1fr; justify-items:center; text-align:center; margin-bottom:0}
.vis .vis-line{
  display:block; position:relative; height:2px; margin:clamp(34px,5vw,58px) auto;
  width:min(760px,100%); overflow:hidden;
}
/* the dormant rule is a hairline centred in the 2px track, so opening the
   bright band thickens it rather than shifting anything */
.vis .vis-line::before{
  content:""; position:absolute; left:0; right:0; top:50%; height:1px;
  background:var(--hair-2);
}
.vis .vis-line i{
  position:absolute; top:0; left:50%; height:100%; width:0;
  transform:translateX(-50%);
  background:linear-gradient(90deg,
    transparent 0%, var(--violet) 18%, var(--cyan) 82%, transparent 100%);
  box-shadow:0 0 18px -2px rgba(90,120,255,.45);
  transition:width 1.6s cubic-bezier(.16,1,.3,1);
}
.vis.is-open .vis-line i{width:100%}
/* Three lines, not six. The statement is one sentence and should read as one
   gesture — a narrow column turns it back into a paragraph. */
.vis-q{
  margin:0 auto; max-width:34ch; text-align:center;
  font-family:var(--f-serif); font-style:italic; font-weight:300;
  font-size:clamp(1.4rem,3vw,2.35rem); line-height:1.38; color:var(--tx);
  text-wrap:balance;
}
@media (prefers-reduced-motion:reduce){
  .vis .vis-line i{width:100%; transition:none}
}


/* --- pull quote ---------------------------------------------------------- */
.pg-quote{text-align:center; margin:0 auto}
.pg-quote blockquote{
  margin:0 auto; font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.8rem,4.6vw,3.4rem); line-height:1.12; letter-spacing:.01em;
  /* em, and on the element that carries the type — see note above */
  max-width:15em;
}
.pg-quote figcaption{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--tx-4); margin:30px auto 0;
  max-width:52em; line-height:1.9;
}

/* --- the five stages, expanded ------------------------------------------- */
.pg-steps{list-style:none; margin:0; padding:0; border-top:1px solid var(--hair)}
.pg-steps li{
  display:grid; grid-template-columns:auto 1fr minmax(160px,200px);
  gap:clamp(20px,3.4vw,56px); align-items:start;
  padding:clamp(28px,3.4vw,46px) 4px; border-bottom:1px solid var(--hair-2);
  position:relative;
}
.pg-steps li::before{
  content:""; position:absolute; inset:0 -18px; z-index:-1;
  background:var(--bg-2); opacity:0; transition:opacity .45s var(--ease);
}
.pg-steps li:hover::before{opacity:1}
.ps-no{
  font-family:var(--f-mono); font-size:clamp(1.6rem,2.6vw,2.3rem); font-weight:400;
  line-height:1; letter-spacing:.02em; color:var(--tx-4);
  transition:color .4s; padding-top:4px;
}
.pg-steps li:hover .ps-no{color:var(--accent)}
.ps-body h3{
  margin:0 0 14px; font-weight:400; letter-spacing:.02em;
  font-size:clamp(1.15rem,2.1vw,1.6rem); color:var(--tx);
}
.ps-body p{margin:0; font-size:15px; line-height:1.75; color:var(--tx-3); max-width:64ch}
.ps-doc{
  display:grid; gap:7px; padding:16px 18px;
  border:1px solid var(--hair-2); background:var(--bg-2);
}
.ps-doc em{
  font-family:var(--f-mono); font-style:normal; font-size:9px;
  letter-spacing:.22em; text-transform:uppercase; color:var(--tx-4);
}
.ps-doc b{font-weight:300; font-size:14.5px; color:var(--tx)}

/* --- sourcing countries -------------------------------------------------- */
.pg-regions{display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:1px;
  background:var(--hair-2); border:1px solid var(--hair-2)}
.pg-region{padding:clamp(22px,2.6vw,34px); background:var(--bg)}
.pg-region h3{
  margin:0 0 20px; font-family:var(--f-mono); font-weight:400; font-size:10px;
  letter-spacing:.24em; text-transform:uppercase; color:var(--accent);
}
.pg-region ul{list-style:none; margin:0; padding:0; display:grid; gap:15px}
.pg-region li{display:grid; grid-template-columns:auto 1fr; gap:14px; align-items:center}
.pg-region img{
  width:30px; height:22px; object-fit:cover; border:1px solid var(--hair-2);
  border-radius:2px; grid-row:span 2;
}
.pg-region b{font-weight:300; font-size:15.5px; color:var(--tx)}
.pg-region span{
  grid-column:2; font-family:var(--f-mono); font-size:9px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--tx-4); margin-top:-2px;
}

/* the same countries as a single row, for the contact page */
.pg-flagrow{list-style:none; margin:0; padding:0;
  display:flex; flex-wrap:wrap; gap:clamp(14px,2vw,26px)}
.pg-flagrow li{display:flex; align-items:center; gap:11px}
.pg-flagrow img{width:34px; height:25px; object-fit:cover;
  border:1px solid var(--hair-2); border-radius:2px}
.pg-flagrow span{font-family:var(--f-mono); font-size:9.5px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--tx-3)}

/* --- two-up related cards ------------------------------------------------ */
.cp-near-grid.cols-2{grid-template-columns:repeat(2,1fr)}

/* --- legal pages --------------------------------------------------------- */
.pg-legal-hd{max-width:70ch}
.pg-draft{
  margin:32px 0 0; padding:16px 20px; border-left:2px solid var(--accent);
  background:var(--bg-2); font-size:14px; line-height:1.7; color:var(--tx-3);
}
.pg-draft b{color:var(--tx); font-weight:400}
.pg-prose{max-width:78ch}
.pg-prose section{padding:0 0 clamp(30px,3.6vw,46px)}
.pg-prose h2{
  display:grid; grid-template-columns:auto 1fr; gap:18px; align-items:baseline;
  margin:0 0 18px; font-weight:300; letter-spacing:.02em;
  font-size:clamp(1.1rem,2vw,1.45rem); color:var(--tx);
}
.pg-prose h2 em{
  font-family:var(--f-mono); font-style:normal; font-size:10px;
  letter-spacing:.2em; color:var(--tx-4);
}
.pg-prose p{margin:0 0 16px; font-size:15.5px; line-height:1.8; color:var(--tx-2)}
.pg-prose a{color:var(--accent); border-bottom:1px solid currentColor}
.pg-updated{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--tx-4); padding-top:28px;
  border-top:1px solid var(--hair-2);
}

/* ==========================================================================
   27. COMPANY PAGE BREAKPOINTS
   ========================================================================== */
@media (max-width:900px){
  .pg-num{grid-template-columns:1fr}
  .pg-steps li{grid-template-columns:auto 1fr; gap:20px}
  .ps-doc{grid-column:2}
  .cp-near-grid.cols-2{grid-template-columns:1fr}
}
@media (max-width:640px){
  .pg-tl li{grid-template-columns:1fr; gap:8px}
  .pg-tl b{padding-top:0}
  .pg-quote{max-width:none}
}

/* --- home page: capability cards now offer the page and the drawer -------- */
.cap-acts{display:flex; align-items:center; gap:clamp(14px,2vw,28px); flex-wrap:wrap}
.cap-link.is-quiet{color:var(--on-media-3); font-size:10px; letter-spacing:.2em}
.cap-link.is-quiet:hover{color:var(--on-media)}

/* --- footer legal row ---------------------------------------------------- */
.ft-legal{display:flex; gap:20px}
.ft-legal a{transition:color .3s}
.ft-legal a:hover{color:var(--accent)}

/* ==========================================================================
   28. THE REMARKS PASS
   Everything the client's review asked for that needed new styling.
   ========================================================================== */

/* --- hero: the lockup, the line, nothing else -------------------------- */
.hero-mid{
  position:absolute; inset:0; z-index:3;
  display:grid; place-items:center; text-align:center; pointer-events:none;
}
/* The type needs its own ground, but this used to be a fixed 1180x760 box with
   an ellipse inside it. The ellipse is sized to the box's corners, so along the
   short axis it was still around 30% opaque when it reached the top and bottom
   edges — and then stopped dead. That straight cut is the "rectangle shape"
   the client could see behind the headline.
   The scrim now covers the whole hero and the ellipse is given its own radii,
   so it reaches fully transparent on its own terms and has no edge anywhere.
   The peak is also much lighter: stacked with .hero-veil the centre used to sit
   at about 96% black, which flattened the picture to a panel. It now lands near
   60%, so the frame behind stays visible while the line still reads. */
.hero-mid::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(62% 52% at 50% 50%,
    rgba(4,6,13,.56) 0%, rgba(4,6,13,.50) 28%, rgba(4,6,13,.34) 52%,
    rgba(4,6,13,.14) 76%, rgba(4,6,13,0) 100%);
}
.hero-mid .wrap{position:relative}
.hero-mid .wrap{width:100%; display:grid; justify-items:center; gap:0}
/* These rest VISIBLE. The intro hides them with a fromTo at runtime, and the
   preloader covers the page until it starts — so the stylesheet is always the
   safe end state, which is what the intro failsafe clears back to. */
/* The line no longer follows a lockup — it opens the page, so it is set
   larger and tighter than before and given the vertical room the mark and
   wordmark used to occupy. */
.hl-line{
  margin:0 0 clamp(26px,3vw,38px); color:var(--on-media);
  font-family:var(--f-ui); font-weight:200; letter-spacing:.03em;
  font-size:clamp(2.1rem,6.4vw,5.2rem); line-height:1.04;
  display:flex; flex-wrap:wrap; justify-content:center; gap:0 .3em;
  max-width:16ch;
}
.hl-line span{display:inline-block; will-change:transform,opacity}
.hl-line span:last-child{
  background:linear-gradient(100deg,var(--violet) 5%,var(--cyan) 85%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.hl-disc{
  margin:0 0 clamp(30px,4vw,52px);
  display:flex; align-items:center; justify-content:center; gap:14px;
  font-family:var(--f-mono); font-size:clamp(9px,1vw,11px);
  letter-spacing:.34em; text-transform:uppercase; color:var(--on-media-2);
}
.hl-disc span,.hl-disc i{will-change:opacity}
.hl-disc i{font-style:normal; color:var(--accent-media)}
.hero-mid .hero-act{display:flex; gap:14px; flex-wrap:wrap; justify-content:center; pointer-events:auto}
/* the whole block is held back by .is-loading until the intro takes over */
body.is-loading .hero-mid{opacity:0}

/* --- the pull quote the review asked for ------------------------------- */
.cap-pull{
  margin:26px 0 0; padding-left:20px; border-left:2px solid transparent;
  border-image:linear-gradient(180deg,var(--violet),var(--cyan)) 1;
  display:grid; gap:12px;
}
.cap-pull b{
  font-weight:300; font-size:clamp(1.15rem,1.9vw,1.5rem); line-height:1.28;
  letter-spacing:.01em; color:var(--tx);
}
.cap-pull span{font-size:14.5px; line-height:1.7; color:var(--tx-4)}

/* --- process: the step number carries the step ------------------------- */
/* the stage title is the thing that has to catch the eye on scroll */
/* the numeral lives in the rail now, so the title is just the title */
.stp.is-on h4{
  font-weight:400;
  background:linear-gradient(96deg,var(--violet) 0%,var(--cyan) 15%,var(--tx) 36%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}

/* --- corridors: the fifteen flags -------------------------------------- */
.corr-flags{margin-top:38px; padding-top:30px; border-top:1px solid var(--hair-2)}
.corr-net .corr-flags-l{margin-bottom:16px}
.corr-flags-l{
  display:block; margin-bottom:18px;
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.24em;
  text-transform:uppercase; color:var(--tx-4);
}
.flagrow{list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:14px 20px}
.flagrow li{display:flex; align-items:center; gap:10px}
.flagrow img{
  width:28px; height:21px; object-fit:cover; flex:none;
  border:1px solid var(--hair-2); border-radius:2px;
}
.flagrow span{
  font-family:var(--f-mono); font-size:9px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--tx-3);
}
.flagrow.is-compact span{display:none}
.flagrow.is-compact{justify-content:center; gap:10px}
.flagrow.is-compact img{width:34px; height:25px; border-color:var(--media-hair)}

/* the labels pinned to the globe now carry a flag */
.glabel img{width:16px; height:12px; object-fit:cover; margin-right:7px;
  vertical-align:-1px; display:inline-block; border-radius:1px}

.vm{overflow:hidden}
.vm .wrap{position:relative; z-index:1}

/* --- contact: flags and the signature ---------------------------------- */
.ct-sign{
  margin:clamp(46px,6vw,74px) auto 0; padding-top:clamp(30px,4vw,44px);
  border-top:1px solid var(--media-hair); max-width:64em;
  /* grid children stretch by default, which ran the address's underline the
     full width of the panel instead of hugging the address */
  display:grid; justify-items:center; gap:12px;
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.18em;
  text-transform:uppercase; color:var(--on-media-2); text-align:center;
}
.ct-sign a{
  font-size:11px; letter-spacing:.16em; color:var(--on-media);
  border-bottom:1px solid var(--media-hair); padding-bottom:3px;
}
.ct-sign a:hover{border-bottom-color:var(--accent-media)}
.ct-sign span{color:var(--on-media-3)}

/* --- languages --------------------------------------------------------- */
.lang{display:flex; align-items:center; gap:7px; padding:0 6px}
/* inherits the header's colour so it stays legible over the dark hero as
   well as against the white page once the header goes solid */
.lang-b{
  display:inline-flex; align-items:center; text-decoration:none;
  font-family:var(--f-mono); font-size:10px; letter-spacing:.16em;
  color:inherit; opacity:.5; padding:8px 2px; min-height:36px;
  transition:opacity .3s, color .3s;
}
.lang-b.is-on{opacity:1}
.lang-b:hover{opacity:1; color:var(--accent)}
.lang i{font-style:normal; opacity:.3; font-size:10px}

@media (max-width:900px){
  .lang{padding:0 2px; gap:5px}
  .lang-b{font-size:11px; letter-spacing:.12em; padding:8px 3px}
}


/* ==========================================================================
   29. THE DOCX PASS
   ========================================================================== */

/* --- the footer lockup ---------------------------------------------------
   The footer used to rebuild the lockup out of three separate pieces — mark,
   wordmark, strapline — each sized by hand. It never matched: the monogram
   came out at a third of the wordmark's width instead of half, and sat flush
   left instead of centred over it. The supplied artwork is one file and is
   now used as one file, so those proportions cannot drift again. */
.mark-full{display:block; width:min(230px,62vw)}
.mark-full img{width:100%; height:auto; display:block}
/* The artwork's monogram runs to a deep violet at the top, which disappears
   on the dark theme's ground. Lifting it there keeps one asset serving both. */
@media (max-width:900px){ .mark-full{width:min(200px,58vw)} }

/* --- the footer bottom row ----------------------------------------------- */
.ft-sign{max-width:44em}
.ft-legal i{font-style:normal; color:var(--tx-4)}
.ft-flags{display:flex; flex-wrap:wrap; align-items:center; gap:6px}
.ft-flags img{
  width:18px; height:13px; object-fit:cover; display:block;
  border:1px solid var(--hair-2); border-radius:1px; opacity:.85;
}

/* --- vision & mission: the card is now the chief executive's line ---------
   The review asked for the first sentence in black and the second in the logo
   gradient. This band is dark, so the first sentence takes the light neutral
   that plays the same role here — the contrast with the gradient is the
   point of the setting. */
/* The quote used to be one half of a two-panel grid. Standing alone under the
   vision statement it needs no panel of its own — it is centred on the same
   axis as the rule and the statement above it. */
.vm-quote{
  margin:clamp(46px,6vw,84px) auto 0; padding:0;
  display:flex; flex-direction:column; align-items:center; text-align:center;
}
.vm-quote blockquote{
  margin:0; font-family:var(--f-ui); font-weight:200; color:var(--on-media);
  font-size:clamp(1.5rem,3vw,2.4rem); line-height:1.16; letter-spacing:.01em;
  max-width:14em;
}
/* the vision block sits on the dark media ground, so the rule and the
   statement take the on-media palette rather than the page one */
.vm.vis .vis-line::before{background:var(--media-hair-2)}
.vm.vis .vis-q{color:var(--on-media)}
.vm-quote figcaption{
  margin-top:26px; font-family:var(--f-mono); font-size:9.5px;
  letter-spacing:.2em; text-transform:uppercase; color:var(--on-media-3);
}

/* the grid no longer holds two equal cards */
.vm-grid{grid-template-columns:1fr 1.05fr; align-items:stretch}

/* --- the expanding film band ---------------------------------------------
   Its body copy is gone, so the section ends on the pin. */
.grow{padding-bottom:0}

@media (max-width:1024px){
  .vm-grid{grid-template-columns:1fr}
}
@media (max-width:640px){
  .ft-btm{flex-direction:column; align-items:flex-start; gap:20px}
  .ft .mark .mark-i{width:46px}
  .ft .mark .mark-w{width:150px}
}

/* --- the chief executive's line, in the vision band ---------------------- */
.vm-quote blockquote{font-size:clamp(1.35rem,2.5vw,2.05rem); max-width:none}
/* the brand violet is close to this band's own black; lift the ramp so the
   second sentence carries as far as the first */
/* background-image, not the background shorthand: the shorthand would reset
   background-clip back to border-box and paint the box instead of the type */
.vm-quote .grad-brand{background-image:linear-gradient(100deg,#A97DFF 5%,var(--cyan) 80%)}

/* --- the footer bottom row -----------------------------------------------
   As a flex row the founder line was squeezed until it broke through the
   middle of a surname. Give it a row of its own width. */
.ft-btm{
  display:grid; grid-template-columns:minmax(0,1fr) auto;
  align-items:center; gap:18px 40px;
}
.ft-sign{grid-area:1/1; max-width:none}
.ft-flags{grid-area:1/2; justify-content:flex-end}
.ft-legal{grid-area:2/1/3/-1}

@media (max-width:860px){
  .ft-btm{grid-template-columns:1fr; align-items:start}
  .ft-sign{grid-area:auto}
  .ft-flags{grid-area:auto; justify-content:flex-start}
  .ft-legal{grid-area:auto}
}

/* --- process: close the gap between the heading and the pinned build ----- */
.sec.proc .sec-hd{margin-bottom:clamp(20px,2.4vw,32px)}
.proc-stage{height:min(88%,820px)}

/* ==========================================================================
   28. SECOND REVIEW — the merged Process page, the Heritage page, CSR, and
   the two-column lists the client asked for so the catalogue stops running
   to ten screens of scrolling.
   ========================================================================== */

/* --- form: the fields she named mandatory ------------------------------- */
.f label .req{
  font-style:normal; font-family:var(--f-mono); font-size:8.5px;
  letter-spacing:.18em; text-transform:uppercase; color:var(--accent);
  margin-left:9px; opacity:.85;
}
.f.err input,.f.err select,.f.err textarea{border-color:#D2564B}
.f-msg{
  display:block; margin-top:7px; font-family:var(--f-mono); font-size:9.5px;
  letter-spacing:.14em; text-transform:uppercase; color:#D2564B;
}

/* --- process: three disciplines, one page ------------------------------- */
.pr-disc{padding:clamp(64px,8vw,120px) 0; border-top:1px solid var(--hair-2)}
.disc-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(18px,2.4vw,34px)}
.disc{
  display:flex; flex-direction:column; gap:16px;
  padding-bottom:clamp(20px,2.4vw,30px); border-bottom:1px solid var(--hair-2);
  scroll-margin-top:110px;
}
.disc-img{
  display:block; overflow:hidden; background:var(--bg-3);
  border-radius:calc(var(--r-lg) * .45); aspect-ratio:16/10;
}
.disc-img img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .9s var(--ease);
}
.disc:hover .disc-img img{transform:scale(1.045)}
.disc h3{
  margin:0; font-weight:200; letter-spacing:.01em;
  font-size:clamp(1.4rem,2.4vw,2rem); color:var(--tx);
}
.disc-lede{
  margin:-6px 0 6px; font-family:var(--f-ui); font-weight:300; font-size:1.02rem;
  letter-spacing:.005em; text-transform:none; color:var(--accent);
}
.disc ul{list-style:none; margin:0; padding:0; display:grid; gap:11px}
.disc li{
  position:relative; padding-left:18px;
  font-size:14px; line-height:1.6; color:var(--tx-3);
}
.disc li::before{
  content:""; position:absolute; left:0; top:.62em;
  width:6px; height:1px; background:var(--accent);
}

/* the five stages lost their numerals, so the row loses its first column */
.pg-steps li{grid-template-columns:1fr minmax(160px,200px)}

/* --- process: the document set ------------------------------------------ */
.doc-set{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(3,1fr); gap:1px;
  background:var(--hair-2); border:1px solid var(--hair-2);
}
.doc-set li{
  display:grid; gap:8px; padding:clamp(20px,2.4vw,30px);
  background:var(--bg); transition:background .4s var(--ease);
}
.doc-set li:hover{background:var(--bg-2)}
.doc-set b{font-weight:300; font-size:clamp(1rem,1.5vw,1.2rem); color:var(--tx)}
.doc-set span{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.14em;
  text-transform:uppercase; line-height:1.8; color:var(--tx-4);
}

/* --- heritage: the year carries the section ----------------------------- */
.hg-line{padding:clamp(64px,8vw,120px) 0; border-top:1px solid var(--hair-2)}
.hg-tl{list-style:none; margin:0; padding:0; position:relative}
.hg-tl::before{
  content:""; position:absolute; left:0; top:6px; bottom:6px; width:1px;
  background:linear-gradient(180deg,var(--violet),var(--cyan));
  opacity:.5;
}
.hg-tl li{
  display:grid; grid-template-columns:minmax(150px,190px) 1fr;
  gap:clamp(24px,4vw,64px); align-items:start;
  padding:clamp(28px,3.4vw,48px) 0 clamp(28px,3.4vw,48px) clamp(24px,3vw,44px);
  border-bottom:1px solid var(--hair-2); position:relative;
}
.hg-tl li:last-child{border-bottom:0}
.hg-tl li::before{
  content:""; position:absolute; left:-3.5px; top:calc(clamp(28px,3.4vw,48px) + 12px);
  width:8px; height:8px; border-radius:50%;
  background:var(--bg); border:1px solid var(--accent);
  transition:background .4s var(--ease);
}
.hg-tl li:hover::before{background:var(--accent)}
.hg-yr{
  font-family:var(--f-ui); font-weight:200; line-height:1;
  font-size:clamp(2.2rem,4.6vw,3.9rem); letter-spacing:-.02em;
  background:linear-gradient(104deg,var(--violet),var(--cyan));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.hg-bd h3{
  margin:0 0 12px; font-weight:400; letter-spacing:.02em;
  font-size:clamp(1.05rem,1.9vw,1.45rem); color:var(--tx);
}
.hg-bd p{margin:0; font-size:15px; line-height:1.78; color:var(--tx-3); max-width:62ch}

/* --- heritage: ownership, and the About CSR block it shares its shape with */
.hg-own{padding:clamp(64px,8vw,110px) 0; background:var(--bg-2)}
.own-grid,.csr-grid{
  display:grid; grid-template-columns:1.05fr 1fr;
  gap:clamp(28px,4vw,72px); align-items:start;
}
.own-lead,.csr-lead{
  margin:0; font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.15rem,2vw,1.6rem); line-height:1.5; color:var(--tx);
}
.own-pts,.csr-pts{
  list-style:none; margin:0; padding:0; display:grid; gap:1px;
  background:var(--hair-2); border:1px solid var(--hair-2);
}
.own-pts li,.csr-pts li{display:grid; gap:7px; padding:20px 22px; background:var(--bg)}
.own-pts b,.csr-pts b{font-weight:400; font-size:14.5px; letter-spacing:.02em; color:var(--tx)}
.own-pts span,.csr-pts span{font-size:13.5px; line-height:1.65; color:var(--tx-4)}

/* --- about: the heritage card ------------------------------------------- */
.ab-her{padding:clamp(48px,6vw,88px) 0}
.her-card{
  display:grid; grid-template-columns:1fr auto;
  gap:clamp(20px,3.4vw,52px); align-items:center;
  padding:clamp(26px,3.4vw,44px) clamp(24px,3vw,40px);
  border:1px solid var(--hair-2);
  background:var(--bg); transition:border-color .45s var(--ease);
}
.her-card:hover{border-color:var(--accent)}
.her-img{display:block; overflow:hidden; aspect-ratio:4/3; background:var(--bg-3)}
.her-img img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .9s var(--ease);
}
.her-card:hover .her-img img{transform:scale(1.05)}
.her-tx{display:grid; gap:14px}
.her-tx b{
  font-weight:200; font-family:var(--f-ui); letter-spacing:-.005em;
  font-size:clamp(1.25rem,2.5vw,2.05rem); line-height:1.24; color:var(--tx);
}
.her-go{
  display:inline-flex; align-items:center; gap:11px;
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--accent);
}
.her-go svg{
  width:18px; height:10px; stroke:currentColor; fill:none; stroke-width:1.2;
  transition:transform .45s var(--ease);
}
.her-card:hover .her-go svg{transform:translateX(7px)}

/* --- about: CSR ---------------------------------------------------------- */
.ab-csr{padding:clamp(64px,8vw,110px) 0; background:var(--bg-2); border-top:1px solid var(--hair-2)}

/* --- contact: the address, at the size it deserves ---------------------- */
.ct-direct{text-align:center}
.ct-direct .kicker{justify-content:center; margin-bottom:8px}
.ct-mail{
  display:block; margin:22px 0 14px; font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.35rem,4.4vw,3rem); letter-spacing:-.015em; line-height:1.2;
  word-break:break-word;
  background:linear-gradient(100deg,var(--violet),var(--cyan));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.ct-note{
  margin:0; font-family:var(--f-mono); font-size:9.5px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--tx-4);
}

/* --- catalogue: two columns, and the thumbnail on the row --------------- */
.cx-rows{
  display:grid; grid-template-columns:repeat(2,1fr);
  column-gap:clamp(26px,3.4vw,64px);
}
.cx-hit{
  grid-template-columns:auto 1fr auto; gap:clamp(14px,1.8vw,24px);
  padding:clamp(13px,1.5vw,18px) 4px;
}
.cx-thumb{
  display:block; width:clamp(52px,5vw,68px); aspect-ratio:4/3;
  overflow:hidden; border-radius:3px; background:var(--bg-3);
}
.cx-thumb img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .8s var(--ease);
}
.cx-row:hover .cx-thumb img{transform:scale(1.09)}
.cx-ttl{font-size:clamp(1rem,1.5vw,1.3rem)}
.cx-row:hover .cx-ttl,.cx-row:hover .cx-subs{transform:translateX(6px)}
.cx-row::before{inset:0 -10px}

@media (max-width:1000px){
  .disc-grid{grid-template-columns:1fr; gap:clamp(28px,4vw,44px)}
  .doc-set{grid-template-columns:repeat(2,1fr)}
  .own-grid,.csr-grid{grid-template-columns:1fr; gap:30px}
  .her-card{grid-template-columns:1fr}
}
@media (max-width:820px){
  .cx-rows{grid-template-columns:1fr}
  .hg-tl li{grid-template-columns:1fr; gap:14px; padding-left:clamp(20px,5vw,32px)}
  .hg-tl li::before{top:calc(clamp(28px,3.4vw,48px) + 6px)}
  .doc-set{grid-template-columns:1fr}
}

/* the count belongs beside the name, not stranded at the far edge of a
   half-width row */
.cx-hit{grid-template-columns:auto 1fr}
.cx-hd{display:flex; align-items:baseline; gap:12px}
.cx-n{
  font-size:9.5px; letter-spacing:.16em; color:var(--tx-4);
  padding-left:12px; border-left:1px solid var(--hair-2); line-height:1;
}
.cx-row:hover .cx-hd{transform:translateX(6px)}
.cx-hd{transition:transform .5s var(--ease)}
.cx-row:hover .cx-ttl{transform:none}

/* Category heroes lost their description and their fact row in the review,
   so the text column is now short. Bottom-aligning it against a squarer
   picture reads as composed rather than as a column that ran out. */
.cpage .cp-hero-in{align-items:end}
.cpage .cp-shot-in{aspect-ratio:3/2}
.cpage .cp-hero .cp-act{margin-bottom:4px}
@media (max-width:1100px){
  .cpage .cp-hero-in{align-items:center}
}

/* the count used to be its own column and was dropped on small screens; it
   now sits beside the name, where there is room for it at any width */
@media (max-width:640px){
  .cx-n{display:inline-block}
}

@media (max-width:700px){
  .her-card{grid-template-columns:1fr; gap:20px}
}

/* --- catalogue search ---------------------------------------------------
   Sticky, because a filter you have to scroll back up to reach is a filter
   nobody uses twice. The offset clears the stuck header. */
.cx-find{
  position:sticky; top:74px; z-index:8;
  display:grid; grid-template-columns:auto 1fr auto; align-items:center;
  gap:14px; margin:0 0 6px; padding:16px 18px;
  border:1px solid var(--hair-2); background:var(--bg);
  /* the band above masks rows sliding through the gap under the header */
  box-shadow:0 -16px 0 0 var(--bg);
  transition:border-color .4s var(--ease);
}
.cx-find:focus-within{border-color:var(--accent)}
.cx-find-i{
  width:18px; height:18px; flex:none;
  fill:none; stroke:var(--tx-4); stroke-width:1.3;
  stroke-linecap:round; transition:stroke .35s;
}
.cx-find:focus-within .cx-find-i{stroke:var(--accent)}
.cx-find input{
  appearance:none; -webkit-appearance:none;
  width:100%; min-width:0; border:0; background:none; padding:0;
  font-family:var(--f-ui); font-weight:300;
  font-size:clamp(15px,1.5vw,18px); letter-spacing:.01em; color:var(--tx);
}
.cx-find input::placeholder{color:var(--tx-4); opacity:1}
.cx-find input:focus{outline:none}
.cx-find input::-webkit-search-cancel-button,
.cx-find input::-webkit-search-decoration{-webkit-appearance:none; display:none}
.cx-find-x{
  display:grid; place-items:center; width:26px; height:26px; flex:none;
  border:0; background:none; cursor:pointer; color:var(--tx-4);
  transition:color .3s;
}
.cx-find-x:hover{color:var(--accent)}
.cx-find-x svg{width:13px; height:13px; fill:none; stroke:currentColor; stroke-width:1.5}

.cx-find-n{
  margin:0; height:0; overflow:hidden; opacity:0;
  font-family:var(--f-mono); font-size:10px; letter-spacing:.18em;
  text-transform:uppercase; color:var(--tx-4);
  transition:opacity .3s var(--ease);
}
.cx-find-n.is-on{height:auto; opacity:1; padding:16px 2px 4px}

/* an empty result set would otherwise collapse to a bare hairline */
.cx-rows.is-empty{border-top:0}

@media (max-width:900px){
  .cx-find{top:64px}
}

/* nothing matched — the one place on the site where asking again is not
   repetition, because the visitor has just said what they want */
.cx-none{
  margin:0; padding:clamp(30px,4vw,46px) 2px;
  font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.05rem,2vw,1.5rem); line-height:1.5; color:var(--tx);
  max-width:58ch;
}
.cx-none b{font-weight:200; color:var(--tx-2)}
.cx-ask{
  border:0; background:none; padding:0; cursor:pointer;
  font:inherit; letter-spacing:inherit;
  background-image:linear-gradient(96deg,var(--violet),var(--cyan));
  -webkit-background-clip:text; background-clip:text; color:transparent;
  border-bottom:1px solid var(--hair-2);
  transition:border-color .35s var(--ease);
}
.cx-ask:hover{border-bottom-color:var(--accent)}

/* ==========================================================================
   29. PICTURE CARDS — the catalogue index and the subcategory lists
   --------------------------------------------------------------------------
   The client asked to see products, not a column of names. Both lists are now
   card grids: four up on a wide screen, which keeps the catalogue near three
   screens of scroll while giving every entry a real photograph.
   ========================================================================== */

/* --- catalogue index ----------------------------------------------------- */
.cx-rows{
  display:grid; grid-template-columns:repeat(4,1fr);
  column-gap:clamp(16px,2.2vw,30px); row-gap:clamp(28px,3.4vw,46px);
  border-top:0;
}
.cx-row{border-bottom:0; z-index:0}
.cx-row::before{content:none}
.cx-hit{
  display:flex; flex-direction:column; align-items:stretch; gap:14px;
  padding:0; height:100%;
}
.cx-thumb{
  width:100%; aspect-ratio:4/3; display:block; overflow:hidden;
  border-radius:calc(var(--r-lg) * .45); background:var(--bg-3);
}
.cx-thumb img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .9s var(--ease);
}
.cx-row:hover .cx-thumb img{transform:scale(1.055)}
.cx-main{display:flex; flex-direction:column; gap:7px; min-width:0}
.cx-hd{display:flex; align-items:baseline; gap:11px}
.cx-ttl{
  font-weight:300; font-size:clamp(1rem,1.25vw,1.18rem); letter-spacing:.01em;
  color:var(--tx); transition:color .35s;
}
.cx-row:hover .cx-ttl{color:var(--accent); transform:none}
.cx-n{
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.16em;
  color:var(--tx-4); line-height:1; padding-left:11px;
  border-left:1px solid var(--hair-2); white-space:nowrap;
}
.cx-subs{
  font-size:12px; line-height:1.55; color:var(--tx-4);
  overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  transition:color .35s;
}
.cx-row:hover .cx-subs{color:var(--tx-3); transform:none}

/* --- subcategory cards on a category page -------------------------------- */
.sub-grid{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(4,1fr);
  column-gap:clamp(16px,2.2vw,30px); row-gap:clamp(26px,3.2vw,42px);
}
.sub-row{display:flex; flex-direction:column; gap:13px}
.sr-img{
  display:block; width:100%; aspect-ratio:4/3; position:relative;
  overflow:hidden; border-radius:calc(var(--r-lg) * .45); background:var(--bg-2);
}
.sr-img img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .9s var(--ease);
}
.sub-row:hover .sr-img img{transform:scale(1.055)}

/* A card the client has not photographed yet. It gets a quiet brand tile
   rather than a broken frame — she is shooting her own products rather than
   buying stock, and an empty grey box would read as a fault. Dropping the
   photograph in later is one <img> inside this span. */
.sr-img:empty{
  border:1px solid var(--hair-2);
  background:linear-gradient(158deg,var(--bg-2) 0%,var(--bg-3) 100%);
}
.sr-img:empty::after{
  content:""; position:absolute; inset:0; opacity:.13;
  background:url("../img/logo-mark.svg") no-repeat center / 30px auto;
}
.sr-name{
  font-weight:300; font-size:clamp(.95rem,1.2vw,1.1rem); letter-spacing:.01em;
  color:var(--tx); transition:color .35s;
}
.sub-row:hover .sr-name{color:var(--accent)}

@media (max-width:1180px){
  .cx-rows,.sub-grid{grid-template-columns:repeat(3,1fr)}
}
@media (max-width:860px){
  .cx-rows,.sub-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:420px){
  .cx-rows,.sub-grid{column-gap:14px}
  .cx-subs{-webkit-line-clamp:2}
}

/* two-up on a phone: the type has to come down or every title wraps */
@media (max-width:520px){
  .cx-hit,.sub-row{gap:10px}
  .cx-ttl{font-size:.95rem}
  .cx-subs{font-size:11px; line-height:1.5}
  .cx-n{padding-left:9px}
  .sr-name{font-size:.9rem}
}

/* ==========================================================================
   30. KATHLEEN'S 31 AUGUST FEEDBACK
   ========================================================================== */

/* --- capabilities: the cards carry a title and a line, nothing else ----- */
.cap-card .zh{font-size:1.16rem; line-height:1.45; margin:0 0 26px}
.cap-pull b{display:block}

/* --- CSR ---------------------------------------------------------------- */
.csr-grid{grid-template-columns:0.9fr 1.1fr; align-items:center}
.csr-fig{
  margin:0; overflow:hidden; border-radius:var(--r-lg);
  background:var(--bg-3); aspect-ratio:4/5;
}
.csr-fig img{width:100%; height:100%; object-fit:cover; display:block}
.csr-body{display:grid; gap:clamp(24px,3vw,36px)}
.csr-lead{
  margin:0; font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.15rem,2vw,1.6rem); line-height:1.5; color:var(--tx);
}

/* the home-page band: her four lines, set large, beside the picture */
.sec.csr{padding:var(--sec-pad) 0}
.csr-home{
  display:grid; grid-template-columns:0.8fr 1fr;
  gap:clamp(30px,5vw,80px); align-items:center;
}
.csr-home .csr-fig{aspect-ratio:3/4}
.csr-line{
  margin:18px 0 0; font-family:var(--f-ui); font-weight:200;
  font-size:clamp(1.5rem,3.4vw,2.7rem); line-height:1.28;
  letter-spacing:-.01em; color:var(--tx);
}
.csr-line em{
  font-style:normal;
  background:linear-gradient(96deg,var(--violet),var(--cyan));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}

@media (max-width:900px){
  .csr-grid,.csr-home{grid-template-columns:1fr; gap:28px}
  .csr-fig,.csr-home .csr-fig{aspect-ratio:16/10}
}

/* Her supplied photography is brighter than the stock it replaced; the card
   grade was tuned to hold white type over a dark stock frame and buried it. */
.cap-card .ci img{filter:saturate(.86) brightness(.8)}

/* "Please make the corners of the images round" — every picture that sits in
   a card now carries the same generous radius rather than a hairline one. */
.cx-thumb,.sr-img,.disc-img,.nc-img{border-radius:calc(var(--r-lg) * .8)}
.cp-shots img{border-radius:calc(var(--r-lg) * .8)}


/* ==========================================================================
   POSITION — no photograph
   --------------------------------------------------------------------------
   The client asked for this band to carry no image: by this point the page has
   shown a lot of photography, and the line reads faster as pure type. Without
   a picture underneath, the heavy vignette had nothing to do but darken a
   rectangle, so it is replaced by an even field with a faint brand lift.
   ========================================================================== */
.bleed.is-plain::after{
  background:
    radial-gradient(120% 90% at 18% 0%,rgba(122,63,242,.16) 0%,rgba(122,63,242,0) 60%),
    radial-gradient(110% 90% at 88% 100%,rgba(45,212,232,.13) 0%,rgba(45,212,232,0) 62%);
}
.bleed.is-plain .neg{margin-top:0}


/* ==========================================================================
   CATALOGUE — LANDSCAPE TILES
   --------------------------------------------------------------------------
   Some of the client's pictures are wide subjects — a sofa, a modular unit, a
   racking aisle — and a portrait slot was cropping them to their least useful
   third. A landscape tile spans two columns instead of two rows, so the mosaic
   stays the same density and only the shape of those cards changes.
   ========================================================================== */
.cat-card.is-wide{grid-column:span 2}
@media (max-width:460px){
  /* the grid is down to two columns here, where a two-column card would be
     full width and break the rhythm */
  .cat-card.is-wide{grid-column:span 1}
}

/* ==========================================================================
   CATALOGUE CARD NUMERALS
   --------------------------------------------------------------------------
   The client could not read the numbers on the cards. They were 9.5px of a
   turquoise that sits at roughly the same luminance as the pale photographs
   behind it, with no separation. They are now larger, heavier, white, and
   carry a shadow — the accent is kept as a rule beneath rather than as the
   colour of the digits, so the number reads on any picture.
   ========================================================================== */
.cat-card .cn{
  font-size:12px; font-weight:500; letter-spacing:.14em;
  color:#fff; text-shadow:0 1px 8px rgba(4,6,13,.75), 0 0 2px rgba(4,6,13,.6);
  padding-bottom:5px; border-bottom:1.5px solid var(--accent-media);
}
/* the subcategory count sat in the same trap */
.cat-card .cc{
  color:rgba(255,255,255,.86);
  text-shadow:0 1px 7px rgba(4,6,13,.7);
}


/* ==========================================================================
   HOME SEARCH
   --------------------------------------------------------------------------
   Sits in the hero, above the two calls to action. It does not filter the home
   page — there is nothing on it to filter — it hands the term to the catalogue
   filter, which already searches the whole taxonomy rather than only the
   category names.
   ========================================================================== */
.hs-find{
  display:flex; align-items:center; gap:12px; margin-bottom:16px;
  max-width:520px; padding:14px 16px; pointer-events:auto;
  background:rgba(255,255,255,.72); border:1px solid rgba(11,16,32,.14);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  transition:border-color .35s var(--ease), background .35s var(--ease);
}
.hs-find:focus-within{border-color:#0b1020; background:rgba(255,255,255,.92)}
.hs-find svg{
  width:17px; height:17px; flex:none; fill:none;
  stroke:#6b7080; stroke-width:1.5; stroke-linecap:round;
}
.hs-find input{
  flex:1; min-width:0; border:0; background:none; outline:none;
  font-family:var(--f-ui); font-weight:300; font-size:15px; color:#0b1020;
}
.hs-find input::placeholder{color:#8b90a0}
.hs-find input::-webkit-search-cancel-button{-webkit-appearance:none}
.hs-find button{
  flex:none; border:0; cursor:pointer; padding:9px 14px;
  background:#0b1020; color:#fff;
  font-family:var(--f-ui); font-size:10.5px; letter-spacing:.19em;
  text-transform:uppercase; transition:background .35s var(--ease);
}
.hs-find button:hover{background:var(--acc,#5b4bdb)}
@media (max-width:860px){
  .hs-find{max-width:none; margin-bottom:14px; padding:12px 14px}
  .hs-find input{font-size:14px}
  .hs-find button{padding:8px 12px; font-size:10px}
}

/* Dutch is live: /nl/ is a full mirror of the site, generated from the
   English pages and the dictionaries in assets/i18n/. The switch is two real
   links, so the language survives a refresh and can be shared. */

/* ==========================================================================
   HOME SEARCH ON THE MEDIA HERO
   --------------------------------------------------------------------------
   The field was built for the light scene hero: a white pane with dark ink.
   The catalogue slideshow put a dark photograph back behind it, where a white
   slab reads as a control bolted onto the picture. On media it becomes the
   same glass the outline button already uses there — a hairline, a light
   fill, and the light ink of --on-media — so the row of controls beneath it
   reads as one set rather than two.
   ========================================================================== */
.hs-find.is-on-media{
  background:rgba(4,6,13,.34);
  border-color:rgba(244,246,250,.28);
  backdrop-filter:blur(10px) saturate(1.1);
  -webkit-backdrop-filter:blur(10px) saturate(1.1);
}
.hs-find.is-on-media:focus-within{
  background:rgba(4,6,13,.52);
  border-color:var(--accent-media);
}
.hs-find.is-on-media svg{stroke:var(--on-media-2)}
.hs-find.is-on-media input{color:var(--on-media)}
.hs-find.is-on-media input::placeholder{color:var(--on-media-3)}
/* the submit keeps the filled-button treatment the hero already sets:
   light plate, dark ink — see ".hero .btn" above */
.hs-find.is-on-media button{background:#F4F6FA; color:#04060D}
.hs-find.is-on-media button:hover{background:var(--accent-media); color:#04060D}

/* The hero centres its column, and the field is a flex row with no width of
   its own — so in that context it shrank to its content and clipped the
   placeholder. Given a width and auto margins it keeps the 520px it was
   designed at and stays centred with the rest of the lockup. */
.hero .hs-find{width:min(520px,100%); margin-left:auto; margin-right:auto}


/* ==========================================================================
   SUBCATEGORIES — NAMES ONLY
   --------------------------------------------------------------------------
   The client asked for the subcategory images to come out until she has
   finalised them. With the pictures gone the four-column tile grid would be
   230 empty frames, so the section is laid out as what it actually is now: an
   index of what sits beneath each category. Names run in columns against a
   hairline, which also lets a long list breathe instead of pushing the page
   down by 200-odd tiles.

   To put the photography back: restore the <img> inside .sr-img on the
   category pages and delete this block. Nothing else changed.
   ========================================================================== */
.sub-grid{
  grid-template-columns:repeat(auto-fill,minmax(238px,1fr));
  column-gap:clamp(20px,3vw,44px); row-gap:0;
  border-top:1px solid var(--hair-2);
}
.sub-row{
  flex-direction:row; align-items:baseline; gap:12px;
  padding:14px 2px; border-bottom:1px solid var(--hair-2);
}
.sr-img{display:none}
/* the accent tick is what the photograph used to do: it marks the row as an
   item in a set, so the column does not read as loose text */
.sub-row::before{
  content:""; flex:none; width:5px; height:5px; margin-top:.5em;
  background:var(--accent); opacity:.5; transition:opacity .35s, transform .35s;
}
.sub-row:hover::before{opacity:1; transform:scale(1.5)}
.sr-name{font-size:clamp(.92rem,1.1vw,1.02rem)}
@media (max-width:560px){
  .sub-grid{grid-template-columns:1fr}
}

/* ==========================================================================
   "NOT A FREIGHT FORWARDER" — LIGHT, AND MEASURED
   --------------------------------------------------------------------------
   Kathleen, 03-09: "reduce the excessive width and black background".

   The band inherited .bleed, which is a full-height near-black plate built
   for the photographic sections. Here there is no photograph — she asked for
   the picture to come out in an earlier round — so the plate was black for no
   reason, ran the full viewport height, and set the three lines across the
   whole 1600px measure.

   It now sits on the page's own light ground, is sized by its content, and
   the lines are held to a readable measure so they break the way they read:
   two negatives, then the answer.

   "A Global Trade Partner." also drops the Cormorant italic it had here and
   takes .grad-brand — the same treatment the identical line already has on
   the About page. That was her point 18: the same sentence set in two
   different faces on two pages.
   ========================================================================== */
.bleed.pos.is-plain{
  min-height:0;
  padding-block:var(--sec-pad);
  background:var(--bg-2);
  color:var(--tx);
}
/* the shared dark scrim has nothing to darken here */
.bleed.pos.is-plain::before{display:none}
.bleed.pos.is-plain .kicker{color:var(--accent); justify-content:center}

/* the measure. 22ch keeps "Not simply a sourcing agent." on one line at every
   width and stops the three lines spreading into a banner. */
.bleed.pos.is-plain .neg{
  max-width:22ch; margin-inline:auto;
  font-size:clamp(1.5rem,3.6vw,2.9rem);
}
.bleed.pos.is-plain .neg-a span,
.bleed.pos.is-plain .neg-b span{color:var(--tx-3)}
.bleed.pos.is-plain .neg-c em{
  font-family:var(--f-ui); font-style:normal; font-weight:300;
  background:linear-gradient(100deg,var(--violet) 5%,var(--cyan) 85%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
/* the outline button reverts to its light-ground treatment */
.bleed.pos.is-plain .btn-line{color:var(--tx); border-color:var(--hair)}
.bleed.pos.is-plain .btn-line:hover{color:#04060D; border-color:var(--tx)}

/* Two corrections to the block above, kept here so the intent stays readable.

   1. The brand wash was authored to sit on near-black, where .16 of violet is
      a hint. On the light ground it became a lilac-to-mint blob competing with
      the type, so it is dialled back to roughly a third.
   2. 22ch broke the lines mid-phrase ("NOT A FREIGHT / FORWARDER."). The point
      of the measure is to stop the three lines spreading across the full
      viewport, not to hyphenate them — each line should sit on one line, so
      the measure is set from the longest of the three and the type sized to
      match it. */
.bleed.pos.is-plain::after{
  background:
    radial-gradient(120% 90% at 18% 0%,rgba(122,63,242,.055) 0%,rgba(122,63,242,0) 62%),
    radial-gradient(110% 90% at 88% 100%,rgba(45,212,232,.05) 0%,rgba(45,212,232,0) 64%);
}
.bleed.pos.is-plain .neg{
  max-width:32ch;
  font-size:clamp(1.25rem,2.9vw,2.3rem);
}

/* ==========================================================================
   ABOUT — LEGACY LEAD, MISSION, CORE VALUES, BRAND STORY
   --------------------------------------------------------------------------
   Four blocks of the client's own copy, added from her spreadsheet. They
   borrow the page's existing devices rather than introducing new ones: the
   three-up list is the same .own-pts used by Ownership, and the section
   heads are the same .sec-hd / .kicker pair as everything above them.

   The timeline is also tightened here — her margin note against the 1966 row
   read "LESS SCROLLING THIS SECTION". Her entries are roughly half the length
   of the ones they replace, and the row padding and year size come down with
   them, which takes about a third off the height of that section.
   ========================================================================== */

/* the Legacy paragraph that opens the timeline */
.hg-lead{
  max-width:74ch; margin:0 0 clamp(34px,4.5vw,58px);
  font-weight:300; font-size:clamp(1rem,1.35vw,1.12rem); line-height:1.72;
  color:var(--tx-2);
}

/* LESS SCROLLING — same content, less height */
.hg-tl li{padding:clamp(16px,1.9vw,24px) 0}
.hg-yr{font-size:clamp(1.9rem,3.6vw,3rem)}
.hg-bd h3{margin-bottom:8px}
.hg-bd p{max-width:62ch}

/* --- mission ------------------------------------------------------------- */
.ab-mission{padding:clamp(56px,7vw,96px) 0; background:var(--bg-2)}
/* the second sentence, set as body against the lead — the .own-grid it sits
   in supplies the column, so no max-width of its own */
.ab-mission-p{
  margin:0;
  font-weight:300; font-size:clamp(.98rem,1.15vw,1.08rem); line-height:1.75;
  color:var(--tx-3);
}
/* nudge the body's first line onto the lead's baseline */
.ab-mission .own-grid{align-items:start}
.ab-mission .ab-mission-p{padding-top:.4em}

/* --- core values --------------------------------------------------------- */
.ab-values{padding:clamp(56px,7vw,96px) 0}
.ab-values .own-pts{grid-template-columns:repeat(3,1fr)}
@media (max-width:760px){
  .ab-values .own-pts{grid-template-columns:1fr}
}

/* --- brand story --------------------------------------------------------- */

/* "LESS SCROLLING THIS SECTION" — her margin note against the 1966 row.
   Her entries are already about half the length of the ones they replaced.
   The rest comes from the section's own frame: the outer padding and the row
   padding, which were set for the longer copy. Together with the shorter
   entries this holds the section to roughly the height it was BEFORE the
   Legacy paragraph was added above it, so she gets the new copy without the
   extra scroll. */
.hg-line{padding:clamp(48px,5.6vw,86px) 0}
/* Tightening the rows above used the padding shorthand, which silently reset
   the left padding to 0 and left the years sitting hard against the gradient
   rail with the marker dot cutting into them. The left inset is restored
   here, and the dot is re-centred on the year's cap height now that the row
   padding is smaller than the value it was originally offset against. */
.hg-tl li{padding:clamp(13px,1.5vw,17px) 0 clamp(13px,1.5vw,17px) clamp(22px,2.6vw,40px)}
.hg-tl li::before{top:calc(clamp(13px,1.5vw,17px) + clamp(11px,1.35vw,20px))}
.hg-lead{margin-bottom:clamp(26px,3.4vw,42px)}

/* Her second entry is a span, "1991–2024", not a single year — nine glyphs
   where the column was sized for four, so it broke across two lines with the
   dash left hanging. The column takes the width it needs and the year never
   wraps. */
.hg-tl li{grid-template-columns:minmax(150px,254px) 1fr}
.hg-yr{white-space:nowrap}

/* --- About: the family photograph on the 1991 timeline row ---------------
   Supplied at 488px, so the frame is capped below that and never upscales.
   It sits inside the timeline body rather than beside it, which keeps the
   two-column timeline rhythm intact on every width.                        */
.hg-fig{margin:18px 0 2px; max-width:264px}
.hg-fig img{
  display:block; width:100%; height:auto;
  border-radius:var(--r-md); background:var(--bg-3);
  filter:saturate(.92) contrast(1.02);
}
.hg-fig figcaption{
  padding:9px 2px 0;
  font-family:var(--f-mono); font-size:9.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--tx-3);
}
@media (max-width:700px){ .hg-fig{max-width:200px} }

/* --- long words on narrow screens ---------------------------------------
   Dutch writes its compounds closed, so a heading that is comfortable in
   English ("Security Products", "Terms of Use") arrives as one unbreakable
   21-character word ("Beveiligingsproducten", "Gebruiksvoorwaarden"). The
   reveal animation wraps each word in an inline-block, which stops even the
   normal wrap from helping, so five Dutch pages pushed 13-99px past the
   viewport on a phone. Hyphenation is language-aware and the pages already
   carry lang="nl", so the browser breaks these where Dutch allows; the
   overflow-wrap is the fallback for anything it cannot hyphenate.          */
@media (max-width:640px){
  .h-caps,.h-sub,.sp-word,.crumb span{
    hyphens:auto; -webkit-hyphens:auto;
    overflow-wrap:anywhere; word-break:normal;
  }
  .sp-word{max-width:100%}
}

/* A grid item defaults to min-width:auto, i.e. it refuses to shrink below its
   longest word. In English the catalogue titles are short enough that this
   never showed; in Dutch "Kunstbenodigdheden" and "Dierbenodigdheden" pushed
   the two-up phone grid 13px past the viewport. */
.cx-row,.sub-grid > *{min-width:0}
@media (max-width:640px){
  .cx-ttl,.cx-subs,.sr-name{overflow-wrap:anywhere; hyphens:auto; -webkit-hyphens:auto}
}

/* --- heritage figure, reduced motion ------------------------------------
   The slats that cover the heritage photograph are lifted by GSAP, and that
   timeline is skipped entirely when the visitor asks for reduced motion — so
   the slats stayed shut and the picture was simply never seen. Anyone with
   that OS setting on got an empty frame where the typewriter should be.
   With motion off there is nothing to reveal, so the cover is not drawn at
   all and the image is shown in its resolved grade rather than the archival
   one the animation would have scrubbed away. */
@media (prefers-reduced-motion:reduce){
  .her-slats,.her-scan{display:none}
  .her-fig img{filter:sepia(.05) saturate(.95) contrast(1.02) brightness(.92)}
}

/* --- About timeline: the family photograph sits on the right --------------
   "It should be on the right as well. You just can't put the thing in here."
   (04-09 call.) The row that carries a picture takes a third column for it,
   so the photograph uses the empty right-hand side instead of pushing the
   text down. Narrow screens fall back to stacking it under the text, where
   there is no room for a third column. */
.hg-tl li.has-fig{
  grid-template-columns:minmax(150px,254px) 1fr auto;
  align-items:start;
}
.hg-tl li.has-fig .hg-fig{
  margin:0; width:clamp(170px,16vw,236px); max-width:none;
}
@media (max-width:980px){
  .hg-tl li.has-fig{grid-template-columns:minmax(150px,254px) 1fr}
  .hg-tl li.has-fig .hg-fig{grid-column:2; margin-top:16px; width:clamp(160px,30vw,220px)}
}
@media (max-width:820px){
  .hg-tl li.has-fig{grid-template-columns:1fr}
  .hg-tl li.has-fig .hg-fig{grid-column:1}
}

/* --- About: "What we are, and what we are not." centred ------------------
   Client, 04-09: this block reads better centred. It is a three-line
   statement rather than body copy, so centring it also matches the way the
   same statement is set on the home page, and the Vision block just below
   it on this page. The heading centres with it or the section reads lopsided. */
.cp-subs .sec-hd{grid-template-columns:1fr; justify-items:center; text-align:center}
.cp-subs .kicker{justify-content:center}
.pg-neg{justify-items:center; text-align:center; text-wrap:balance}

/* --- the quote: larger, and the space around it closed up ----------------
   Client, 05-09: "it's a lot of space… it can be a little bit bigger, maybe
   like twice this." The line itself grows and the measure narrows with it,
   so the statement fills the block instead of floating in the middle of one. */
.pg-quote blockquote{font-size:clamp(2.3rem,6vw,4.6rem); max-width:12em; line-height:1.08}
.pg-quote figcaption{margin-top:22px}
.vm-quote blockquote{font-size:clamp(2rem,4.4vw,3.4rem); max-width:11em; line-height:1.1}
.vm-quote{margin-top:clamp(30px,3.6vw,52px)}
.sec.vm{padding-top:var(--sec-pad); padding-bottom:var(--sec-pad)}

/* --- About: the line and the photograph, side by side --------------------
   Client, 05-09: "remove the lines… so it reads like one section… this whole
   section, it should be just in the middle center on the right." The rules
   between rows are gone, the list keeps its gradient rail, and the picture
   sits centred against the full height of the line rather than inside one row. */
.hg-wrap{
  display:grid; grid-template-columns:1fr auto;
  gap:clamp(28px,4vw,72px); align-items:center;
}
.hg-wrap .hg-tl{min-width:0}
.hg-wrap .hg-fig{margin:0; width:clamp(180px,17vw,250px)}
.hg-tl li{border-bottom:0}
@media (max-width:900px){
  .hg-wrap{grid-template-columns:1fr; justify-items:start}
  .hg-wrap .hg-fig{margin-top:20px; width:clamp(170px,34vw,230px)}
}


/* --- catalogue tiles: landscape, because the pictures are ----------------
   Client, 05-09: "the images are out of proportion." A tall cell is portrait
   (about 300x350) and nearly every picture she supplied is landscape, so a
   tall cell threw most of each one away. Every cell is now landscape, and the
   four she asked to be bigger or wider — Machinery, Home & Living, Building
   Finishes and Prefab — take a double tile that keeps the same proportion. */
.cat-card.is-feature{grid-column:span 2; grid-row:span 2}
@media (max-width:860px){
  .cat-card.is-feature{grid-column:span 2; grid-row:span 1}
}
@media (max-width:560px){
  .cat-card.is-feature{grid-column:span 2; grid-row:span 1}
}

/* --- her list of 05-09 ---------------------------------------------------
   3. "Building need to fix as height not width" — the Building Finishes
      picture is a portrait staircase, so it takes a tall tile, not a wide one.
   4. Prefab "need to see full not zoomed in" — the tile overscale that drives
      the parallax is cut right back above, so a picture now sits almost fully
      inside its frame.
   2. Home & Living: the crop favoured the hedge; it is pulled to the kitchen.  */
.cat-card.is-portrait{grid-row:span 2}
.cat-card[data-cat="home"] .ci img{object-position:38% 50%}
.cat-card[data-cat="prefab"] .ci img{top:0; height:100%; object-position:50% 50%}

/* 4. "Our position" was carrying a full section's padding above and below a
      three-line statement. */
.cp-subs{padding-top:clamp(40px,4.6vw,64px); padding-bottom:clamp(40px,4.6vw,64px)}
.cp-subs .sec-hd{margin-bottom:clamp(24px,3vw,38px)}
.pg-neg{margin-bottom:0}

/* 5. Vision and Mission in one section: the mission sits under the vision
      line, in the same centred column, so it reads as one statement. */
.ab-vm .vm-mission{margin:clamp(34px,4.4vw,60px) auto 0; max-width:var(--wrap)}
.ab-vm .vm-mission .own-grid{align-items:start}

/* 9./10. Privacy, Terms and the copyright line were set larger and in a
      different face from the rest of the footer. They now match it. */
.ft-legal{
  display:flex; gap:22px; align-items:baseline;
  font-family:var(--f-mono); font-size:10px; letter-spacing:.18em;
  text-transform:uppercase; color:var(--tx-4);
}
.ft-legal a{color:var(--tx-4); transition:color .3s}
.ft-legal a:hover{color:var(--accent)}
.ft-legal i{font-style:normal; color:var(--tx-4)}

/* --- contact hero, centred ----------------------------------------------
   Client, 05-09: "contact page image remove and make this content all
   center." Without the picture the two-column frame left the text stranded
   on the left, so the hero becomes one centred column. */
.cp-hero.is-centred .cp-hero-in{grid-template-columns:1fr; justify-items:center}
.cp-hero.is-centred .cp-hero-tx{text-align:center; max-width:60ch}
.cp-hero.is-centred .kicker{justify-content:center}
.cp-hero.is-centred .cp-facts{justify-content:center}
.cp-hero.is-centred .cp-act{justify-content:center}
.cp-hero.is-centred .lede{margin-left:auto; margin-right:auto}

/* --- Vision and Mission, one section, two equal columns ------------------
   Both statements take the same face, size and colour; only the small label
   above them differs. The vision rule runs across the pair. */
.ab-vm .vm-pair{
  display:grid; grid-template-columns:1fr 1fr;
  gap:clamp(30px,5vw,80px); align-items:start;
  margin-top:clamp(28px,3.6vw,50px);
}
.ab-vm .vm-col{display:grid; gap:16px; justify-items:center}
.ab-vm .vm-lab{
  font-family:var(--f-mono); font-size:10px; letter-spacing:.34em;
  text-transform:uppercase; color:var(--accent);
}
.ab-vm .vm-pair .vis-q{max-width:26ch; margin:0}
@media (max-width:820px){
  .ab-vm .vm-pair{grid-template-columns:1fr; gap:clamp(28px,6vw,44px)}
}

/* --- Core values, set like the timeline entries --------------------------
   Client, 05-09: drop the "Three, and no more." heading, take them out of
   the boxes, and set them the way "The line" is set — a name and a sentence. */
.ab-values .sec-hd{margin-bottom:clamp(24px,3vw,38px)}
.val-list{display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(28px,4vw,72px)}
.val h3{
  margin:0 0 12px; font-weight:400; letter-spacing:.02em;
  font-size:clamp(1.05rem,1.9vw,1.45rem); color:var(--tx);
}
.val p{margin:0; font-size:15px; line-height:1.78; color:var(--tx-3)}
@media (max-width:820px){ .val-list{grid-template-columns:1fr; gap:26px} }

/* --- Brand Story, rebuilt to match the rest of the page ------------------
   Client, 05-09: she did not like the previous treatment and asked for the
   content to be consistent across the site. It now uses exactly the parts
   every other section here uses — nothing bespoke. */

/* Prefab spans three columns so the whole modular home reads on the card —
   client, 05-09: "you can extend that card to 3 cards so it will show all". */
.cat-card.is-wide3{grid-column:span 3; grid-row:span 2}
@media (max-width:1180px){ .cat-card.is-wide3{grid-column:span 2} }
@media (max-width:860px){ .cat-card.is-wide3{grid-column:span 2; grid-row:span 1} }

/* ==========================================================================
   SECTION RHYTHM — one scale, tightened
   --------------------------------------------------------------------------
   Client, 05-09: "spacing in section all over the website is too much… when
   section end, second section should start."

   Sections were padded on a viewport-height-ish scale (up to 180px top and
   bottom, so 360px between two blocks of copy on a large screen). This sets
   one step for the whole site — about 40% of what it was — and one for the
   gap under a section heading. It is a single place to change, rather than a
   value invented per section, which is what let them drift apart.
   ========================================================================== */
:root{
  --sec-pad:clamp(44px,4.6vw,76px);
  --sec-hd-gap:clamp(22px,2.6vw,38px);
}
.sec,
.cp-hero,.cp-subs,.cp-flow,.cp-near,.cp-cta,.cx-hero,.cx-list,
.hg-line,.ab-values,.ab-story,.ab-vm,.ab-csr,.pr-disc,.ct-direct,.cp-ref{
  padding-top:var(--sec-pad); padding-bottom:var(--sec-pad);
}
.sec-hd{margin-bottom:var(--sec-hd-gap)}

/* ==========================================================================
   BRAND STORY
   --------------------------------------------------------------------------
   Rebuilt on 05-09. The previous version inherited a two-column grid from an
   earlier layout, which chopped the prose into two short ragged columns with
   the right half of the page empty — which is what the client was reacting to.

   It is now the plainest thing on the page and uses only what the rest of the
   page uses: a kicker, one column of prose at a readable measure, the three
   principles in the same three-up as Core Values, and a closing statement.
   ========================================================================== */
.ab-story{background:var(--bg-2)}
.ab-story .sec-hd{margin-bottom:var(--sec-hd-gap)}

.ab-story .story-body{
  display:block; max-width:64ch; margin:0;
}
.ab-story .story-body p{
  margin:0 0 18px; font-weight:300; font-size:15.5px; line-height:1.8; color:var(--tx-3);
}
.ab-story .story-body p:last-child{margin-bottom:0}

/* the opening line carries the name, so it is set a step up */
.story-lead{
  font-size:1.12rem; line-height:1.7; color:var(--tx);
}
.story-lead i{font-style:normal; color:var(--tx-4); letter-spacing:.04em; font-size:.86em}

/* the cue that introduces the three principles */
.story-cue{color:var(--tx); margin-bottom:0}

.ab-story .val-list{margin:clamp(26px,3.2vw,42px) 0}
.ab-story .story-after{margin-top:clamp(20px,2.6vw,34px)}

/* one closing statement, set like the section headings rather than as a pull
   quote — she asked for the serif italic to come off it */
.story-close{
  font-family:var(--f-ui); font-style:normal; font-weight:200;
  font-size:clamp(1.3rem,2.2vw,1.75rem); line-height:1.35; color:var(--tx);
  max-width:30ch; margin:clamp(22px,2.8vw,36px) 0 0;
  text-wrap:balance;
}
.story-sign{margin:10px 0 0; font-size:clamp(1.05rem,1.8vw,1.35rem)}
.story-sign em{font-style:normal; font-weight:400}

/* Every remaining block that opens a page or closes one, on the same step —
   so no section is padded differently from its neighbour on any page. */
.sec,.bleed,.cx-hero,.cx-list,.cp-hero,.cp-subs,.cp-flow,.cp-near,.cp-cta,
.cp-ref,.hg-line,.ab-values,.ab-story,.ab-vm,.pr-disc,.ct-direct,.pg-legal,
.sec.csr,.sec.vm,.sec.her,.sec.proc,.sec.corr,.sec.cat{
  padding-top:var(--sec-pad); padding-bottom:var(--sec-pad);
}
.sec.proc{padding-bottom:0}

/* Home & Living spans three columns too, so the whole outdoor kitchen reads
   on the card (client, 05-09). */
.cat-card[data-cat="home"]{grid-column:span 3; grid-row:span 2}
@media (max-width:1180px){ .cat-card[data-cat="home"]{grid-column:span 2} }
@media (max-width:860px){ .cat-card[data-cat="home"]{grid-column:span 2; grid-row:span 1} }
.cat-card[data-cat="home"] .ci img{object-position:50% 50%}

/* the Sports hero was cutting the runner's head — anchor it higher */
.hero-sl[data-cat="Sports & Outdoor"]{object-position:50% 6%}

/* --- button hover: legible at both ends of the gradient ------------------
   Client, 05-09: "hovering on white button text invisible."
   The fill was the display gradient, whose cyan end (#2DD4E8) is light — white
   label text on it measured about 1.7:1, i.e. gone. The fill is now a deeper
   pair of the same two hues, and every button turns its label white on hover,
   so the label reads across the whole sweep instead of only over the violet. */
.btn::before{background:linear-gradient(100deg,#5B21B6,#0E7490)}
.btn:hover,
.btn-line:hover,
.hero .btn:hover,.bleed .btn:hover,.on-media .btn:hover,
.hero .btn-line:hover,.bleed .btn-line:hover,.on-media .btn-line:hover{
  color:#FFFFFF; border-color:transparent;
}

/* "Our position" was still carrying a full-viewport min-height from when it
   was a full-bleed image band, so the empty space below the button was the
   section stretching to fill the screen. It is content-sized now, on the same
   padding step as everything else (client, 05-09). */
.pos{min-height:0}
.pos .wrap{padding-top:0; padding-bottom:0}

/* --- full-bleed bands: content-sized and centred -------------------------
   Client, 05-09: the "Our position" band sat with its text at the top and a
   screen of empty space beneath. `.bleed` was forcing a near-viewport height
   (min-height:clamp(560px,90vh,900px)); the content then sat at the top of a
   box far taller than it needed. The bands are now sized by what is in them,
   on the shared padding step, and their content is centred both ways. */
.bleed{
  min-height:0;
  display:grid; place-items:center; align-content:center;
  padding-block:var(--sec-pad);
}
.bleed.is-cta{min-height:0}
.bleed .wrap{width:100%}

/* Privacy / Terms / © set to the navigation's size and tracking, so the two
   pieces of chrome that bracket the page read as the same thing
   (client, 05-09). */
/* Privacy, Terms and the copyright now match the footer navigation exactly —
   same size, tracking and case — so the bottom of the page reads as one thing
   (client, 05-09, asked twice). */
.ft .ft-legal,
.ft .ft-legal a,
.ft .ft-legal i{
  font-family:var(--f-ui); font-size:14px; letter-spacing:normal;
  text-transform:none; color:var(--tx-3);
}
.ft .ft-legal{gap:24px}
.ft .ft-legal a:hover{color:var(--tx)}

/* sixteen captions at the old size collided; a touch smaller and tighter
   keeps the front-facing half readable */
.glabel{font-size:9px; letter-spacing:.14em; padding:4px 8px 4px 14px}

/* The full-bleed bands centred their .wrap, but the wrap carried the trailing
   margin of its last paragraph — so the visible content sat 6px from the top
   with 142px of empty band beneath it. Collapsing the last child's margin is
   what actually centres what you can see (client, 05-09). */
.bleed .wrap > *:last-child{margin-bottom:0}
.bleed .wrap > p:last-child{margin-bottom:0}

/* --- "Our position": centred in its band --------------------------------
   The client's own fix, and she is right: the band was carrying bottom
   padding that the centring never accounted for, so the content sat high
   with a gap beneath it. Dropping that padding and pushing the block down by
   the same amount puts it in the middle of what you actually see. */
#position span.kicker{margin-top:65px}
section#position{padding-bottom:0}

/* The footer carried 130px of bottom padding, which read as dead space under
   the legal line (client, 05-09). */
footer.ft{padding-bottom:24px}

/* --- button hover fill sits BEHIND the label, always ---------------------
   The fill was an ::after-style overlay relying on the label carrying
   z-index:2. That only works when the label is wrapped in a <span> — and
   plenty of buttons on the site put their text straight inside the <a>, e.g.
   "The corridors", "Open full page", "Enquire about this category". Those
   labels have no z-index, so the fill painted straight over them and only the
   arrow survived (the SVG is positioned, the bare text is not).

   Isolating the button and dropping the fill to -1 puts it above the button's
   own background and below everything inside it, whether that content is
   wrapped or not. */
.btn{isolation:isolate}
.btn::before{z-index:-1}

/* --- Brand story, centred ------------------------------------------------
   Client, 05-09: heading and body centred. The prose keeps its measure and is
   centred as a block, so the lines stay a readable length rather than running
   the full width; the three principles centre within their columns. */
.ab-story.is-centred .sec-hd{grid-template-columns:1fr; justify-items:center; text-align:center}
.ab-story.is-centred .kicker{justify-content:center}
.ab-story.is-centred .story-body{margin-left:auto; margin-right:auto; text-align:center}
.ab-story.is-centred .story-close{margin-left:auto; margin-right:auto}
.ab-story.is-centred .story-sign{text-align:center}
.ab-story.is-centred .val-list{text-align:center}
.ab-story.is-centred .val h3,
.ab-story.is-centred .val p{text-align:center}

/* --- long category names on a card --------------------------------------
   Dutch writes its compounds closed, so "Uitvaartbenodigdheden" is one
   21-character word where the English is two short ones — on a card it ran
   past the edge and was cut. The name wraps and hyphenates where Dutch allows
   it, which is language-aware because the page carries lang="nl". */
.cat-card .ct{
  overflow-wrap:anywhere; hyphens:auto; -webkit-hyphens:auto;
  word-break:normal;
}

/* --- the capability pictures on the process page -------------------------
   Client, 05-09: "images are cropped here". The three pictures she chose are
   portrait, roughly 1:2, and the frame was 16/10 — so each card showed a thin
   horizontal band and nothing else. The frame now carries the pictures' own
   proportion, which means cover crops nothing at all, and the grid is drawn
   in a little so three portrait plates sit in the section rather than tower
   over it. */
.pr-disc .disc-img{aspect-ratio:199 / 406}
@media (max-width:1000px){
  /* one per row below 1000px: a full-width portrait would be a screen and a
     half tall, so the plate is capped and centred instead. */
  .pr-disc .disc-img{width:min(100%,320px); margin-inline:auto}
}

/* --- the catalogue search bar and the auto-hiding header ------------------
   Client, 05-09: scrolling the catalogue fast left a band of empty page above
   the search bar until the header caught up. The bar was parked 74px down to
   clear the header; when the header slides away that 74px is bare page, and
   the 16px mask above the bar cannot reach across it. So the bar travels with
   the header — up to the top edge while the header is away, back down to its
   normal seat when the header returns — on the same easing and the same
   duration, so the two move as one. */
.cx-find{transition:top .55s var(--ease), border-color .4s var(--ease)}
:root.hdr-off .cx-find{top:8px}

/* --- Core values, centred ------------------------------------------------
   Client, 05-09. The heading sat left while Brand story below it was centred,
   so the two read as different pages. Only the heading moves — the three
   values keep their columns. */
.ab-values .sec-hd{grid-template-columns:1fr; justify-items:center; text-align:center}
.ab-values .sec-hd .kicker{justify-content:center}

/* ==========================================================================
   PHONE — the round of 05-09
   Everything below is the client's list from testing the site on a handset.
   ========================================================================== */

/* --- the category panel would not scroll ---------------------------------
   "when I click on any category card it doesn't have scroll if the
   subcategories are more". The panel had max-height:100vh, but on a phone it
   starts 38vh down the screen, so a hundred viewport-heights of panel hung
   off the bottom of a fixed, clipped view. It now takes exactly the row it
   sits in and scrolls inside it. (The markup also carries data-lenis-prevent,
   or the smooth-scroll layer swallows the gesture before the panel sees it.) */
@media (max-width:900px){
  .cv-panel{
    align-self:stretch; height:100%; min-height:0; max-height:none;
    overflow-y:auto; -webkit-overflow-scrolling:touch;
    padding-bottom:clamp(28px,7vw,48px);
  }
}

/* --- the three counters ---------------------------------------------------
   Stacked, each stat's gradient rule still sat 35px above its own top, which
   on one column is inside the label of the stat before it. The row opens up
   a little and the rule sits in the middle of the gap where it belongs. */
@media (max-width:860px){
  .mf-foot{gap:34px}
  .mf-stat .mf-rule{top:-17px}
}

/* --- the footer, centred --------------------------------------------------
   "make it nicer on mobile, logo center and all details on footer need to be
   center as well". One column, everything on the centre line. */
@media (max-width:860px){
  .ft .wrap{text-align:center}
  .ft-grid{justify-items:center}
  .ft-grid > div{display:flex; flex-direction:column; align-items:center}
  .ft .mark-full{margin-inline:auto}
  .ft ul{width:100%}
  .ft .bl{margin-inline:auto}
  .ft-btm{justify-items:center; text-align:center; gap:20px}
  .ft-sign{margin-inline:auto}
  .ft-legal{justify-content:center; flex-wrap:wrap}
  .ft-flags{justify-content:center}
}

/* --- About: the first two generations ------------------------------------
   The portrait and its caption sat hard left under the timeline. Both centre. */
@media (max-width:900px){
  .hg-wrap .hg-fig{justify-self:center; text-align:center; margin-inline:auto}
  .hg-wrap .hg-fig figcaption{text-align:center}
}

/* --- chain of custody: the assembly had almost no height ------------------
   .proc-stage is sized as a percentage of its grid row. On one column the row
   is auto, so the percentage had nothing to resolve against and the stage
   collapsed to the canvas's intrinsic size — a 240px strip with a screenful
   of white above and below it. Real heights on both blocks, so the pinned
   screen is filled rather than padded. */
@media (max-width:1100px){
  .proc-stage{height:min(48vh,430px)}
  .proc-cards{min-height:clamp(240px,32vh,300px)}
}


/* --- the two buttons under a category ------------------------------------
   .cv-act was a bare div, so its two inline-flex buttons wrapped onto a
   second line with no space between them and overlapped on a phone. */
.cv-act{display:flex; flex-wrap:wrap; gap:14px; align-items:center}
@media (max-width:900px){
  .cv-act{flex-direction:column; align-items:stretch}
  .cv-act .btn{width:100%}
}

/* --- About: the timeline on a phone --------------------------------------
   The year column was re-widened to minmax(150px,254px) further down the
   sheet, which landed after the narrow-screen rule that stacks the rows — so
   on a 390px screen the year kept 150px and the entry itself was left with
   about 160, one or two words to a line. Below 820px the row stacks, which
   is what the earlier rule intended. */
@media (max-width:820px){
  .hg-tl li,
  .hg-tl li.has-fig{grid-template-columns:1fr; gap:8px}
  .hg-tl li.has-fig .hg-fig{width:min(100%,240px); margin:18px auto 0}
}

/* --- the lines the client asked to be set bold ---------------------------
   05-09: "make 32 Categories bold", "make CAPABILITIES bold", "A NEW COMPANY
   (make bold)", "FIVE STAGES - FIVE DOCUMENTS bold", "15 countries bold",
   "ONE FAMILY - THREE HANDS (make bold)". Jost is loaded at 500 and the
   display headings sit at 200, so one line lifts clearly out of the other
   without changing the typeface. */
.h-caps b,.h-sub b,.neg b{font-weight:500}

/* --- "Our priority": the picture was being cropped ------------------------
   Client, 05-09: "Our priority: image has been cropped. Also at About tab."
   Her photograph is 717x895 — exactly 4:5. About already framed it that way;
   the home page asked for 3:4 and every screen under 900px asked for 16:10,
   which threw away half its height. One frame, the picture's own. */
.csr-home .csr-fig{aspect-ratio:4/5}
@media (max-width:900px){
  .csr-fig,.csr-home .csr-fig{
    aspect-ratio:4/5; width:min(100%,420px); margin-inline:auto;
  }
}

/* --- "Full Ownership, Complete Control" on a phone -----------------------
   The caption was pinned bottom-left with a desktop-sized side padding. It
   centres under the film instead, and the Dutch line — which is longer than
   the English — is given room rather than being pushed off the edge. */
@media (max-width:860px){
  .grow-cap{
    justify-content:center; align-items:center; text-align:center;
    padding-left:clamp(18px,5vw,30px); padding-right:clamp(18px,5vw,30px);
  }
  .grow-cap h3{font-size:clamp(1.15rem,5.4vw,1.7rem); line-height:1.18}
  .grow-cap .rt{text-align:center}
}

/* --- process: the closing band is now just the button --------------------
   "Remove section: start with stage one. Leave option 'request a quote'."
   With the heading and the paragraph gone the band was carrying a screen and
   a half of padding around a single button. */
.cp-cta{padding:clamp(46px,6vw,84px) 0}

/* --- a word that only belongs in the English sentence --------------------
   "Tell us what you need sourced" needs the last word; "Vertel ons wat u
   nodig hebt" is already the whole sentence, and the client crossed the
   translated word out on the Dutch home page (05-09). It is dropped on the
   Dutch pages rather than deleted, so the English keeps it. */
:root[lang="nl"] .en-only{display:none}

/* ==========================================================================
   06-09 — her list against the built site
   ========================================================================== */

/* --- process: the capability block ---------------------------------------
   "Put Capabilities in CAPS LOCK. Images are too big — one full page. Make
   them small, but DO NOT CROP. Sourcing, Trade, Logistics in CAPS + BOLD."
   The heading and the three names are cased in CSS rather than in the markup
   so the Dutch translations keep working untouched. The pictures keep their
   own 1:2 proportion — nothing is cut — and are simply drawn smaller, so the
   section stops filling a screen on its own. */
.pr-disc .h-sub{text-transform:uppercase; letter-spacing:.05em}
.pr-disc .disc h3{
  text-transform:uppercase; font-weight:500; letter-spacing:.05em;
  font-size:clamp(1.05rem,1.7vw,1.35rem);
}
.pr-disc .disc-img{width:min(100%,220px)}

/* --- contact: the address, a little smaller ------------------------------ */
.ct-mail{font-size:clamp(1.05rem,3vw,2rem)}

/* --- About: the typewriter was being cropped on a phone -------------------
   The narrow-screen rule put every page hero into a 16:10 landscape frame.
   That suits the category pages, whose pictures are landscape; the About
   portrait is 461x576 — exactly 4:5 — and half its height was thrown away. */
@media (max-width:900px){
  .cp-shot-in{aspect-ratio:4/5; width:min(100%,340px); margin-inline:auto}
  .cpage .cp-shot-in{aspect-ratio:3/2; width:auto}
}

/* --- process: the three disciplines swipe sideways on a phone -------------
   "The nice, smooth function ... has been removed from Sourcing, Trade &
   Logistics. Now everything stacks vertically instead of horizontally."
   The home page's rail is back as it was; here the three cards become one
   swipeable row, which is the same gesture without pinning a whole screen. */
@media (max-width:1000px){
  .pr-disc .disc-grid{
    display:flex; gap:clamp(14px,3vw,22px);
    overflow-x:auto; -webkit-overflow-scrolling:touch;
    scroll-snap-type:x mandatory;
    scroll-padding-inline:var(--gut);
    margin-inline:calc(var(--gut) * -1);
    padding:0 var(--gut) 8px;
    scrollbar-width:none;
  }
  .pr-disc .disc-grid::-webkit-scrollbar{display:none}
  .pr-disc .disc{
    flex:0 0 min(78vw,330px); scroll-snap-align:start;
    border-bottom:0;
  }
  /* the picture keeps its proportion here too, just small enough that a card
     is a picture and its copy rather than a screen of picture */
  .pr-disc .disc-img{width:min(100%,200px); margin-inline:0}
}

/* --- the header stays put on a phone -------------------------------------
   Client, 06-09: "on mobile when scrolling to bottom header should stay
   always". main.js already refuses to hide it on a touch screen; this makes
   it structural, so the bar cannot leave even if the class is applied — and
   the catalogue's search bar keeps its seat under it rather than riding up
   to a header that never went anywhere. */
@media (max-width:860px){
  .hdr.hide{transform:none}
  :root.hdr-off .cx-find{top:74px}
}

/* the header is taller on a phone than on the desktop, so the catalogue's
   search bar needs a deeper seat or its top edge sits behind the bar */
@media (max-width:860px){
  .cx-find{top:92px}
  :root.hdr-off .cx-find{top:92px}
}

/* --- the heritage lead is three paragraphs now ---------------------------
   Client, 07-09: the "one family" lead was rewritten from a single block
   into three paragraphs. The old rule put the full gap to the timeline on
   every .hg-lead, which multiplied by three; the gap now belongs to the
   block that actually precedes the timeline. */
.hg-lead{margin-bottom:1.15em}
.hg-wrap{margin-top:clamp(26px,3.4vw,42px)}
