/* ============================================================
   CEYENAR — NETWORK ATLAS · LIGHT POLYCHROME
   Base: high fidelity/network-atlas.html
   Warm-white paper ground, ink-navy text, and the full logo
   palette doing categorical work. Routes are transit lines in
   the three family colours; hubs are white-core ringed
   stations. A printed logistics atlas, not a dashboard.
   ============================================================ */

/* ============================================================
   DESIGN TOKENS
   Primitives hold raw values; semantic tokens name a *use*, and are
   what every component below references. Change a primitive and the
   whole system follows. Nothing under this block should carry a raw
   hex, a bare cubic-bezier, or a one-off clamp().

   Two deliberate exceptions: `#000` inside a mask-image is an alpha
   stop, not a colour, and the map's label size is a bespoke inverse
   clamp so pins stay legible as the SVG shrinks.
   ============================================================ */
:root{

  /* ---------- colour · primitives ---------- */
  --c-white:#FFFFFF;
  --c-paper-50:#FAFBFD;     /* page ground */
  --c-paper-100:#F6F9FC;    /* whisper tint */
  --c-paper-200:#F2F7FB;
  --c-paper-300:#EFF5FA;    /* tinted band */
  --c-paper-400:#EDF3F8;    /* map land */

  --c-navy-900:#0E2238;     /* ink */
  --c-navy-800:#13304E;     /* top of the dark band */
  --c-navy-600:#4E6076;     /* body copy */
  --c-navy-500:#5E7189;     /* AA on white + tint at mono sizes */
  --c-navy-300:#B9CFDE;     /* coastline */
  --c-navy-200:#CBD8E3;     /* strong hairline */
  --c-navy-100:#DFE7EE;     /* hairline */

  --c-blue-600:#075C92;
  --c-blue-500:#0A7AC2;

  /* the three logo squares = the three product families */
  --c-yellow-500:#FFC20E;
  --c-yellow-600:#F5B800;
  --c-yellow-900:#8A6A00;   /* AA-safe as text on white */
  --c-teal-500:#1FB6C1;
  --c-teal-900:#0E7E88;
  --c-green-500:#8BC53F;
  --c-green-600:#7DB53A;
  --c-green-900:#4E7B22;

  /* light inks, only ever used on the dark band */
  --c-sky-200:#CFE0EE;
  --c-sky-300:#B9C9DA;
  --c-sky-400:#8FA6BD;
  --c-mint-200:#9DE0E6;

  /* channels, so alpha mixes stay on-palette */
  --ch-ink:14,34,56;
  --ch-blue:10,122,194;
  --ch-teal:31,182,193;
  --ch-yellow:255,194,14;
  --ch-green:139,197,63;
  --ch-paper:250,251,253;
  --ch-sky:214,232,246;
  --ch-white:255,255,255;
  --ch-black:0,0,0;

  /* ---------- colour · semantic ---------- */
  --ground:var(--c-paper-50);
  --paper:var(--c-white);
  --tint:var(--c-paper-300);
  --tint-2:var(--c-paper-100);
  --land:var(--c-paper-400);
  --coast:var(--c-navy-300);

  --ink:var(--c-navy-900);
  --slate:var(--c-navy-600);
  --mist:var(--c-navy-500);
  --hair:var(--c-navy-100);
  --hair-strong:var(--c-navy-200);

  --blue:var(--c-blue-500);
  --deep:var(--c-blue-600);

  --logo-y:var(--c-yellow-500);
  --logo-t:var(--c-teal-500);
  --logo-g:var(--c-green-500);
  --fam-y:var(--c-yellow-600);
  --fam-g:var(--c-green-600);
  --y-text:var(--c-yellow-900);
  --t-text:var(--c-teal-900);
  --g-text:var(--c-green-900);

  /* the one dark moment: everything that sits on ink */
  --on-ink-top:var(--c-navy-800);
  --on-ink-text:var(--c-white);
  --on-ink-muted:var(--c-sky-300);
  --on-ink-faint:var(--c-sky-400);
  --on-ink-link:var(--c-sky-200);
  --on-ink-accent:var(--c-mint-200);
  --on-ink-rule:rgba(var(--ch-sky),.16);
  --on-ink-grid:rgba(var(--ch-sky),.05);
  --on-ink-border:rgba(var(--ch-white),.32);
  --on-ink-dim:rgba(var(--ch-white),.72);

  /* interaction + signature */
  --focus-ring:0 0 0 3px rgba(var(--ch-blue),.14);
  --scrim:rgba(var(--ch-ink),.42);
  --scrim-soft:rgba(var(--ch-ink),.38);
  --selection:rgba(var(--ch-teal),.28);
  /* the atlas signature: three logo squares as one rule */
  --tri:linear-gradient(90deg, var(--logo-y) 0 33.4%, var(--logo-t) 33.4% 66.7%, var(--logo-g) 66.7% 100%);
  /* the cube-lattice motif as a static, repeatable tile — the no-JS / touch /
     reduced-motion face of the tess hero (ink navy line-work, drawn at 1px) */
  --tess-tile:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='64' viewBox='0 0 56 64'%3E%3Cg fill='none' stroke='%230E2238' stroke-width='1' stroke-linejoin='round' stroke-linecap='round'%3E%3Cpath d='M28 0v16M28 16l14 8M28 16l-14 8M14 24v16M42 24v16M0 16v16M56 16v16M28 48v16M28 48l14-8M28 48l-14-8M0 48l14 8M56 48l-14 8M14 8 0 16M42 8l14 8M14 8 28 0 42 8'/%3E%3C/g%3E%3C/svg%3E");

  /* ---------- type · families ---------- */
  --font-display:'Hanken Grotesk', system-ui, sans-serif;
  --font-body:'Inter', system-ui, sans-serif;
  --font-mono:'Geist Mono','JetBrains Mono', ui-monospace, monospace;

  /* type · mono label register (the atlas small-caps voice) */
  --label-xs:10px;
  --label-sm:11px;
  --label-md:11.5px;
  --label-lg:12.5px;

  /* type · body + UI register */
  --text-xs:13.5px;
  --text-sm:14.5px;
  --text-md:15px;
  --text-lg:16px;
  --text-xl:17px;
  --text-2xl:19px;
  --text-3xl:21px;

  /* type · display register, fluid */
  --display-xs:clamp(1.25rem, 1.05rem + .8vw, 1.6rem);
  --display-sm:clamp(1.5rem, 1.1rem + 1.2vw, 1.9rem);
  --display-md:clamp(1.75rem, 1rem + 2.6vw, 2.6rem);
  --display-lg:clamp(2rem, 1.5rem + 1.8vw, 3rem);
  --display-xl:clamp(2.1rem, .8rem + 3.4vw, 3.4rem);
  --display-2xl:clamp(3rem, 1.4rem + 3.5vw, 4.5rem);
  --text-lede:clamp(1.02rem, .95rem + .35vw, 1.18rem);
  --text-sub:clamp(.98rem, .9rem + .35vw, 1.1rem);

  --fw-regular:400; --fw-medium:500; --fw-semi:600; --fw-bold:700; --fw-black:800;

  --lh-tight:1.06; --lh-snug:1.35; --lh-normal:1.55; --lh-relaxed:1.65; --lh-loose:1.7;

  --track-tighter:-.025em; --track-tight:-.02em; --track-snug:-.015em;
  --track-wide:.06em; --track-label:.1em; --track-label-lg:.12em; --track-label-xl:.14em;

  /* ---------- space · static step scale ---------- */
  --sp-1:4px;  --sp-2:8px;  --sp-3:12px; --sp-4:16px; --sp-5:20px;
  --sp-6:24px; --sp-7:28px; --sp-8:32px; --sp-10:40px; --sp-12:48px;

  /* space · fluid rhythm — one ladder for gaps, card padding, block flow */
  --flow-2xs:clamp(12px, 1.6vw, 18px);
  --flow-xs:clamp(16px, 2.4vw, 26px);
  --flow-sm:clamp(20px, 2.4vw, 28px);
  --flow-md:clamp(24px, 3vw, 34px);
  --flow-lg:clamp(28px, 4vw, 44px);
  --flow-xl:clamp(36px, 4.5vw, 56px);
  --flow-2xl:clamp(44px, 6vw, 76px);
  --space-section:clamp(64px, 6vw + 32px, 110px);
  --space-band:clamp(28px, 4vw, 64px);

  /* space · viewport-height ladder — heroes breathe against the fold, not the
     gutter, so they scale on vh rather than vw */
  --vflow-sm:clamp(24px, 3.4vh, 32px);
  --vflow-md:clamp(28px, 4.5vh, 56px);
  --vflow-lg:clamp(38px, 6vh, 64px);
  --vflow-xl:clamp(44px, 7vh, 80px);
  --hero-top:clamp(100px, 13vh, 140px);

  /* ---------- shape ---------- */
  --r-8:8px; --r-12:12px; --r-16:16px; --r-20:20px; --pill:999px;
  --tap:44px;              /* minimum touch-target square */
  --bw-hair:1px; --bw-rule:2px; --bw-accent:3px; --bw-edge:4px; --bw-band:5px;

  --shadow-sm:0 1px 2px rgba(var(--ch-ink),.06);
  --shadow-md:0 12px 32px -14px rgba(var(--ch-ink),.16), 0 2px 8px rgba(var(--ch-ink),.05);
  --shadow-lg:0 30px 70px -30px rgba(var(--ch-ink),.24), 0 10px 28px -16px rgba(var(--ch-ink),.10);
  --shadow-cta:0 10px 24px -10px rgba(var(--ch-blue),.55);   /* the blue CTA pill lift */

  /* ---------- motion ---------- */
  --dur-fast:.16s; --dur-quick:.18s; --dur-base:.2s; --dur-slow:.25s;
  --dur-slower:.3s; --dur-panel:.34s; --dur-reveal:.7s;
  --ease-out:cubic-bezier(.2,.7,.2,1);

  /* ---------- layers ---------- */
  --z-raised:2; --z-head:60; --z-scrim:70; --z-nav:80; --z-drawer:90; --z-skip:200;

  /* ---------- layout ---------- */
  --maxw:1240px;
  --gutter:clamp(20px, 5vw, 56px);
  --head-h:72px;
}

/* ---------- reset ---------- */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
body{
  margin:0; background:var(--ground); color:var(--slate);
  font-family:var(--font-body); font-size:var(--text-xl); line-height:var(--lh-relaxed);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,svg{ max-width:100%; display:block; }
/* width/height attributes are for aspect reservation only — never let the raw
   height attribute win over a component's aspect-ratio or object-fit box. */
img{ height:auto; }
a{ color:inherit; text-decoration:none; }
button{ font-family:inherit; cursor:pointer; }
h1,h2,h3,h4{
  font-family:var(--font-display); font-weight:var(--fw-bold); letter-spacing:var(--track-tighter);
  margin:0; line-height:var(--lh-tight); color:var(--ink);
  overflow-wrap:normal; word-break:normal; hyphens:none;
}
p{ margin:0; }
ul,ol{ margin:0; padding:0; list-style:none; }
:focus-visible{ outline:2.5px solid var(--blue); outline-offset:3px; border-radius:4px; }
::selection{ background:var(--selection); color:var(--ink); }

.wrap{ width:100%; max-width:var(--maxw); margin:0 auto; padding-inline:var(--gutter); }
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
.nowrap{ white-space:nowrap; }

.skip{
  position:fixed; top:10px; left:10px; z-index:var(--z-skip);
  padding:12px 18px; border-radius:var(--pill);
  background:var(--ink); color:var(--on-ink-text); font-weight:var(--fw-semi); font-size:var(--text-sm);
  transform:translateY(-64px); opacity:0; transition:transform var(--dur-base), opacity var(--dur-base);
}
.skip:focus-visible{ transform:none; opacity:1; outline-offset:2px; }

/* ---------- logo ---------- */
/* translateZ(0) gives the inline SVG its own compositor layer: inside the
   header's backdrop-filter it otherwise flashes on tab restore while the
   browser re-rasterizes the blurred backdrop */
.logo-cube{ width:26px; height:22px; flex:none; transform:translateZ(0); }
.brand{
  display:inline-flex; align-items:center; gap:10px; font-family:var(--font-display);
  font-weight:var(--fw-black); font-size:var(--text-3xl); letter-spacing:var(--track-tight); color:var(--ink);
  min-height:var(--tap);
}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-2);
  min-height:46px; padding:12px 22px; border-radius:var(--pill);
  font-size:var(--text-sm); font-weight:var(--fw-semi); line-height:1; white-space:nowrap;
  border:1px solid transparent;
  transition:transform var(--dur-quick) ease, background var(--dur-quick) ease, border-color var(--dur-quick) ease, color var(--dur-quick) ease, box-shadow var(--dur-quick) ease;
}
.btn:hover{ transform:translateY(-2px); }
.btn .arr{ transition:transform var(--dur-quick) ease; }
.btn:hover .arr{ transform:translateX(3px); }
.btn-primary{ background:var(--blue); color:var(--on-ink-text); box-shadow:var(--shadow-cta); }
.btn-primary:hover{ background:var(--deep); }
.btn-secondary{ background:var(--paper); color:var(--ink); border-color:var(--hair-strong); box-shadow:var(--shadow-sm); }
.btn-secondary:hover{ border-color:var(--blue); color:var(--deep); }
.btn-sm{ min-height:40px; padding:10px 16px; font-size:var(--text-xs); }
.on-ink .btn-secondary{ background:transparent; color:var(--on-ink-text); border-color:var(--on-ink-border); box-shadow:none; }
.on-ink .btn-secondary:hover{ border-color:var(--on-ink-text); color:var(--on-ink-text); }

/* text link with arrow */
.tlink{
  display:inline-flex; align-items:center; gap:var(--sp-2); min-height:var(--tap);
  font-weight:var(--fw-semi); font-size:var(--text-sm); color:var(--deep);
}
.tlink .arr{ transition:transform var(--dur-quick) ease; }
.tlink:hover .arr{ transform:translateX(3px); }

/* ---------- eyebrow / section heads ---------- */
.eyebrow{
  font-family:var(--font-mono); font-size:var(--label-lg); font-weight:var(--fw-medium); letter-spacing:var(--track-label);
  text-transform:uppercase; color:var(--deep);
}
/* tri-colour survey tick - the atlas signature (the mobile-nav
   foot line and the drawer's category label) */
.mnav-foot::before,
.pd-cat::before{
  content:""; width:21px; height:7px; flex:none; border-radius:2px;
  background:var(--tri);
}
.sec-head h2{
  font-size:var(--display-md);
  margin:14px 0 14px; max-width:24ch; text-wrap:balance;
}
.sec-head .sec-sub{ font-size:var(--text-sub); line-height:var(--lh-relaxed); max-width:60ch; }
.sec-head--wide h2{ max-width:30ch; }
/* a section head with one action: the action sits level with the title, on the
   far right, and drops under the copy once the two no longer fit side by side.
   It stays last in the DOM so the tab order follows the reading order. */
.sec-head--action{ display:grid; grid-template-columns:minmax(0,1fr) auto; column-gap:var(--flow-lg); }
.sec-head--action > *{ grid-column:1; }
.sec-head--action .sec-action{ grid-column:2; grid-row:2; align-self:center; white-space:nowrap; }
@media(max-width:640px){
  .sec-head--action{ grid-template-columns:minmax(0,1fr); }
  .sec-head--action .sec-action{ grid-column:1; grid-row:auto; justify-self:start; margin-top:var(--flow-xs); }
}

/* Lattice texture for section grounds — the same --tess-tile the heroes carry,
   so a page never mixes two background patterns. Kept at the heroes' .035 so
   the texture stays a ground rather than a motif. */
.texgrid{ position:relative; }
.texgrid::before{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:0;
  background:var(--tess-tile);
  background-size:56px 64px;
  opacity:.035;
  -webkit-mask-image:radial-gradient(120% 100% at 50% 0%, #000 25%, transparent 82%);
  mask-image:radial-gradient(120% 100% at 50% 0%, #000 25%, transparent 82%);
}
.texgrid > .wrap{ position:relative; z-index:1; }

section{ padding-block:var(--space-section); }
[id]{ scroll-margin-top:calc(var(--head-h) + 18px); }

/* ============================================================
   HEADER - sticky paper bar
   ============================================================ */
.site-head{
  position:fixed; top:0; left:0; right:0; z-index:var(--z-head);
  background:rgba(var(--ch-paper),.86);
  -webkit-backdrop-filter:blur(12px); backdrop-filter:blur(12px);
  border-bottom:1px solid var(--hair);
}
.head-inner{ display:flex; align-items:center; gap:var(--sp-6); height:var(--head-h); }
.head-links{ display:none; gap:26px; margin-left:16px; }
.head-links a{
  font-size:var(--text-sm); font-weight:var(--fw-medium); color:var(--slate);
  padding:12px 2px; transition:color var(--dur-quick); position:relative;
}
.head-links a:hover{ color:var(--ink); }
.head-links a[aria-current="page"]{ color:var(--ink); }
.head-links a[aria-current="page"]::after{
  content:""; position:absolute; left:0; right:0; bottom:6px; height:2px; border-radius:2px;
  background:var(--tri);
}
.head-cta{ display:none; margin-left:auto; }

.burger{
  margin-left:auto; width:46px; height:46px; flex:none;
  display:inline-flex; flex-direction:column; align-items:center; justify-content:center; gap:5px;
  background:var(--paper); border:1px solid var(--hair); border-radius:10px;
}
.burger span{
  width:19px; height:2px; border-radius:2px; background:var(--ink);
  transition:transform var(--dur-slow) var(--ease-out), opacity var(--dur-base);
}
.burger[aria-expanded="true"] span:nth-child(1){ transform:translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2){ opacity:0; }
.burger[aria-expanded="true"] span:nth-child(3){ transform:translateY(-7px) rotate(-45deg); }

@media(min-width:1040px){
  .head-links{ display:flex; }
  .head-cta{ display:inline-flex; }
  .burger{ display:none; }
}

/* slide-in mobile panel */
.mnav-overlay{
  position:fixed; inset:0; z-index:var(--z-scrim);
  background:var(--scrim-soft);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  opacity:0; visibility:hidden; border:0; padding:0; margin:0; width:100%;
  transition:opacity var(--dur-slower) ease, visibility 0s linear var(--dur-slower);
}
.mnav{
  position:fixed; top:0; right:0; bottom:0; z-index:var(--z-nav);
  width:min(330px, 88vw);
  background:var(--paper);
  border-left:1px solid var(--hair);
  box-shadow:var(--shadow-lg);
  padding:18px 24px 28px;
  display:flex; flex-direction:column;
  transform:translateX(105%); visibility:hidden;
  transition:transform var(--dur-panel) var(--ease-out), visibility 0s linear var(--dur-panel);
  overflow-y:auto;
}
body.nav-open .mnav{ transform:none; visibility:visible; transition-delay:0s; }
body.nav-open .mnav-overlay{ opacity:1; visibility:visible; transition-delay:0s; }
body.nav-open{ overflow:hidden; }
.mnav-top{ display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--sp-5); }
.mnav-close{
  width:46px; height:46px; border-radius:10px; border:1px solid var(--hair);
  background:var(--paper); color:var(--ink); font-size:var(--text-3xl); line-height:1;
  display:inline-flex; align-items:center; justify-content:center;
}
.mnav-links{ display:flex; flex-direction:column; border-top:1px solid var(--hair); }
.mnav-links a{
  display:flex; align-items:center; justify-content:space-between;
  min-height:54px; padding:14px 4px;
  border-bottom:1px solid var(--hair);
  color:var(--ink); font-family:var(--font-display); font-weight:var(--fw-semi); font-size:var(--text-2xl);
}
.mnav-links a[aria-current="page"]{ color:var(--deep); }
.mnav-links a .idx{
  font-family:var(--font-mono); font-size:var(--label-sm); font-weight:var(--fw-regular);
  letter-spacing:var(--track-label-lg);
}
.mnav-links a:nth-child(1) .idx{ color:var(--y-text); }
.mnav-links a:nth-child(2) .idx{ color:var(--t-text); }
.mnav-links a:nth-child(3) .idx{ color:var(--g-text); }
.mnav-links a:nth-child(4) .idx{ color:var(--deep); }
.mnav-links a:nth-child(5) .idx{ color:var(--y-text); }
.mnav .btn{ margin-top:26px; width:100%; }
.mnav-foot{
  margin-top:auto; padding-top:26px;
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label);
  text-transform:uppercase; color:var(--mist);
  display:flex; align-items:center; gap:9px;
}

/* ============================================================
   HERO - the atlas fold
   ============================================================ */
.hero{
  position:relative;
  min-height:100svh;
  padding-block:0;
  background:
    radial-gradient(1100px 720px at 78% 30%, rgba(var(--ch-teal),.07), transparent 62%),
    linear-gradient(168deg, var(--paper) 0%, var(--ground) 52%, var(--c-paper-200) 100%);
  overflow:hidden;
  display:flex; flex-direction:column;
}
/* The lattice, not the survey grid — same tile the sub-page heroes carry, so
   the whole site reads with one background texture. The radial mask below is
   the hero's own and stays: it keeps the pattern off the headline column.
   Only the static tile here; the homepage's living layer is the atlas map, and
   tess-hero.js deliberately never mounts on index (the two must not stack). */
.hero::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:var(--tess-tile);
  background-size:56px 64px;
  opacity:.035;
  -webkit-mask-image:radial-gradient(120% 100% at 70% 40%, #000 30%, transparent 78%);
  mask-image:radial-gradient(120% 100% at 70% 40%, #000 30%, transparent 78%);
}
.hero .wrap{ position:relative; z-index:var(--z-raised); flex:1; display:flex; }

.hero h1{
  color:var(--ink);
  font-size:var(--display-xl);
  margin:18px 0 20px;
  text-wrap:balance;
}
.hero h1 .move{ color:var(--blue); }
.hero .sub{
  color:var(--slate);
  font-size:var(--text-lede);
  line-height:var(--lh-relaxed);
  max-width:480px;
  margin-bottom:var(--vflow-md);
}
.hero .ctas{ display:flex; flex-wrap:wrap; gap:var(--sp-3); margin-bottom:var(--vflow-md); }

.lbl{
  font-family:var(--font-mono); font-size:var(--label-sm); font-weight:var(--fw-medium);
  letter-spacing:var(--track-label); text-transform:uppercase; fill:var(--ink);
  paint-order:stroke; stroke:rgba(var(--ch-paper),.92); stroke-width:3.5px; stroke-linejoin:round;
}

@media(max-width:1000px){
  .hero{ min-height:0; }
}

/* ---------- wide desktop: the headline claims the empty north ----------
   Copy and map share one grid cell so the h1 can run out across the top of
   the map, where there is nothing but blank landmass. A paper scrim under the
   copy keeps the type off the coastline hairlines, and the sub / CTAs / stats
   stay on a short measure so nothing but the headline overlaps. */
@media(min-width:1180px){
  .hero h1{
    position:relative;
    width:min(78%,880px);
    font-size:var(--display-2xl);
    margin:20px 0 24px;
  }
  /* a soft paper halo behind the headline only — enough to lift the type off
     the coastline hairlines, not enough to bleach the map */
  .hero h1::before{
    content:""; position:absolute; z-index:-1; pointer-events:none;
    inset:-.34em -14% -.26em -7%;
    background:radial-gradient(78% 118% at 24% 50%,
      rgba(var(--ch-paper),.90) 0 44%,
      rgba(var(--ch-paper),.58) 68%,
      rgba(var(--ch-paper),0) 88%);
  }
  /* everything below the headline keeps a comfortable measure */
  .hero .sub{ max-width:470px; }
  .hero .ctas{ max-width:620px; }
}

/* ============================================================
   PAGE HERO - the compact atlas fold for sub-pages
   ============================================================ */
.page-hero{
  position:relative; overflow:hidden;
  padding-top:calc(var(--head-h) + var(--vflow-lg));
  padding-bottom:var(--flow-2xl);
  background:
    radial-gradient(900px 560px at 82% 18%, rgba(var(--ch-teal),.08), transparent 62%),
    linear-gradient(168deg, var(--paper) 0%, var(--ground) 60%, var(--c-paper-200) 100%);
  border-bottom:1px solid var(--hair);
}
.page-hero::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:var(--tess-tile);
  background-size:56px 64px;
  opacity:.035;
  -webkit-mask-image:radial-gradient(110% 100% at 72% 30%, #000 26%, transparent 78%);
  mask-image:radial-gradient(110% 100% at 72% 30%, #000 26%, transparent 78%);
}
.page-hero > .wrap{ position:relative; z-index:var(--z-raised); }
.ph-grid{ display:grid; grid-template-columns:minmax(0,7fr) minmax(0,5fr); gap:var(--space-band); align-items:center; }
.page-hero h1{
  font-size:var(--display-lg);
  margin:16px 0 18px; max-width:19ch; text-wrap:balance;
}
.page-hero h1 .move{ color:var(--blue); }
.page-hero .lede{
  font-size:var(--text-lede); line-height:var(--lh-relaxed);
  color:var(--slate); max-width:56ch;
}
.page-hero .ctas{ display:flex; flex-wrap:wrap; gap:var(--sp-3); margin-top:var(--flow-md); }
/* the shared photo plate — page-hero figure, split moment, story photo */
.ph-figure,
.split-media,
.story-photo{
  margin:0; border-radius:var(--r-16); overflow:hidden;
  border:1px solid var(--hair); box-shadow:var(--shadow-lg); background:var(--paper);
  position:relative;
}
.ph-figure img,
.split-media img,
.story-photo img{ width:100%; height:100%; object-fit:cover; aspect-ratio:4/3; }
/* beside the copy the 4:3 plate leaves the hero row slightly short — 5:4 takes
   that back. It stops there because every sub-page source is landscape and the
   products swatch wall is a 3x3 grid of trays: any taller and cover starts
   slicing its outer columns in half. */
@media(min-width:901px){ .ph-figure img{ aspect-ratio:5/4; } }
@media(max-width:900px){
  .ph-grid{ grid-template-columns:1fr; }
  .ph-figure{ order:-1; }
}
/* on a phone the stacked hero photo pushes the headline and CTAs below the
   fold for no gain — drop it and let the sub-page open on its words */
@media(max-width:640px){
  .ph-figure{ display:none; }
  .page-hero{ padding-bottom:var(--flow-xl); }
}

/* ============================================================
   TRUST STATS
   ============================================================ */
.trust{ background:var(--paper); border-top:1px solid var(--hair); }
.trust-grid{
  display:grid; grid-template-columns:minmax(300px,5fr) 7fr;
  gap:var(--flow-xs);
  align-items:stretch;
}
.feature-tile{
  position:relative; margin:0; overflow:hidden;
  border-radius:var(--r-16); border:1px solid var(--hair);
  background:var(--paper); box-shadow:var(--shadow-sm);
  display:flex; flex-direction:column;
}
.feature-tile img{ width:100%; flex:1; min-height:210px; object-fit:cover; }
.feature-tile figcaption{ padding:20px 22px 22px; border-top:3px solid var(--logo-y); }
.feature-tile .val{
  font-family:var(--font-display); font-weight:var(--fw-black); letter-spacing:var(--track-tight);
  font-size:var(--display-lg); color:var(--ink); line-height:1;
  margin:10px 0 8px;
}
.feature-tile .cap{ font-size:var(--text-md); color:var(--slate); max-width:34ch; }
.tile-label{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-lg); text-transform:uppercase; color:var(--mist);
}

.stat-cells{ display:grid; grid-template-columns:repeat(2,1fr); gap:var(--flow-2xs); }
/* the --3 variant is the standalone one, sitting directly under a section head
   rather than inside .trust-grid, so it carries its own top rhythm */
.stat-cells--3{ grid-template-columns:repeat(3,1fr); margin-top:var(--flow-lg); }
.stat-cell{
  position:relative;
  border:1px solid var(--hair); border-radius:var(--r-16);
  background:var(--paper); box-shadow:var(--shadow-sm);
  padding:var(--flow-sm);
  display:flex; flex-direction:column; justify-content:flex-end;
  min-height:132px; overflow:hidden;
}
.stat-cell .n{
  font-family:var(--font-display); font-weight:var(--fw-black); letter-spacing:var(--track-tight);
  font-size:var(--display-lg); color:var(--ink); line-height:1;
}
.stat-cell .n::after{ content:""; display:block; width:44px; height:5px; border-radius:3px; margin-top:var(--sp-3); }
.stat-cell:nth-child(1) .n::after{ background:var(--logo-y); }
.stat-cell:nth-child(2) .n::after{ background:var(--logo-t); }
.stat-cell:nth-child(3) .n::after{ background:var(--logo-g); }
.stat-cell:nth-child(4) .n::after{ background:var(--blue); }
.stat-cell:nth-child(5) .n::after{ background:var(--logo-y); }
.stat-cell:nth-child(6) .n::after{ background:var(--logo-t); }
.stat-cell .l{
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label); text-transform:uppercase;
  color:var(--mist); margin-top:9px;
}
/* ---------- the credential line — the signature rule ----------
   This was a tinted panel holding a sentence and three outline pills, and it
   gave three real credentials the visual grammar of a disclaimer. Worse, the
   sentence said what the pills already said, so half the band repeated itself.
   Set as one line under the logo's three-colour rule, carrying the dates the
   pills never did, it reads as a masthead credit instead of a footnote. */
.cred{ margin-top:var(--flow-md); }
.cred .tri-rule{
  display:block; width:96px; height:3px; border-radius:2px;
  background:var(--tri); margin-bottom:var(--sp-4);
}
.cred-row{ display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--sp-3) var(--sp-6); }
.cred-cap{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-xl);
  text-transform:uppercase; color:var(--mist);
}
.cred-list{
  --cred-pair:9px;                       /* name to whom */
  display:flex; flex-wrap:wrap; align-items:baseline;
  gap:var(--sp-3) var(--sp-6); margin:0; padding:0; list-style:none;
}
.cred-list li{ display:flex; align-items:baseline; gap:var(--cred-pair); }
/* The hairline between credentials is a pseudo-element, not an empty span, so
   the three of them stay a list of three things to a screen reader. Centring it
   is not just its own margin: the rule is generated INSIDE the following item,
   which makes it that item's first flex child, so the item's own --cred-pair
   gap lands to the rule's right on top of the margin. Subtract it back out, or
   the hairline sits 9px nearer the credential before it than the one after. */
.cred-list li + li::before{
  content:""; width:1px; height:14px; align-self:center;
  background:var(--hair-strong); margin-right:calc(var(--sp-6) - var(--cred-pair));
}
.cred-list .nm{
  font-family:var(--font-display); font-weight:var(--fw-bold); font-size:1rem;
  letter-spacing:var(--track-snug); color:var(--ink);
}
.cred-list .yr{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label);
  color:var(--mist); font-variant-numeric:tabular-nums;
}
/* Stack before the row can wrap, not after. A wrapped flex line starts with
   whatever the item carries, so the separator - which hangs off the item that
   follows it - lands at the head of the new line with nothing to its left. The
   three credentials need ~600px and run out at about a 656px viewport, so the
   switch sits at 720px with room for a font that loads wider than expected.
   Measured: at 640px the old 620px breakpoint left a hairline stranded in
   front of SAP. Do not lower this without re-checking that range. */
@media(max-width:720px){
  .cred-list{ flex-direction:column; align-items:flex-start; gap:var(--sp-3); }
  .cred-list li + li::before{ display:none; }
}
@media(max-width:860px){ .trust-grid{ grid-template-columns:1fr; } }
@media(max-width:640px){ .stat-cells--3{ grid-template-columns:repeat(2,1fr); } }
@media(max-width:430px){
  .stat-cells{ grid-template-columns:1fr 1fr; }
  .stat-cell{ min-height:112px; }
}

/* ============================================================
   PRODUCTS & INDUSTRIES - the soft tinted band
   ============================================================ */
.industries{ background:var(--tint); border-top:1px solid var(--hair); }
.icards{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--flow-2xs); margin-top:var(--flow-lg); }
.icard{
  position:relative; display:block;
  border:1px solid var(--hair); border-radius:var(--r-16);
  background:var(--paper); box-shadow:var(--shadow-sm);
  overflow:hidden;
  transition:transform var(--dur-slow) var(--ease-out), box-shadow var(--dur-slow), border-color var(--dur-slow);
}
.icard::before{ content:""; position:absolute; top:0; left:0; right:0; height:var(--bw-accent); z-index:3; }
.icard:nth-child(3n+1)::before{ background:var(--logo-y); }
.icard:nth-child(3n+2)::before{ background:var(--logo-t); }
.icard:nth-child(3n)::before{ background:var(--logo-g); }
.icard:hover{ transform:translateY(-3px); box-shadow:var(--shadow-md); border-color:var(--hair-strong); }
/* One ratio at every width — the phone crop was the right one, so the desktop
   cards use it too rather than carrying a second value to keep in sync. */
.icard .ph{ position:relative; aspect-ratio:16/6.4; overflow:hidden; background:var(--tint); }
.icard .ph img{ width:100%; height:100%; object-fit:cover; transition:transform .4s var(--ease-out); }
.icard:hover .ph img{ transform:scale(1.045); }
.icard .meta{ padding:16px 18px 18px; }
.icard h3{ font-size:1.08rem; font-weight:var(--fw-bold); letter-spacing:var(--track-snug); }
.icard .tags{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-wide); text-transform:uppercase;
  color:var(--mist); margin-top:7px; line-height:var(--lh-normal);
}
/* category cards that filter the index rather than just linking to it */
.icard .tags .go{
  color:var(--deep); float:right; opacity:0; transform:translateX(-4px);
  transition:opacity var(--dur-base), transform var(--dur-base);
}
.icard:hover .tags .go, .icard:focus-visible .tags .go{ opacity:1; transform:none; }
@media(hover:none){ .icard .tags .go{ opacity:1; transform:none; } }
@media(max-width:760px){ .icards{ grid-template-columns:repeat(2,1fr); } }
@media(max-width:400px){
  .icards{ grid-template-columns:1fr; }
  .icard .meta{ padding:12px 16px 14px; }
}

/* ============================================================
   INDEX CARDS (generic 3-up feature cards)
   ============================================================ */
.wcards{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--flow-2xs); margin-top:var(--flow-lg); }
.wcards--2{ grid-template-columns:repeat(2,1fr); }
.wcard{
  position:relative;
  border:1px solid var(--hair); border-radius:var(--r-16);
  background:var(--paper); box-shadow:var(--shadow-sm);
  padding:var(--flow-sm);
  transition:border-color var(--dur-slow), transform var(--dur-slow) var(--ease-out), box-shadow var(--dur-slow);
}
.wcard:hover,
.branch:hover{ border-color:var(--hair-strong); transform:translateY(-3px); box-shadow:var(--shadow-md); }
.wcard .mod{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-xl); text-transform:uppercase;
  color:var(--mist);
  border-bottom:1px dashed var(--hair-strong);
  padding-bottom:12px; margin-bottom:var(--sp-4);
}
.wcard .ico{
  width:42px; height:42px; border-radius:11px;
  display:flex; align-items:center; justify-content:center;
  margin-bottom:15px;
}
.wcard .ico svg{ width:22px; height:22px; }
.wcard:nth-child(6n+1) .ico{ background:rgba(var(--ch-yellow),.16);  color:var(--y-text); }
.wcard:nth-child(6n+2) .ico{ background:rgba(var(--ch-teal),.14);  color:var(--t-text); }
.wcard:nth-child(6n+3) .ico{ background:rgba(var(--ch-green),.16);  color:var(--g-text); }
.wcard:nth-child(6n+4) .ico{ background:rgba(var(--ch-blue),.12);  color:var(--deep); }
.wcard:nth-child(6n+5) .ico{ background:rgba(var(--ch-teal),.14);  color:var(--t-text); }
.wcard:nth-child(6n)   .ico{ background:rgba(var(--ch-green),.16);  color:var(--g-text); }
.wcard:nth-child(6n+1) .mod .tag{ color:var(--y-text); }
.wcard:nth-child(6n+2) .mod .tag{ color:var(--t-text); }
.wcard:nth-child(6n+3) .mod .tag{ color:var(--g-text); }
.wcard:nth-child(6n+4) .mod .tag{ color:var(--deep); }
.wcard:nth-child(6n+5) .mod .tag{ color:var(--t-text); }
.wcard:nth-child(6n)   .mod .tag{ color:var(--g-text); }
.wcard h3{ font-size:1.1rem; margin-bottom:var(--sp-2); letter-spacing:var(--track-snug); }
.wcard p{ font-size:var(--text-md); line-height:var(--lh-relaxed); color:var(--slate); }
.wcard .portrait{
  width:100%; aspect-ratio:1/1; object-fit:cover; border-radius:var(--r-12);
  margin-bottom:var(--sp-4); background:var(--tint);
}
.wcard .role{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-lg); text-transform:uppercase;
  color:var(--mist); margin-bottom:6px;
}
@media(max-width:980px){ .wcards{ grid-template-columns:repeat(2,1fr); } }
@media(max-width:620px){ .wcards, .wcards--2{ grid-template-columns:1fr; } }

/* ============================================================
   LEADERSHIP - two tiers, because two of the six carry the story
   The founder and the Managing Director get a wide card with the portrait
   beside the write-up; the rest of the board is a plain name grid. Keeping
   them in one uniform 3-up made the two who built the place look like
   everyone else, and gave the other four an empty half-card to fill.
   ============================================================ */
.leads{ display:grid; grid-template-columns:repeat(2,1fr); gap:var(--flow-2xs); margin-top:var(--flow-lg); }
.lead-card{
  display:grid; grid-template-columns:clamp(132px, 40%, 216px) minmax(0,1fr);
  gap:var(--flow-2xs); align-items:start;
  border:1px solid var(--hair); border-radius:var(--r-16);
  background:var(--paper); box-shadow:var(--shadow-sm);
  padding:var(--flow-sm);
  transition:border-color var(--dur-slow), transform var(--dur-slow) var(--ease-out), box-shadow var(--dur-slow);
}
.lead-card:hover,
.person:hover{ border-color:var(--hair-strong); transform:translateY(-3px); box-shadow:var(--shadow-md); }
.lead-card .portrait,
.person .portrait{
  width:100%; aspect-ratio:1/1; object-fit:cover; object-position:50% 22%;
  border-radius:var(--r-12); background:var(--tint);
}
.lead-card .role,
.person .role{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-lg);
  text-transform:uppercase; color:var(--mist); margin-bottom:6px;
}
.lead-card h3{ font-size:1.24rem; letter-spacing:var(--track-snug); }
/* a short brand rule under the name - the quiet marker that says "these two" */
.lead-card h3::after{
  content:""; display:block; width:34px; height:3px; border-radius:2px;
  margin:var(--sp-3) 0 var(--sp-4);
}
.leads .lead-card:nth-child(1) h3::after{ background:var(--logo-y); }
.leads .lead-card:nth-child(2) h3::after{ background:var(--logo-t); }
.lead-card p{ font-size:var(--text-md); line-height:var(--lh-relaxed); color:var(--slate); }

.people-lede{
  display:flex; align-items:center; gap:var(--sp-4);
  margin-top:var(--flow-lg);
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label-xl);
  text-transform:uppercase; color:var(--mist);
}
.people-lede::after{ content:""; flex:1; height:1px; background:var(--hair-strong); }
.people{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--flow-2xs); margin-top:var(--flow-sm); }
.person{
  border:1px solid var(--hair); border-radius:var(--r-16);
  background:var(--paper); box-shadow:var(--shadow-sm);
  padding:var(--flow-2xs);
  transition:border-color var(--dur-slow), transform var(--dur-slow) var(--ease-out), box-shadow var(--dur-slow);
}
.person .portrait{ margin-bottom:var(--sp-4); }
.person h3{ font-size:1.02rem; letter-spacing:var(--track-snug); }

/* Portraits stay black and white for now. Drop `bw-portraits` from the
   section to bring the colour back - nothing else depends on it. */
.bw-portraits .portrait{ filter:grayscale(1); }

@media(max-width:980px){
  .leads{ grid-template-columns:1fr; }
  .people{ grid-template-columns:repeat(2,1fr); }
}
@media(max-width:620px){
  .lead-card{ grid-template-columns:1fr; }
  .lead-card .portrait{ width:140px; }
}

/* ============================================================
   SPLIT MOMENT - copy + checklist beside a photo plate
   ============================================================ */
.split{ display:grid; grid-template-columns:minmax(300px,6fr) 7fr; gap:var(--space-band); align-items:center; }
/* Only the careers branch-office shot (.industries) gains from a deeper crop:
   its copy column runs taller than the plate, and the extra height lands on
   ceiling and desk rather than on nothing. The homepage yard shot (.trust) is
   a panorama whose plate is already the taller column — cropping it further
   just trades pallet rows for empty concrete, so it stays at 4:3. */
@media(min-width:881px){ .industries .split-media img{ aspect-ratio:5/4; } }
.checklist{ display:grid; gap:13px; margin:var(--flow-sm) 0 0; }
.checklist li{ display:flex; gap:var(--sp-3); align-items:flex-start; font-size:var(--text-md); color:var(--slate); line-height:var(--lh-relaxed); }
.checklist li svg{ width:19px; height:19px; flex:none; margin-top:2px; }
.checklist li:nth-child(3n+1) svg{ color:var(--y-text); }
.checklist li:nth-child(3n+2) svg{ color:var(--t-text); }
.checklist li:nth-child(3n)   svg{ color:var(--g-text); }
.checklist li b{ color:var(--ink); font-weight:var(--fw-semi); }
@media(max-width:880px){
  .split{ grid-template-columns:1fr; }
}

/* ============================================================
   BRANCH TICKER — the homepage distribution rail
   One continuous line instead of a wrapped chip grid, with the branch names
   separated by the logo's own geometry: a rounded rectangle, tilted, cycling
   the three brand colours.

   The rail holds two identical tracks, so translating it -50% lands exactly one
   track along and the loop is seamless. The second track is aria-hidden, so the
   thirteen branches are announced once rather than twice.
   ============================================================ */
.bticker{
  position:relative; overflow:hidden; margin-top:var(--flow-md);
  /* fade both ends so names enter and leave instead of popping at a hard edge */
  mask-image:linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
  -webkit-mask-image:linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
}
.bticker-rail{
  display:flex; width:max-content;
  animation:bticker 42s linear infinite;
  will-change:transform;
}
@keyframes bticker{ from{ transform:translateX(0); } to{ transform:translateX(-50%); } }
/* pause for anyone who wants to read a specific name */
.bticker:hover .bticker-rail,
.bticker:focus-within .bticker-rail{ animation-play-state:paused; }

.bticker-track{
  display:flex; align-items:center; flex:none;
  margin:0; padding:0; list-style:none;
}
.bticker-item{
  display:inline-flex; align-items:center; gap:17px; padding-right:17px;
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-wide);
  text-transform:uppercase; color:var(--slate); white-space:nowrap;
}
/* the separator: a logo cube, not a dot — same 0.25 corner ratio and tilt as
   the three rects in the wordmark SVG */
.bticker-item::after{
  content:""; flex:none; width:10px; height:10px; border-radius:2.5px;
  background:var(--hair-strong);
}
.bticker-item:nth-child(3n+1)::after{ background:var(--logo-y); transform:rotate(-12deg); }
.bticker-item:nth-child(3n+2)::after{ background:var(--logo-t); transform:rotate(12deg); }
.bticker-item:nth-child(3n)::after{   background:var(--logo-g); transform:rotate(-6deg); }
/* 13 is prime, so a 3-cycle would repeat a colour across the loop seam —
   force the last one teal so the wrap reads green, teal, yellow */
.bticker-item:nth-child(13)::after{ background:var(--logo-t); transform:rotate(12deg); }
.bticker-item--hq{ color:var(--ink); font-weight:var(--fw-medium); }

@media(prefers-reduced-motion:reduce){
  /* no travel: drop the duplicate and let the row be scrolled by hand */
  .bticker-rail{ animation:none; }
  .bticker{ overflow-x:auto; mask-image:none; -webkit-mask-image:none; }
  .bticker-track[aria-hidden="true"]{ display:none; }
}

/* ============================================================
   STORY / PEOPLE
   ============================================================ */
.story{ background:var(--tint-2); border-top:1px solid var(--hair); }
.story-grid{ display:grid; grid-template-columns:minmax(300px,7fr) 6fr; gap:var(--space-band); align-items:center; }
.story .lead{
  font-size:var(--text-lede); line-height:var(--lh-loose);
  color:var(--slate); max-width:56ch; margin:4px 0 26px;
}
/* the copy column runs far taller than a 4:3 plate, so the photo floated in a
   pool of its own whitespace. Square closes most of that gap, and the index
   photo is shot portrait — it only ever had height to give back. */
@media(min-width:881px){ .story-photo img{ aspect-ratio:1/1; } }
.leaders{ display:flex; flex-wrap:wrap; gap:14px; margin-top:var(--flow-md); }
.leader{
  display:inline-flex; align-items:center; gap:var(--sp-3);
  background:var(--paper); border:1px solid var(--hair); border-radius:var(--pill);
  padding:8px 18px 8px 8px; box-shadow:var(--shadow-sm);
}
.leader img{ width:44px; height:44px; border-radius:50%; object-fit:cover; flex:none; background:var(--tint); }
.leader b{ display:block; font-family:var(--font-display); font-size:var(--text-md); font-weight:var(--fw-bold); color:var(--ink); letter-spacing:var(--track-snug); }
.leader span{
  display:block; font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label);
  text-transform:uppercase; color:var(--mist); margin-top:3px;
}
@media(max-width:880px){
  .story-grid{ grid-template-columns:1fr; }
  .story-photo{ order:-1; max-width:640px; }
}

/* ============================================================
   TIMELINE - a transit line with hub-dot stations
   ============================================================ */
.timeline{ margin-top:var(--flow-2xl); position:relative; max-width:820px; }
.tstop{ position:relative; padding:0 0 26px 40px; }
.tstop:last-child{ padding-bottom:0; }
/* One unbroken line with stations on it, not a run of dashes: the connector
   spans the stop's FULL height and passes behind the dot, so each segment butts
   into the next with no seam. Square ends for the same reason - a radius here
   pinches the line at every colour change. Only the two true ends are rounded,
   and the era headers (below) bridge the gaps between groups. */
.tstop::before{ content:""; position:absolute; left:6.5px; top:0; bottom:0; width:3px; background:var(--logo-y); }
.tstop .dot{
  position:absolute; left:0; top:4px;
  width:16px; height:16px; border-radius:50%;
  background:var(--paper); border:3px solid; box-shadow:var(--shadow-sm);
}
.tstop .yr{ font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label-xl); text-transform:uppercase; }
.tstop .yr .place{ color:var(--mist); }
.tstop h3, .tstop h4{ font-size:1.08rem; margin:5px 0 5px; letter-spacing:var(--track-snug); }
.tstop p{ font-size:var(--text-md); color:var(--slate); max-width:52ch; }

/* ---------- the journey, grouped into eras with a show-all toggle ---------- */
.journey{ margin-top:var(--flow-xl); max-width:820px; }
/* these are <section>s inside a section, so the global band padding has to go */
.tgroup{ position:relative; padding-block:0; }
.tgroup + .tgroup{ margin-top:var(--flow-xl); }
.tgroup-h{
  position:relative;
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2) var(--sp-3);
  padding-bottom:var(--sp-4); padding-left:40px; border-bottom:1px solid var(--hair);
  font-size:1.06rem; letter-spacing:var(--track-snug);
}
/* The line carries on past every era header but the first, so the four groups
   read as one route rather than four. The offsets are exactly the gaps either
   side of the header - the group's own margin-top above, the timeline's
   margin-top below - so it meets the stop connectors with no join. The 40px
   indent above keeps the era label clear of it and in line with the stop text. */
.tgroup + .tgroup > .tgroup-h::before{
  content:""; position:absolute; left:6.5px; width:3px;
  top:calc(-1 * var(--flow-xl)); bottom:calc(-1 * var(--flow-sm));
  background:var(--logo-y);
}
/* the route starts at the first station and terminates at the last one */
.journey > .tgroup:first-child .timeline > .tstop:first-child::before{
  top:12px; border-radius:2px 2px 0 0;
}
.journey > .tgroup:last-child .timeline > .tstop:last-child::before,
.journey > .tgroup:last-child .timeline > .tstop.is-lastvis::before{
  bottom:auto; height:12px; border-radius:0 0 2px 2px;
}
/* Colour runs by era, not by stop. A line that changed colour at every marker
   read as segments; changing it only where the era changes - the one boundary
   that means something - is what makes the whole thing read as one route.
   Yellow, teal, green from the logo, then brand blue for the era we are in. */
.journey > .tgroup:nth-child(1) .tstop::before{ background:var(--logo-y); }
.journey > .tgroup:nth-child(1) .dot{ border-color:var(--fam-y); }
.journey > .tgroup:nth-child(1) .yr{ color:var(--y-text); }
.journey > .tgroup:nth-child(2) .tstop::before,
.journey > .tgroup:nth-child(2) > .tgroup-h::before{ background:var(--logo-t); }
.journey > .tgroup:nth-child(2) .dot{ border-color:var(--logo-t); }
.journey > .tgroup:nth-child(2) .yr{ color:var(--t-text); }
.journey > .tgroup:nth-child(3) .tstop::before,
.journey > .tgroup:nth-child(3) > .tgroup-h::before{ background:var(--fam-g); }
.journey > .tgroup:nth-child(3) .dot{ border-color:var(--fam-g); }
.journey > .tgroup:nth-child(3) .yr{ color:var(--g-text); }
.journey > .tgroup:nth-child(4) .tstop::before,
.journey > .tgroup:nth-child(4) > .tgroup-h::before{ background:var(--blue); }
.journey > .tgroup:nth-child(4) .dot{ border-color:var(--blue); }
.journey > .tgroup:nth-child(4) .yr{ color:var(--deep); }
.tgroup-yrs{
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label-lg);
  text-transform:uppercase; color:var(--deep); font-weight:var(--fw-medium);
  padding:5px 11px; border-radius:var(--pill);
  background:var(--tint); border:1px solid var(--hair-strong);
}
.tgroup-n{
  margin-left:auto; font-family:var(--font-mono); font-size:var(--label-md);
  letter-spacing:var(--track-label-xl); text-transform:uppercase;
  color:var(--mist); font-weight:var(--fw-medium);
}
.tgroup .timeline{ margin-top:var(--flow-sm); }
/* Collapsed by default, but only where the toggle can undo it: keyed off
   html.js so a no-script reader gets the whole list and no toggle, and so the
   collapse is in the first paint rather than a flash of all twenty-one.
   The line terminates at the last *visible* stop, not the last in the markup. */
.js .journey:not(.is-expanded) .tstop:not(.tstop--key){ display:none; }

/* The scope control sits ABOVE the list, not under it: parked at the bottom it
   was only discoverable after scrolling the whole collapsed timeline. Gated on
   html.js for the same reason the collapse is — no script, whole list, no button. */
.journey-bar{ display:none; }
.js .journey-bar{
  display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-3) var(--sp-4);
  margin-top:var(--flow-lg);
}
.journey-bar .scope{
  font-family:var(--font-mono); font-size:var(--label-md);
  letter-spacing:var(--track-label-xl); text-transform:uppercase; color:var(--mist);
}
.journey-bar .rule{ flex:1; min-width:var(--sp-4); height:1px; background:var(--hair-strong); }
.journey-toggle{
  display:inline-flex; align-items:center; gap:10px; min-height:46px;
  padding:12px 20px; border:1px solid var(--hair-strong); border-radius:var(--pill);
  background:var(--paper); color:var(--ink);
  font-family:var(--font-display); font-weight:var(--fw-semi); font-size:var(--text-sm);
  box-shadow:var(--shadow-sm);
  transition:border-color var(--dur-quick), background var(--dur-quick), color var(--dur-quick);
}
.journey-toggle:hover{ border-color:var(--blue); color:var(--deep); background:var(--tint-2); }
.journey-toggle .chev{
  width:8px; height:8px; flex:none;
  border-right:var(--bw-rule) solid currentColor; border-bottom:var(--bw-rule) solid currentColor;
  transform:rotate(45deg) translateY(-2px); transition:transform var(--dur-fast);
}
.journey-toggle[aria-expanded="true"] .chev{ transform:rotate(-135deg) translateY(-2px); }

/* ============================================================
   PROSE / KEY-VALUE / NOTE / TAGS
   ============================================================ */
.prose{ max-width:66ch; }
.prose p{ font-size:var(--text-lg); line-height:var(--lh-loose); color:var(--slate); }
.prose p + p{ margin-top:var(--sp-4); }
.prose strong{ color:var(--ink); font-weight:var(--fw-semi); }
.pullquote{
  margin:var(--flow-md) 0;
  padding-left:22px; border-left:var(--bw-edge) solid var(--logo-t);
  font-family:var(--font-display); font-weight:var(--fw-bold); letter-spacing:var(--track-tight);
  font-size:var(--display-xs); line-height:var(--lh-snug); color:var(--ink);
  max-width:34ch;
}
.kv{ border-top:1px solid var(--hair); margin-top:var(--flow-md); }
.kv .row{ display:grid; grid-template-columns:1fr; gap:var(--sp-1); padding:16px 0; border-bottom:1px solid var(--hair); }
@media(min-width:640px){ .kv .row{ grid-template-columns:minmax(0,190px) minmax(0,1fr); gap:var(--sp-6); align-items:baseline; } }
.kv .k{ font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-lg); text-transform:uppercase; color:var(--mist); }
.kv .v{ font-size:var(--text-lg); color:var(--ink); }
.kv .v a{ color:var(--deep); font-weight:var(--fw-medium); }
.kv .v a:hover{ color:var(--blue); }
.note{
  border:1px solid var(--hair); border-left:var(--bw-edge) solid var(--logo-y);
  border-radius:var(--r-12); background:var(--paper); box-shadow:var(--shadow-sm);
  padding:20px 24px; margin-top:var(--flow-md); max-width:64ch;
}
.note h3{ font-size:1.05rem; margin-bottom:var(--sp-2); }
.note p{ font-size:var(--text-md); color:var(--slate); line-height:var(--lh-relaxed); }
.note a{ color:var(--deep); font-weight:var(--fw-semi); }
.taglist{ display:flex; flex-wrap:wrap; gap:var(--sp-2); margin-top:var(--flow-lg); }
.pill{
  display:inline-flex; align-items:center; gap:var(--sp-2); min-height:34px;
  padding:7px 13px; border-radius:var(--pill);
  border:1px solid var(--hair-strong); background:var(--paper);
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-wide); text-transform:uppercase;
  color:var(--slate);
}
.pill--y{ border-color:var(--fam-y); color:var(--y-text); }
.pill--t{ border-color:var(--logo-t); color:var(--t-text); }
.pill--g{ border-color:var(--fam-g); color:var(--g-text); }
.pill--b{ border-color:var(--blue); color:var(--deep); }

/* ============================================================
   CATALOGUE (products) — filter rail + A–Z results
   ============================================================ */
/* the 264px rail + results layout is the products catalogue's alone now; the
   contact directory traded its rail for a map pane - see BRANCH DIRECTORY */
.catalog{
  display:grid; grid-template-columns:1fr;
  gap:var(--flow-md);
  margin-top:var(--flow-lg);
}
@media(min-width:1000px){
  .catalog{ grid-template-columns:264px minmax(0,1fr); gap:var(--flow-xl); align-items:start; }
}

/* ---------- left rail ---------- */
@media(min-width:1000px){
  .cat-side{
    position:sticky; top:calc(var(--head-h) + 20px);
    max-height:calc(100vh - var(--head-h) - 40px);
    overflow-y:auto; overscroll-behavior:contain;
    padding-right:4px; scrollbar-width:thin;
  }
}
.cat-side-inner{ display:flex; flex-direction:column; gap:14px; }

.qsearch{
  position:relative; display:flex; align-items:center;
  border:1px solid var(--hair-strong); border-radius:var(--r-12);
  background:var(--paper); box-shadow:var(--shadow-sm);
  transition:border-color var(--dur-quick), box-shadow var(--dur-quick);
}
.qsearch:focus-within{ border-color:var(--blue); box-shadow:var(--focus-ring); }
.qsearch-ico{ width:17px; height:17px; flex:none; margin-left:13px; color:var(--mist); }
.qsearch input{
  flex:1; min-width:0; border:0; background:transparent; color:var(--ink);
  font-family:var(--font-body); font-size:var(--text-lg); padding:12px 10px; min-height:46px;
}
.qsearch input::placeholder{ color:var(--mist); }
.qsearch input:focus{ outline:none; }
.qsearch input::-webkit-search-cancel-button{ -webkit-appearance:none; appearance:none; }
.qsearch-x{
  flex:none; width:34px; height:34px; margin-right:6px;
  border:0; border-radius:9px; background:var(--tint); color:var(--slate);
  font-size:var(--text-2xl); line-height:1; display:inline-flex; align-items:center; justify-content:center;
  transition:background var(--dur-quick), color var(--dur-quick);
}
.qsearch-x[hidden]{ display:none; }
.qsearch-x:hover{ background:var(--hair); color:var(--ink); }

.side-label{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-xl); text-transform:uppercase;
  color:var(--mist); margin-top:var(--sp-2);
}
.fbtn{
  width:100%; display:flex; align-items:center; gap:10px;
  min-height:42px; padding:9px 12px;
  border:1px solid transparent; border-radius:10px;
  background:transparent; color:var(--slate);
  font-family:var(--font-body); font-size:var(--text-sm); font-weight:var(--fw-medium); text-align:left;
  transition:background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.fbtn::before{ content:""; width:8px; height:8px; border-radius:2.5px; flex:none; background:var(--hair-strong); }
.fbtn .n{
  margin-left:auto; font-family:var(--font-mono); font-size:var(--label-md); color:var(--mist);
  font-variant-numeric:tabular-nums;
}
.fbtn:hover{ background:var(--tint-2); color:var(--ink); }
.fbtn[aria-pressed="true"]{ background:var(--ink); border-color:var(--ink); color:var(--on-ink-text); }
.fbtn[aria-pressed="true"] .n{ color:var(--on-ink-dim); }
.fbtn.is-empty{ opacity:.42; }

/* ---------- the products rail is a tree: 6 industries, each opening onto
     the sub-categories that actually hold stock under it. ---------- */
.ftree{ display:flex; flex-direction:column; gap:2px; }
.fbtn--all::before{ background:var(--ink); }
/* the three logo colours cycle down the six industries (li 1 is All products) */
.ftree > li:nth-child(3n+2) .fbtn--ind::before{ background:var(--logo-y); }
.ftree > li:nth-child(3n)   .fbtn--ind::before{ background:var(--logo-t); }
.ftree > li:nth-child(3n+1) .fbtn--ind::before{ background:var(--logo-g); }

.ftree-row{ display:flex; align-items:center; gap:1px; }
.ftree-row .fbtn{ min-width:0; }
.ftree-tog{
  flex:none; width:24px; height:24px; margin-left:-4px;
  display:inline-flex; align-items:center; justify-content:center;
  border:0; border-radius:7px; background:transparent; color:var(--mist);
  transition:background var(--dur-fast), color var(--dur-fast);
}
.ftree-tog:hover{ background:var(--tint); color:var(--ink); }
.ftree-chev{ width:13px; height:13px; transition:transform var(--dur-fast) var(--ease-out); }
.ftree-tog[aria-expanded="true"] .ftree-chev{ transform:rotate(90deg); }

/* the spine: one hairline running down the children of an open branch */
.ftree-sub{
  display:flex; flex-direction:column; gap:1px;
  margin:2px 0 6px 11px; padding-left:12px;
  border-left:1px solid var(--hair-strong);
}
.ftree-sub[hidden]{ display:none; }
.fbtn--sub{
  min-height:36px; padding:7px 11px;
  font-size:var(--text-xs); font-weight:var(--fw-regular); color:var(--mist);
}
.fbtn--sub::before{ width:5px; height:5px; border-radius:50%; }

.az-jump{ display:grid; grid-template-columns:repeat(6,1fr); gap:5px; }
.az-jump a{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:36px; border:1px solid var(--hair); border-radius:9px; background:var(--paper);
  font-family:var(--font-mono); font-size:var(--label-lg); color:var(--slate);
  transition:border-color var(--dur-quick), color var(--dur-quick), background var(--dur-quick);
}
.az-jump a:hover{ border-color:var(--blue); color:var(--deep); }
.az-jump a.is-off{ opacity:.3; pointer-events:none; }

.side-reset{
  align-self:flex-start; min-height:38px; padding:8px 14px;
  border:1px solid var(--hair-strong); border-radius:var(--pill);
  background:var(--paper); color:var(--slate);
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label); text-transform:uppercase;
  transition:border-color var(--dur-quick), color var(--dur-quick);
}
.side-reset:hover{ border-color:var(--blue); color:var(--deep); }

/* ---------- results ---------- */
/* min-width:0 so the two-up item grid inside can shrink below its content —
   without it a long product name widens the whole column past its track. */
.cat-results{ min-width:0; }
.result-bar{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:6px 16px;
  padding-bottom:14px; border-bottom:1px solid var(--hair-strong);
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label-lg); text-transform:uppercase; color:var(--mist);
}
.result-bar .ct{ color:var(--deep); }
.az-group{ margin-top:var(--flow-md); }
.az-group[hidden]{ display:none; }
.az-letter{
  font-family:var(--font-display); font-weight:var(--fw-black); font-size:1.4rem; color:var(--ink);
  letter-spacing:var(--track-tight); padding-bottom:9px; margin-bottom:4px;
  border-bottom:var(--bw-rule) solid var(--hair-strong);
  display:flex; align-items:center; gap:var(--sp-3);
}
.az-letter::after{
  content:""; width:26px; height:5px; border-radius:3px;
  background:var(--tri);
}
.az-items{ display:grid; grid-template-columns:1fr; gap:0 var(--flow-xs); }
@media(min-width:700px){ .az-items{ grid-template-columns:1fr 1fr; } }
/* the li is a grid so the button fills the row: side-by-side entries of unequal
   length still get one hover surface that reaches the shared rule below */
.az-items li{ display:grid; border-bottom:1px solid var(--hair); }
.az-items li[hidden]{ display:none; }
.az-item{
  position:relative; text-align:left;
  border:0; background:transparent; padding:15px 12px 14px;
  margin-inline:-12px; width:calc(100% + 24px);
  border-radius:var(--r-12);
  transition:background var(--dur-fast);
}
.az-item b{
  display:block; font-family:var(--font-display); font-size:var(--text-lg); font-weight:var(--fw-bold);
  color:var(--ink); letter-spacing:var(--track-snug); transition:color var(--dur-fast);
}
.az-item span{ display:block; font-size:var(--text-sm); color:var(--slate); margin-top:4px; line-height:var(--lh-normal); }
/* a named affordance, in flow: "chevron only" left it unclear that a row opened
   anything, and a floating chevron crowds the copy in the two-column layout */
.az-item::after{
  content:"More info \2192"; display:inline-block; margin-top:9px;
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label-lg);
  text-transform:uppercase; color:var(--mist); font-weight:var(--fw-medium);
  transition:color var(--dur-fast), transform var(--dur-fast);
}
.az-item:hover{ background:var(--tint-2); }
.az-item:hover b{ color:var(--deep); }
.az-item:hover::after{ color:var(--blue); transform:translateX(3px); }
.empty-note{
  padding:44px 0; text-align:center;
  font-family:var(--font-mono); font-size:var(--label-lg); letter-spacing:var(--track-label); text-transform:uppercase; color:var(--mist);
}
.empty-note a{ color:var(--deep); }

/* ---------- phones: finding your way back up a 63-item list ----------
   On a phone the whole rail (search, industries, A-Z jump grid) scrolls away
   under the list, so each letter heading pins under the fixed header while
   its group is on screen, and a small pill offers the way back to the jump
   grid once it has gone. Both exist only below the two-column breakpoint;
   on desktop the rail is sticky and neither is needed. */
@media(max-width:999px){
  .az-letter{
    position:sticky; top:var(--head-h); z-index:var(--z-raised);
    background:var(--paper); padding-top:10px;
  }
  .az-return{
    position:fixed; right:var(--sp-4); bottom:var(--sp-5); z-index:var(--z-head);
    display:inline-flex; align-items:center; gap:6px; min-height:var(--tap); padding:10px 16px;
    border-radius:var(--pill); background:var(--ink); color:var(--on-ink-text);
    font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label); text-transform:uppercase;
    text-decoration:none; box-shadow:var(--shadow-lg);
    opacity:0; transform:translateY(12px); pointer-events:none;
    transition:opacity var(--dur-base) ease, transform var(--dur-base) var(--ease-out);
  }
  .az-return.is-on{ opacity:1; transform:none; pointer-events:auto; }
  .az-return:focus-visible{ outline:none; box-shadow:var(--shadow-lg), var(--focus-ring); }
}
@media(min-width:1000px){ .az-return{ display:none; } }
@media(prefers-reduced-motion:reduce){ .az-return{ transition:none; } }

/* the contact page's direct lines are the page's primary actions: give the
   phone, email and LinkedIn links a full thumb's height without moving the
   text, so the row still reads as a line, not a button */
.kv .v a{ display:inline-block; padding-block:10px; margin-block:-10px; }

/* ---------- small screens: the rail becomes a header strip ---------- */
@media(max-width:999px){
  .cat-side-inner{ gap:var(--sp-3); }
  .side-label{ margin-top:4px; }
  /* the tree flattens: industries flow as pills and the open branch breaks to a
     line of its own. display:contents dissolves the branch <li> so its row and
     its sub-list wrap as siblings; the chevron goes, and tapping the industry
     both filters and opens it. */
  .ftree{ flex-direction:row; flex-wrap:wrap; gap:var(--sp-2); }
  .ftree-node--branch{ display:contents; }
  .ftree > li, .ftree-row{ flex:0 0 auto; }
  .ftree-tog{ display:none; }
  /* the spine survives the flattening: an indent and a rule keep the open
     sub-list reading as children rather than six more industries */
  .ftree-sub{
    flex:1 0 100%;
    flex-direction:row; flex-wrap:wrap; gap:var(--sp-2);
    margin:0; padding:var(--sp-2) 0 var(--sp-2) var(--sp-3);
    border-left:var(--bw-rule) solid var(--hair-strong);
  }
  .fbtn{
    width:auto; min-height:var(--tap); padding:10px 16px 10px 13px;
    border-color:var(--hair-strong); border-radius:var(--pill); background:var(--paper);
    box-shadow:var(--shadow-sm); font-size:var(--text-sm);
  }
  .fbtn .n{ margin-left:4px; }
  .fbtn.is-empty{ display:none; }
  /* after .fbtn, not before it — same specificity, so source order decides */
  .fbtn--sub{
    padding:9px 15px 9px 12px; font-size:var(--text-xs);
    background:var(--tint-2); border-color:transparent; box-shadow:none;
  }
  .fbtn--sub[aria-pressed="true"]{ background:var(--ink); border-color:var(--ink); }
  /* auto-fill, not a fixed 9: the touch rules below force each cell to 44px,
     and nine of those are wider than a phone — which pushed the whole grid
     column past the viewport and gave the page a horizontal scrollbar. */
  .az-jump{ grid-template-columns:repeat(auto-fill, minmax(44px, 1fr)); }
  .az-jump a{ min-height:40px; }
}

/* ============================================================
   PRODUCT DETAIL — side panel (desktop) / bottom drawer (mobile)
   ============================================================ */
.pdrawer{ position:fixed; inset:0; z-index:var(--z-drawer); }
.pdrawer[hidden]{ display:none; }
.pdrawer-scrim{
  position:absolute; inset:0; width:100%; border:0; padding:0; margin:0;
  background:var(--scrim);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  opacity:0; transition:opacity var(--dur-slower) ease;
}
.pdrawer-panel{
  position:absolute; top:0; right:0; bottom:0;
  width:min(468px, 92vw);
  display:flex; flex-direction:column;
  background:var(--paper); border-left:1px solid var(--hair);
  box-shadow:var(--shadow-lg);
  transform:translateX(102%);
  transition:transform var(--dur-panel) var(--ease-out);
  overflow-y:auto; overscroll-behavior:contain;
}
body.pd-open .pdrawer-scrim{ opacity:1; }
body.pd-open .pdrawer-panel{ transform:none; }
body.pd-open{ overflow:hidden; }

.pdrawer-grab{ display:none; }
.pdrawer-head{
  position:sticky; top:0; z-index:var(--z-raised);
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  padding:16px var(--flow-sm);
  background:var(--paper); border-bottom:1px solid var(--hair);
}
.pd-cat{
  display:inline-flex; align-items:center; gap:9px;
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label-lg); text-transform:uppercase; color:var(--deep);
}
.pdrawer-close{
  flex:none; width:44px; height:44px; margin-right:-8px;
  border:1px solid var(--hair); border-radius:11px; background:var(--paper);
  color:var(--ink); font-size:var(--text-3xl); line-height:1;
  display:inline-flex; align-items:center; justify-content:center;
  transition:border-color var(--dur-quick), background var(--dur-quick);
}
.pdrawer-close:hover{ border-color:var(--blue); background:var(--tint-2); }

.pdrawer-body{ flex:1; padding:var(--flow-sm) var(--flow-sm) 8px; }
.pdrawer-body h2{ font-size:var(--display-sm); letter-spacing:var(--track-tighter); }
.pd-sum{ margin-top:var(--sp-3); font-size:var(--text-md); line-height:var(--lh-relaxed); color:var(--slate); }
/* the full description off the product sheet: body copy under the one-line lede */
.pd-desc{ margin-top:var(--sp-4); font-size:var(--text-sm); line-height:var(--lh-relaxed); color:var(--slate); text-wrap:pretty; }
.pd-desc[hidden]{ display:none; }
.pd-block{ margin-top:var(--sp-6); padding-top:var(--sp-5); border-top:1px solid var(--hair); }
.pd-block[hidden]{ display:none; }
.pd-label{
  font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-xl); text-transform:uppercase;
  color:var(--mist); margin-bottom:10px;
}
.pd-tax{
  display:inline-flex; align-items:center; padding:7px 14px; border-radius:var(--pill);
  background:var(--tint); border:1px solid var(--hair-strong);
  font-family:var(--font-display); font-weight:var(--fw-semi); font-size:var(--text-sm); color:var(--ink);
}
.pd-list{ display:flex; flex-direction:column; gap:9px; }
.pd-list li{
  position:relative; padding-left:20px; font-size:var(--text-md); line-height:var(--lh-normal); color:var(--slate);
}
.pd-list li::before{
  content:""; position:absolute; left:0; top:8px;
  width:8px; height:8px; border-radius:2.5px; background:var(--logo-t);
}
.pd-list li:nth-child(3n+1)::before{ background:var(--logo-y); }
.pd-list li:nth-child(3n)::before{ background:var(--logo-g); }
.pd-chips{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.pd-chip{
  display:inline-flex; align-items:center; min-height:38px; padding:8px 15px;
  border:1px solid var(--hair-strong); border-radius:var(--pill);
  background:var(--paper); color:var(--ink);
  font-size:var(--text-xs); font-weight:var(--fw-medium);
  transition:border-color var(--dur-quick), color var(--dur-quick), background var(--dur-quick);
}
a.pd-chip:hover{ border-color:var(--blue); color:var(--deep); background:var(--tint-2); }
.pd-chips--plain .pd-chip{
  background:var(--tint-2); color:var(--slate);
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-wide);
}
.pd-fine{
  margin-top:var(--sp-6); padding-top:var(--sp-5); border-top:1px solid var(--hair);
  font-size:var(--text-xs); line-height:var(--lh-relaxed); color:var(--mist);
}
.pd-fine a{ color:var(--deep); font-weight:var(--fw-semi); }

.pdrawer-foot{
  position:sticky; bottom:0; z-index:var(--z-raised);
  display:flex; flex-wrap:wrap; gap:10px;
  padding:16px var(--flow-sm) calc(16px + env(safe-area-inset-bottom, 0px));
  background:var(--paper); border-top:1px solid var(--hair);
}
.pdrawer-foot .btn{ flex:1 1 auto; }

/* ---- phones: same panel, entering from the bottom ---- */
@media(max-width:719px){
  .pdrawer-panel{
    top:auto; left:0; right:0; bottom:0;
    width:auto; max-height:88vh;
    border-left:0; border-top:1px solid var(--hair);
    border-radius:var(--r-20) var(--r-20) 0 0;
    transform:translateY(102%);
  }
  .pdrawer-grab{
    display:block; position:sticky; top:0; z-index:3;
    width:44px; height:4px; margin:10px auto 0; border-radius:3px;
    background:var(--hair-strong); flex:none;
  }
  .pdrawer-head{ top:14px; padding-top:10px; }
  .pdrawer-foot .btn{ flex:1 1 100%; }
}

/* ============================================================
   JOB ROWS (careers)
   ============================================================ */
.jobs{ margin-top:var(--flow-lg); display:grid; gap:var(--flow-2xs); }
.job{
  border:1px solid var(--hair); border-radius:var(--r-16); background:var(--paper);
  box-shadow:var(--shadow-sm); padding:var(--flow-sm);
  display:grid; grid-template-columns:1fr; gap:var(--sp-3); align-items:center;
  transition:border-color var(--dur-base), transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base);
  position:relative; overflow:hidden;
}
.job::before{ content:""; position:absolute; left:0; top:0; bottom:0; width:4px; }
.job:nth-child(3n+1)::before{ background:var(--logo-y); }
.job:nth-child(3n+2)::before{ background:var(--logo-t); }
.job:nth-child(3n)::before{ background:var(--fam-g); }
.job:hover{ border-color:var(--hair-strong); transform:translateY(-3px); box-shadow:var(--shadow-md); }
@media(min-width:840px){ .job{ grid-template-columns:minmax(0,5fr) minmax(0,3fr) minmax(0,3fr) auto; gap:var(--sp-5); } }
.job h3{ font-size:1.12rem; letter-spacing:var(--track-snug); }
.job .jmeta{ font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label); text-transform:uppercase; color:var(--mist); }
.job .jmeta b{ color:var(--slate); font-weight:var(--fw-medium); }

/* ============================================================
   PHOTO REEL (careers) - "life here"

   The one full-bleed moment on a sub-page: real staff photographs running
   right to left, edge to edge, with no captions. The page states the culture
   in words directly above; this is the evidence, and it reads faster with
   nothing to parse.

   Built on the same two-part trick as .bticker - identical tracks in one rail,
   translated by exactly one track width so the loop has no seam. It takes
   THREE tracks, not the ticker's two: one track is only ~2.3k wide, and with
   two the rail runs out of content on a display wider than that. Three keeps
   two track-widths of cover behind the travel at any viewport we will meet.

   Spacing is margin-right on the item, never gap on the track: gap does not
   apply between two adjacent tracks, so the seam would close up to nothing
   once per cycle and give the loop away.

   The sources are 400x305 originals with nothing larger available, so the item
   width is capped below that - do not raise it past 360px.
   ============================================================ */
.life{ background:var(--ground); border-top:1px solid var(--hair); }
.preel{
  position:relative; overflow:hidden; margin-top:var(--flow-lg);
  /* fade both ends so photographs enter and leave instead of popping at a hard edge */
  mask-image:linear-gradient(to right, transparent, #000 4%, #000 96%, transparent);
  -webkit-mask-image:linear-gradient(to right, transparent, #000 4%, #000 96%, transparent);
}
.preel-rail{
  display:flex; width:max-content;
  animation:preel 44s linear infinite;
  will-change:transform;
}
/* calc(-100%/3), not -33.3333% - the rounded figure leaves a sub-pixel
   step at every loop restart, and on a 6.8k rail that is visible as a tick. */
@keyframes preel{ from{ transform:translateX(0); } to{ transform:translateX(calc(-100% / 3)); } }
/* hold still for anyone who wants to look at one photograph */
.preel:hover .preel-rail,
.preel:focus-within .preel-rail{ animation-play-state:paused; }
.preel-track{ display:flex; align-items:center; flex:none; margin:0; padding:0; list-style:none; }
.preel-item{
  position:relative; flex:none; margin-right:var(--flow-2xs);
  width:clamp(230px, 26vw, 360px);
  border:1px solid var(--hair); border-radius:var(--r-16); overflow:hidden;
  background:var(--paper); box-shadow:var(--shadow-sm);
}
.preel-item img{ width:100%; aspect-ratio:400/305; object-fit:cover; transition:transform .5s var(--ease-out); }
.preel-item:hover img{ transform:scale(1.04); }
/* a logo colour under each frame - the reel's only ornament, and the thing
   that gives the run a rhythm now the captions are gone. Six photographs over
   a three-colour cycle, so the sequence repeats cleanly across the seam. */
.preel-item::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:var(--bw-accent); z-index:1;
}
.preel-item:nth-child(3n+1)::after{ background:var(--logo-y); }
.preel-item:nth-child(3n+2)::after{ background:var(--logo-t); }
.preel-item:nth-child(3n)::after{   background:var(--fam-g); }
.preel-foot{ margin-top:var(--flow-md); }

@media(prefers-reduced-motion:reduce){
  /* no travel: drop the duplicates and let the row be scrolled by hand. The
     gutter pad replaces the mask fade so the first frame still starts on the
     page's own margin rather than flush to the viewport edge. */
  .preel-rail{ animation:none; padding-inline:var(--gutter); }
  .preel{ overflow-x:auto; mask-image:none; -webkit-mask-image:none; }
  .preel-track[aria-hidden="true"]{ display:none; }
  .preel-item img, .preel-item:hover img{ transition:none; transform:none; }
}

/* ============================================================
   BRANCH CARDS
   ============================================================ */
.branches{ display:grid; grid-template-columns:1fr; gap:var(--flow-2xs); margin-top:var(--flow-lg); }
@media(min-width:660px){ .branches{ grid-template-columns:1fr 1fr; } }
@media(min-width:1040px){ .branches{ grid-template-columns:repeat(3,1fr); } }
.branch{
  position:relative; overflow:hidden;
  border:1px solid var(--hair); border-radius:var(--r-12); background:var(--paper);
  box-shadow:var(--shadow-sm); padding:12px var(--sp-5) 12px 18px;
  transition:border-color var(--dur-base), transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base);
}
/* The accent runs down the left edge, not across the top. On the tall cards
   this used to be, a top bar read as a header rule; on a 46px row thirteen of
   them stack into a ladder of stripes. Down the side it reads as the row
   marker it now is - the same treatment the footer nav links take. */
.branch::before{ content:""; position:absolute; top:0; bottom:0; left:0; width:var(--bw-accent); }
.branch:nth-child(3n+1)::before{ background:var(--logo-y); }
.branch:nth-child(3n+2)::before{ background:var(--logo-t); }
.branch:nth-child(3n)::before{ background:var(--logo-g); }
.branch .region{ font-family:var(--font-mono); font-size:var(--label-sm); letter-spacing:var(--track-label-xl); text-transform:uppercase; color:var(--mist); }
.branch h3{ font-size:1.2rem; margin:9px 0 10px; letter-spacing:var(--track-tight); }
.branch address{ font-style:normal; font-size:var(--text-md); color:var(--slate); line-height:var(--lh-relaxed); }
.branch .bcontact{ margin-top:14px; padding-top:14px; border-top:1px solid var(--hair); display:flex; flex-direction:column; gap:6px; }
.branch .bcontact a{ font-size:var(--text-sm); color:var(--deep); font-weight:var(--fw-medium); min-height:32px; display:inline-flex; align-items:center; }
.branch .bcontact a:hover{ color:var(--blue); }
.branch--hq{ background:var(--tint-2); }
/* .branch.branch--hq, not .branch--hq: the nth-child cycle three lines up is
   (0,2,1) and a bare .branch--hq::before is (0,1,1), so the head office's
   accent bar lost to it and painted yellow. Same re-assert idiom as the
   pressed filter pill. */
.branch.branch--hq::before{ background:var(--blue); }
.branch--hq .region{ color:var(--deep); }

/* ---- every branch is a native <details> accordion, at every width ----
   Thirteen expanded cards were 4,819px of an 8,481px mobile page — 57% of the
   scroll for a directory most people use to find ONE branch. Collapsed rows cut
   the section to roughly 1,100px.

   <details>/<summary> rather than a button plus JS: it carries the
   expanded/collapsed state to assistive tech, handles Enter and Space, and keeps
   working with scripting off — which matters because on a phone the accordion is
   the whole experience, not an enhancement of it. The head office ships with
   `open` so the pattern is self-evident and the branch the copy points people to
   ("write to the head office if you are not sure") is already showing. */
.branch > summary{
  position:relative;
  display:flex; flex-direction:column; justify-content:center;
  min-height:var(--tap); padding-right:26px;
  cursor:pointer; list-style:none;
  -webkit-tap-highlight-color:transparent;
}
.branch > summary::-webkit-details-marker{ display:none; }
.branch > summary::marker{ content:""; }
/* Region over name, stacked. Tried it on one line with the state pushed to the
   right edge; it read as a table rather than a directory, and the state — the
   thing you scan by — ended up the furthest from the name it belongs to.
   Stacked keeps them together and still fits a compact row. */
.branch > summary .region{ display:block; }   /* was a <p>; <summary> can't hold one */
.branch > summary h3{ margin:3px 0 0; font-size:1.04rem; }
/* chevron, pointing down closed and up open */
.branch > summary::after{
  content:""; position:absolute; right:2px; top:50%;
  width:7px; height:7px; margin-top:-6px;
  border-right:2px solid var(--mist); border-bottom:2px solid var(--mist);
  transform:rotate(45deg);
  transition:transform var(--dur-base) var(--ease-out);
}
.branch[open] > summary::after{ transform:rotate(-135deg); margin-top:-2px; }
.branch[open] > .bbody{ padding-top:12px; }
/* the hover lift is a pointer affordance; on a tapped list it just wobbles */
@media(max-width:999px){
  .branch:hover{ transform:none; box-shadow:var(--shadow-sm); border-color:var(--hair); }
}

/* ---------- directory: [ accordion list | map ] ----------
   The state filters that used to live here - first a 264px sticky rail, then a
   pill bar across the top - are gone. Thirteen one-line rows are quicker to
   scan than they are to filter, and the map is the thing that wanted the room. */
.dir-layout{
  display:grid; grid-template-columns:minmax(0,1fr);
  gap:var(--flow-md); margin-top:var(--flow-md);
}
@media(min-width:1000px){
  .dir-layout{ gap:var(--flow-xl); align-items:start; }
  /* Only pair the columns when a map is actually there — the thirteen-row
     accordion left, map right. The markup keeps the map first so the phone
     stack still leads with it; order swaps the two only here. If a build omits
     the pane, :has() never matches and the directory falls back to the
     full-width list it was before the map existed. A browser without :has()
     lands on the same fallback. */
  .dir-layout:has(.dir-map){ grid-template-columns:minmax(0,1.05fr) minmax(0,1fr); }
  .dir-layout:has(.dir-map) .dir-results{ order:1; }
  .dir-layout:has(.dir-map) .dir-map{ order:2; }
  .dir-map{ position:sticky; top:calc(var(--head-h) + 20px); }
}
/* The frame does the styling an embed will not let us do to the tiles: a
   hairline in the site's own navy, the 16px radius everything else here uses,
   and a 1px inset ring so the map reads as inset into the page rather than
   pasted on top of it. --map-tone is the one dial for the tiles themselves -
   see .map-embed. */
.map-frame{
  position:relative; overflow:hidden; isolation:isolate;
  aspect-ratio:4 / 3;
  border:1px solid var(--hair-strong); border-radius:var(--r-16);
  background:var(--land); box-shadow:var(--shadow-sm);
}
/* the ring rides above the iframe; pointer-events:none or it eats every drag */
.map-frame::after{
  content:""; position:absolute; inset:0; z-index:2; pointer-events:none;
  border-radius:inherit;
  box-shadow:inset 0 0 0 1px rgba(var(--ch-ink),.06);
}
@media(min-width:1000px){
  /* beside a thirteen-row list the pane wants height, not a ratio; capped so a
     short laptop still sees the whole frame under the fixed header */
  .map-frame{ aspect-ratio:auto; height:min(66svh, 620px); }
}
/* Google's default tiles are a warm green-and-beige that fights a page built
   on #EDF3F8 land and a navy coastline. Pulling the saturation back and easing
   the whole thing a shade lighter lands it close to the atlas on the homepage,
   without touching legibility: roads, labels and the Google attribution all
   stay exactly as readable, which is the line that matters - Google's terms do
   not allow the logo or the attribution to be obscured or removed, and this
   obscures neither. Dial or delete --map-tone to taste; `none` is honest too.

   The tiles inside a My Maps embed are better styled at the source: My Maps'
   own base-map picker has pale variants that suit this palette, and pin colour
   is set there too. This is only what an embed can be styled from outside. */
:root{ --map-tone:saturate(.62) contrast(1.02) brightness(1.03); --map-header-crop:60px; }
.map-embed{
  position:absolute; inset:0; width:100%; height:100%; border:0; display:block;
  filter:var(--map-tone);
}
/* A My Maps embed ships a header bar carrying the map's title, the OWNER'S
   NAME AND GOOGLE PROFILE PHOTO, a share button and a "made with Google My
   Maps" line. There is no setting or URL parameter that removes it - &ehbc=
   only recolours it - so the only way off a company contact page is to crop:
   grow the iframe by the bar's height and pull it up by the same amount, so
   the bar lands outside .map-frame's overflow:hidden.

   Because the frame grows at the TOP only, the iframe's bottom edge still
   lines up with the frame's, which is where Google's "Google My Maps"
   attribution and Terms link sit. Those stay visible - the bar being cropped
   is Google's chrome, not its attribution.

   60px matches what ceyenar's current production site uses for the same crop
   on the same embed. If a Google change ever moves the bar, this is the one
   number to adjust. */
.dir-map.is-mymaps .map-embed{
  inset:auto; top:calc(-1 * var(--map-header-crop)); left:0;
  height:calc(100% + var(--map-header-crop));
}
/* note on the left, the reset control on the right, baselines aligned */
.map-bar{
  display:flex; align-items:baseline; justify-content:space-between;
  gap:var(--sp-4); margin-top:var(--sp-3);
}
.map-note{
  margin:0;
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label);
  text-transform:uppercase; color:var(--mist);
}
.map-note b{ color:var(--ink); font-weight:var(--fw-medium); }
/* a quiet text control, not a button-looking button: it sits under a map, and
   the accordion beside it is the loud thing on this half of the section */
.map-reset{
  flex:none; appearance:none; background:none; border:0; padding:0;
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label);
  text-transform:uppercase; color:var(--deep); font-weight:var(--fw-medium);
  cursor:pointer; white-space:nowrap; padding-bottom:3px;
  border-bottom:1px solid rgba(var(--ch-blue),.35);
  transition:color var(--dur-quick) var(--ease-out), border-color var(--dur-quick) var(--ease-out);
}
.map-reset:hover{ color:var(--blue); border-bottom-color:var(--blue); }
/* the two map actions, right of the note */
.map-acts{ display:flex; align-items:baseline; gap:var(--sp-4); flex:none; }
.map-dir{
  display:inline-flex; align-items:baseline; gap:6px; padding-bottom:3px;
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label);
  text-transform:uppercase; color:var(--deep); font-weight:var(--fw-medium);
  white-space:nowrap;
  border-bottom:1px solid rgba(var(--ch-blue),.35);
  transition:color var(--dur-quick) var(--ease-out), border-color var(--dur-quick) var(--ease-out);
}
/* a class that sets display outranks the UA's [hidden]{display:none}, so the
   hidden attribute would do nothing here without this line */
.map-dir[hidden]{ display:none; }
.map-dir:hover{ color:var(--blue); border-bottom-color:var(--blue); }
.map-dir .arr{ transition:transform var(--dur-quick) ease; }
.map-dir:hover .arr{ transform:translateX(3px); }
/* anyone who has asked for more contrast did not ask for a prettier map */
@media(prefers-contrast:more){ :root{ --map-tone:none; } }
@media(max-width:639px){
  /* the note plus two actions stop fitting on one line; stack rather than
     shrink type that is already at label size */
  .map-bar{ flex-direction:column; align-items:flex-start; gap:var(--sp-2); }
  .map-acts{ gap:var(--sp-4); }
}

.dir-results{ min-width:0; }
/* one column of compact rows: the list is half the width now, each row drives
   the map, and thirteen of them should read as a directory rather than a stack
   of cards - so the gap tightens to match the row height. */
.dir-results .branches{ grid-template-columns:1fr; gap:var(--sp-2); margin-top:0; }
/* the row whose location the map is showing */
.branch.is-shown{ border-color:var(--blue); }
.bdir{
  display:inline-flex; align-items:center; gap:7px; min-height:32px;
  font-size:var(--text-sm); font-weight:var(--fw-medium); color:var(--deep);
}
.bdir:hover{ color:var(--blue); }
.bdir .arr{ transition:transform var(--dur-quick) ease; }
.bdir:hover .arr{ transform:translateX(3px); }

/* ============================================================
   CTA BAND - the one dark moment
   ============================================================ */
.cta{ background:var(--paper); border-top:1px solid var(--hair); }
.cta-band{
  position:relative; overflow:hidden;
  border-radius:var(--r-20);
  background:linear-gradient(180deg, var(--on-ink-top), var(--ink) 70%);
  padding:var(--flow-2xl) var(--flow-2xl);
  text-align:center;
  box-shadow:var(--shadow-lg);
}
.cta-band::before{
  content:""; position:absolute; top:0; left:0; right:0; height:var(--bw-band); z-index:var(--z-raised);
  background:var(--tri);
}
.cta-band::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:
    linear-gradient(var(--on-ink-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--on-ink-grid) 1px, transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image:radial-gradient(90% 90% at 50% 0%, #000 20%, transparent 75%);
  mask-image:radial-gradient(90% 90% at 50% 0%, #000 20%, transparent 75%);
}
.cta-band > *{ position:relative; z-index:1; }
.cta-band .eyebrow{ justify-content:center; color:var(--on-ink-accent); }
.cta-band h2{
  color:var(--on-ink-text);
  font-size:var(--display-md);
  margin:14px auto 14px; max-width:22ch; text-wrap:balance;
}
.cta-band .sec-sub{
  color:var(--on-ink-muted); margin:0 auto 30px; max-width:56ch;
  font-size:var(--text-sub); line-height:var(--lh-relaxed);
}
.cta-band .ctas{ display:flex; flex-wrap:wrap; justify-content:center; gap:var(--sp-3); }
/* align-items:center is load-bearing: the links inside .meta are 44px-tall
   inline-flex hit areas, so without it the plain <span> items stretch and their
   text sits a line above the links — the row reads as a broken staircase. */
.cta-band .meta{
  margin-top:26px; padding-top:8px; border-top:1px solid var(--on-ink-rule);
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:0 28px;
  font-family:var(--font-mono); font-size:var(--label-md); letter-spacing:var(--track-label); text-transform:uppercase; color:var(--on-ink-faint);
}
.cta-band .meta > *{ display:inline-flex; align-items:center; min-height:var(--tap); }
.cta-band .meta a{ color:var(--on-ink-link); }
.cta-band .meta a:hover{ color:var(--on-ink-text); }

/* ---- the G close: a photograph does the arguing ----
   Cinematic bleed translated onto the atlas system — navy scrim, Hanken,
   tricolour rule kept. The ask sits low-left where the scrim is deepest.
   Photos are below the fold on every page, so they lazy-load and cost the
   first paint nothing. The survey grid stays off: the photo is the texture. */
.cta-band--photo{
  text-align:left;
  min-height:clamp(340px, 32vw, 460px);
  display:flex; flex-direction:column; align-items:flex-start; justify-content:flex-end;
}
.cta-band--photo::after{ content:none; }
.cta-photo, .cta-scrim{ position:absolute; inset:0; z-index:0; }
.cta-photo{ width:100%; height:100%; object-fit:cover; }
.cta-scrim{
  background:
    linear-gradient(100deg, rgba(var(--ch-ink),.88) 0%, rgba(var(--ch-ink),.5) 48%, rgba(var(--ch-ink),.08) 82%),
    linear-gradient(to top, rgba(var(--ch-ink),.92) 0%, rgba(var(--ch-ink),.55) 42%, rgba(var(--ch-ink),.16) 78%, rgba(var(--ch-ink),.36) 100%);
}
.cta-band--photo .eyebrow{ justify-content:flex-start; }
.cta-band--photo h2{ margin:14px 0; max-width:19ch; }
.cta-band--photo .sec-sub{ margin:0 0 30px; max-width:46ch; }
.cta-band--photo .ctas{ justify-content:flex-start; }
.cta-band--photo .meta{ justify-content:flex-start; align-self:stretch; }
/* stacked, the copy crosses the busy centre of the photograph — the diagonal
   scrim stops carrying it, so a near-uniform one takes over */
@media(max-width:640px){
  .cta-scrim{
    background:
      linear-gradient(to top, rgba(var(--ch-ink),.94) 0%, rgba(var(--ch-ink),.84) 52%, rgba(var(--ch-ink),.62) 84%, rgba(var(--ch-ink),.54) 100%);
  }
}

/* ============================================================
   FOOTER - the index drawer
   The dark slab that ends every page. Contact, the enquiry CTA, the
   locator, the standards and the legal line all sit permanently open;
   the doormat nav reads as lines in a printed atlas index, each with a
   dot leader running to its link count. No JavaScript, no disclosure -
   at thirteen links the evidence says stack and expand rather than
   collapse, so every link is visible at every width.
   ============================================================ */
.site-foot{
  /* ---- surface ladder for the dark slab ----
     Hand-picked navies, not white-alpha overlays - rgba(255,255,255,.06)
     resolves to #1C2F44, which drifts grey and kills the navy. L1 is the
     system's own --on-ink-top: a 1.20:1 step off --ink, inside the
     1.08-1.5 window that reads as elevation without needing a shadow.
     The well exists only for the seam riser. */
  --foot-l1:var(--on-ink-top);
  --foot-well:#0A1B2D;
  /* the atlas signature stood on end, spining each link group */
  --foot-tri-v:linear-gradient(180deg, var(--logo-y) 0 33.4%, var(--logo-t) 33.4% 66.7%, var(--logo-g) 66.7% 100%);
  --foot-hair:rgba(var(--ch-white),.08);
  --foot-hair-strong:rgba(var(--ch-white),.16);
  --foot-hover:rgba(var(--ch-white),.05);
  --foot-underline:rgba(var(--ch-sky),.26);

  position:relative;
  isolation:isolate;
  /* THE SEAM. Never gradient *between* light and dark - it passes through
     muddy mid-values and bands on 8-bit panels. The riser lives inside the
     dark instead, so the boundary itself is the darkest point and the slab
     appears to deepen upward as it meets the light page. */
  background:linear-gradient(180deg, var(--foot-well) 0, var(--ink) 132px);
  background-color:var(--ink);
  color:var(--on-ink-muted);
  font-family:var(--font-body);
}

/* The site's cube lattice, same motif and same 56x64 pitch as the index
   hero (.hero::before). --tess-tile is stroked in ink navy and would be
   invisible on this ground, so the tile is used as a MASK and the paint
   underneath carries the colour - one pattern for the whole site, no
   second texture introduced on ink. The edge fade lives in the painted
   gradient rather than a second mask layer, so there is only ever one
   mask to compose. */
.site-foot::after{
  content:"";
  position:absolute; inset:0; z-index:0; pointer-events:none;
  background:radial-gradient(120% 90% at 50% 0%,
    rgba(var(--ch-sky),.95) 18%, rgba(var(--ch-sky),0) 78%);
  -webkit-mask-image:var(--tess-tile);
  mask-image:var(--tess-tile);
  -webkit-mask-size:56px 64px;
  mask-size:56px 64px;
  -webkit-mask-repeat:repeat;
  mask-repeat:repeat;
  opacity:.055;
}

/* ---- the seam mark ---------------------------------------------------
   A full-bleed 1px rule opening the dark, with the tricolour signature cut
   into it as a short gutter-aligned segment. A full-width tri band would
   shout; 96-120px at the grid's first column reads as deliberate. */
.foot-seam{
  position:absolute; top:0; left:0; right:0; z-index:2;
  height:var(--bw-edge);
  pointer-events:none;
  background:linear-gradient(var(--on-ink-rule), var(--on-ink-rule)) 0 0 / 100% 1px no-repeat;
}
.foot-seam-mark{
  display:block;
  width:clamp(96px, 28vw, 120px);
  height:100%;
  /* Align to the CONTENT column, not the viewport. The seam is full-bleed
     (left:0;right:0) but .foot-inner is a centred max-width column, so a plain
     margin-left:var(--gutter) parks the mark at the window edge while the logo
     below it sits up to (100vw - --maxw)/2 further in — they only coincide
     below ~1352px. max() keeps the gutter on narrow screens and tracks the
     centred column above it. */
  margin-left:max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter)));
  background:var(--tri);
  border-radius:0 0 3px 3px;
}

/* ---- shell ---------------------------------------------------------- */
.foot-inner{
  position:relative; z-index:1;
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gutter);
  padding-block:var(--flow-xl) calc(var(--flow-md) + env(safe-area-inset-bottom, 0px));
}
.foot-main{ display:grid; gap:var(--flow-md); }

.foot-sr{
  position:absolute;
  width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip-path:inset(50%);
  white-space:nowrap; border:0;
}

/* ---- brand ---------------------------------------------------------- */
.foot-brand{
  display:inline-flex; align-items:center; flex-wrap:wrap;
  gap:var(--sp-3);
  min-height:var(--tap);
  text-decoration:none;
}
.foot-logo{ width:34px; height:29px; flex:none; }
.foot-word{
  font-family:var(--font-display);
  font-size:var(--text-xl);
  font-weight:var(--fw-bold);
  letter-spacing:var(--track-snug);
  color:var(--on-ink-text);
}
.foot-est{
  padding:4px 8px;
  border:var(--bw-hair) solid var(--foot-hair-strong);
  border-radius:var(--pill);
  font-family:var(--font-mono);
  font-size:var(--label-xs);
  font-weight:var(--fw-medium);
  letter-spacing:var(--track-label-lg);
  text-transform:uppercase;
  color:var(--on-ink-muted);
}
.foot-blurb{
  margin:var(--sp-4) 0 0;
  max-width:40ch;
  font-size:var(--text-sm);
  /* light-on-dark gains apparent weight and loses counter space:
     hold 400, add +.01em tracking and +.03 leading over the light value */
  font-weight:var(--fw-regular);
  letter-spacing:.01em;
  line-height:1.68;
  color:var(--on-ink-muted);
}

/* ---- contact deck ----------------------------------------------------
   NOTE the `padding` shorthand: this is a <section>, and styles.css's
   `section{ padding-block:var(--space-section); }` would otherwise add
   64-110px of dead space to each edge. The shorthand resets it. */
.foot-deck{
  margin-top:var(--flow-sm);
  padding:var(--sp-4) var(--sp-4) var(--sp-2);
  background:var(--foot-l1);
  border:var(--bw-hair) solid rgba(var(--ch-white),.10);
  border-radius:var(--r-16);
}
.foot-kicker{
  margin:0;
  font-family:var(--font-mono);
  font-size:var(--label-md);
  font-weight:var(--fw-medium);
  letter-spacing:var(--track-label-lg);
  text-transform:uppercase;
  color:var(--on-ink-text);
}
.foot-rows{ list-style:none; margin:var(--sp-3) 0 0; padding:0; }
.foot-rows li + li{ border-top:var(--bw-hair) solid var(--foot-hair); }
.foot-row{
  display:flex; align-items:center; gap:var(--sp-3);
  min-height:56px;
  padding:var(--sp-2) var(--sp-1);
  border-radius:var(--r-8);
  text-decoration:none;
  transition:background var(--dur-quick) var(--ease-out);
}
/* raise the surface - never brightness() or a glow, both bloom on dark */
.foot-row:hover{ background:var(--foot-hover); }
.foot-row-ico{
  display:grid; place-items:center;
  width:24px; flex:none;
  color:var(--on-ink-accent);
}
.foot-row-ico svg{ width:19px; height:19px; }
.foot-row-txt{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.foot-row-k,
.foot-reg-k{
  font-family:var(--font-mono);
  font-size:var(--label-xs);
  letter-spacing:var(--track-label-lg);
  text-transform:uppercase;
  color:var(--on-ink-faint);
}
.foot-row-v{
  font-size:var(--text-lg);
  font-weight:var(--fw-medium);
  letter-spacing:.01em;
  color:var(--on-ink-link);
  overflow-wrap:anywhere;
  /* a quiet permanent underline: the affordance is not colour alone */
  text-decoration:underline;
  text-decoration-color:var(--foot-underline);
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  transition:color var(--dur-quick) var(--ease-out),
             text-decoration-color var(--dur-quick) var(--ease-out);
}
.foot-row:hover .foot-row-v{
  color:var(--on-ink-text);
  text-decoration-color:currentColor;
}
.foot-row-arr{
  width:16px; height:16px; flex:none;
  margin-left:auto;
  color:var(--on-ink-faint);
  transition:transform var(--dur-quick) var(--ease-out),
             color var(--dur-quick) var(--ease-out);
}
.foot-row:hover .foot-row-arr{ transform:translateX(3px); color:var(--on-ink-text); }

/* ---- the one conversion point ----------------------------------------
   Matches .btn-primary, the same pill the CTA band above the footer uses
   for "Call ..." - the footer's own conversion point shouldn't introduce
   a second, unrelated brand colour right below it. */
.foot-cta{
  display:flex; align-items:center; justify-content:center; gap:var(--sp-3);
  margin-top:var(--flow-2xs);
  min-height:56px;
  padding-inline:var(--sp-6);
  border-radius:var(--pill);
  background:var(--blue);
  color:var(--on-ink-text);
  font-family:var(--font-body);
  font-size:var(--text-sm);
  font-weight:var(--fw-semi);
  text-decoration:none;
  box-shadow:var(--shadow-cta);
  transition:background var(--dur-quick) var(--ease-out), transform var(--dur-quick) ease;
}
.foot-cta:hover{ background:var(--deep); transform:translateY(-2px); }
.foot-cta-arr{
  width:17px; height:17px; flex:none;
  transition:transform var(--dur-quick) var(--ease-out);
}
.foot-cta:hover .foot-cta-arr{ transform:translateX(3px); }

/* ---- the index ------------------------------------------------------
   Each group is headed by a register line, set like an entry in the index
   at the back of an atlas. The heading is not interactive: every link
   below it is always visible. */
.foot-nav{ border-bottom:var(--bw-hair) solid var(--on-ink-rule); }
.foot-col{ border-top:var(--bw-hair) solid var(--on-ink-rule); }

.foot-colhead{
  display:flex; align-items:center; gap:var(--sp-3);
  min-height:52px;
  padding-block:var(--sp-2);
}
.foot-colname{
  margin:0;
  font-family:var(--font-mono);
  font-size:var(--label-lg);
  font-weight:var(--fw-medium);
  letter-spacing:var(--track-label-lg);
  text-transform:uppercase;
  color:var(--on-ink-text);
}

.foot-links{
  position:relative;
  list-style:none;
  margin:0;
  padding:0 0 var(--sp-3) var(--sp-4);
}
/* the atlas signature on its side: each group is spined in the three logo
   colours, so a link list reads as one block rather than a loose stack */
.foot-links::before{
  content:"";
  position:absolute; left:0; top:6px; bottom:calc(var(--sp-3) + 6px);
  width:var(--bw-accent);
  border-radius:var(--pill);
  background:var(--foot-tri-v);
}
.foot-links li + li{ margin-top:var(--sp-2); }
.foot-links a{
  display:flex; align-items:center; gap:var(--sp-3);
  min-height:48px;
  padding:var(--sp-1) var(--sp-3);
  border-radius:var(--r-8);
  color:var(--on-ink-muted);
  text-decoration:none;
  transition:background var(--dur-quick) var(--ease-out),
             color var(--dur-quick) var(--ease-out);
}
.foot-links a:hover{ background:var(--foot-hover); color:var(--on-ink-text); }
.foot-t{
  font-size:var(--text-lg);
  letter-spacing:.01em;
  text-decoration:underline;
  text-decoration-color:rgba(var(--ch-sky),.22);
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  transition:text-decoration-color var(--dur-quick) var(--ease-out);
}
.foot-links a:hover .foot-t{ text-decoration-color:currentColor; }

/* ---- standards, statutory, legal - one content type per row ---------- */
.foot-base{
  margin-top:var(--flow-lg);
  padding-top:var(--sp-2);
  border-top:var(--bw-hair) solid var(--on-ink-rule);
}
.foot-standards{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:var(--sp-1) var(--sp-6);
  list-style:none; margin:0; padding:0;
}
/* The decorative shield/chart glyphs are dropped: the text does the work,
   and a dated claim is what separates a certificate from a sticker. */
.foot-stamp{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  min-height:var(--tap);
  font-family:var(--font-mono);
  font-size:var(--label-sm);
  letter-spacing:var(--track-label);
  text-transform:uppercase;
  color:var(--on-ink-muted);
}
.foot-stamp-y{
  padding:3px 7px;
  border:var(--bw-hair) solid var(--foot-hair-strong);
  border-radius:var(--r-8);
  font-variant-numeric:tabular-nums;
  color:var(--on-ink-text);
}

/* statutory identifiers - Companies Act s.12 expects CIN and registered
   office on the site. Key and value share a row and wrap as a pair. */
.foot-statutory{
  display:flex; flex-wrap:wrap;
  gap:var(--sp-1) var(--sp-6);
  list-style:none;
  margin:var(--sp-2) 0 0;
  padding-top:var(--sp-3);
  border-top:var(--bw-hair) solid var(--foot-hair);
  font-size:var(--text-xs);
}
.foot-statutory li{
  display:inline-flex; align-items:baseline; flex-wrap:wrap;
  gap:var(--sp-2);
  min-height:32px;
}
.foot-reg-v{
  font-family:var(--font-mono);
  letter-spacing:var(--track-label);
  font-variant-numeric:tabular-nums;
  color:var(--on-ink-muted);
}
/* Unfilled placeholder. Deliberately conspicuous so a dummy CIN cannot go
   live unnoticed - remove the class once the real value is in. */
.foot-tbd{
  color:var(--on-ink-faint);
  text-decoration:underline dashed;
  text-decoration-color:rgba(var(--ch-yellow),.55);
  text-decoration-thickness:1px;
  text-underline-offset:3px;
}

.foot-legal{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:var(--sp-2) var(--sp-4);
  margin-top:var(--sp-2);
  padding-top:var(--sp-3);
  border-top:var(--bw-hair) solid var(--foot-hair);
}
.foot-copy{
  margin:0;
  font-size:var(--text-xs);
  letter-spacing:.01em;
  color:var(--on-ink-faint);
}
.foot-social{
  display:inline-grid; place-items:center;
  width:44px; height:44px; flex:none;
  border:var(--bw-hair) solid var(--foot-hair-strong);
  border-radius:var(--r-12);
  color:var(--on-ink-muted);
  transition:background var(--dur-quick) var(--ease-out),
             border-color var(--dur-quick) var(--ease-out),
             color var(--dur-quick) var(--ease-out);
}
.foot-social:hover{
  background:var(--foot-hover);
  border-color:var(--on-ink-border);
  color:var(--on-ink-text);
}
.foot-social svg{ width:18px; height:18px; }

/* ---- focus ----------------------------------------------------------
   A real outline, not a shadow: glow effects do not satisfy SC 2.4.11.
   Logo yellow is 9.95:1 on the ground, and reads just as clearly against
   the CTA's blue fill, so the one outline colour covers every footer link. */
.site-foot a:focus-visible{
  outline:var(--bw-rule) solid var(--logo-y);
  outline-offset:2px;
}

/* ---- tablet and up: the index becomes two columns -------------------- */
@media(min-width:760px){
  .foot-deck,
  .foot-cta{ max-width:520px; }
  .foot-blurb{ max-width:52ch; }

  .foot-nav{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:var(--flow-lg);
    align-content:start;
    border-bottom:0;
  }
  .foot-col{ border-top:0; }
  .foot-colhead{
    min-height:0;
    padding:0 0 var(--sp-3);
    border-bottom:var(--bw-hair) solid var(--on-ink-rule);
  }
  .foot-links{ padding-top:var(--sp-3); padding-bottom:0; }
  .foot-links::before{ width:var(--bw-rule); top:calc(var(--sp-3) + 6px); bottom:6px; }
}

@media(min-width:1020px){
  .foot-inner{
    padding-block:var(--flow-2xl) calc(var(--flow-lg) + env(safe-area-inset-bottom, 0px));
  }
  .foot-main{
    grid-template-columns:minmax(320px, 1fr) 1.2fr;
    gap:var(--flow-xl);
    align-items:start;
  }
  .foot-base{ margin-top:var(--flow-xl); }
}

/* ---- motion ---------------------------------------------------------- */
@media(prefers-reduced-motion: reduce){
  .foot-cta-arr,
  .foot-row-arr,
  .foot-row,
  .foot-links a,
  .foot-social{ transition:none; }
  .foot-row:hover .foot-row-arr,
  .foot-cta:hover .foot-cta-arr{ transform:none; }
}

/* ============================================================
   SCROLL REVEALS
   ============================================================ */
/* Scroll reveals are progressive enhancement ONLY. The opacity:0 is gated behind
   .js, which an inline script in <head> adds before first paint — so with
   JavaScript off or still loading, every section renders normally instead of a
   blank page. Never write a bare `.reveal{opacity:0}` here. */
.js .reveal{
  opacity:0; transform:translateY(18px);
  transition:opacity var(--dur-reveal) var(--ease-out), transform var(--dur-reveal) var(--ease-out);
}
.reveal.in{ opacity:1; transform:none; }

/* Above-the-fold entrance, CSS only — never waits on a script. Use .rise (not
   .reveal) for anything in the first viewport. */
@keyframes rise{ from{ opacity:0; transform:translateY(18px); } to{ opacity:1; transform:none; } }
.rise{ animation:rise var(--dur-reveal) var(--ease-out) both; }
.rise[data-d="1"]{ animation-delay:.07s }
.rise[data-d="2"]{ animation-delay:.15s }
.rise[data-d="3"]{ animation-delay:.24s }
.rise[data-d="4"]{ animation-delay:.33s }
.rise[data-d="5"]{ animation-delay:.42s }
.reveal[data-d="1"]{ transition-delay:.07s }
.reveal[data-d="2"]{ transition-delay:.15s }
.reveal[data-d="3"]{ transition-delay:.24s }
.reveal[data-d="4"]{ transition-delay:.33s }
.reveal[data-d="5"]{ transition-delay:.42s }

/* ============================================================
   TESS HERO — the living lattice on sub-page heroes
   (about · contact · products · careers; never index, whose
   living layer is the atlas map)

   Base layer: every hero and section ground now paints the static
   --tess-tile (see .hero::before, .page-hero::before, .texgrid::before)
   — one texture for the whole site, and on its own the whole
   treatment for touch, reduced-motion and no-JS visitors.
   tess-hero.js mounts a live field only on fine-pointer desktops:
   a one-shot courses-laid build, then a capped bloom loop and
   pointer ink. When it mounts (.has-fx) the static tile hides —
   the field replaces the tile, the two never stack. The modifier
   class is what the script looks for, so it stays even though the
   tile itself is now inherited from .page-hero.
   ============================================================ */
.page-hero--tess.has-fx::before{ display:none; }

.tess-fx{
  position:absolute; inset:0; overflow:hidden; pointer-events:none;
  contain:layout paint;
  /* copy exclusion: the field drops to ~an eighth of its strength under the
     text column, so headline and lede read off effectively flat paper */
  -webkit-mask-image:linear-gradient(100deg, rgba(var(--ch-black),.12) 0 38%, rgb(var(--ch-black)) 66%);
          mask-image:linear-gradient(100deg, rgba(var(--ch-black),.12) 0 38%, rgb(var(--ch-black)) 66%);
}
.tess-fx svg{ position:absolute; inset:0; width:100%; height:100%; display:block; }

.tess-fx .tl{ fill:none; stroke:var(--ink); stroke-width:1; stroke-linejoin:round; opacity:var(--o,.07); }
.tess-fx .tl-ghost{ fill:none; stroke:var(--hair-strong); stroke-width:1; stroke-linejoin:round; opacity:var(--o,.25); }
.tess-fx .f-y{ fill:var(--logo-y); } .tess-fx .f-g{ fill:var(--logo-g); }
.tess-fx .f-t{ fill:var(--logo-t); } .tess-fx .f-b{ fill:var(--blue); }

/* courses-laid build: rows fade up once, then rest at their natural opacity */
.tess-fx .t-build{ animation:tess-build .5s var(--ease-out) var(--del,0s) 1 backwards; }
@keyframes tess-build{ from{ opacity:0; } to{ opacity:var(--o,1); } }

/* built residue: a face settles lit and stays */
.tess-fx .t-hold{ opacity:0; animation:tess-hold .6s var(--ease-out) var(--del,0s) 1 forwards; }
@keyframes tess-hold{ from{ opacity:0; } to{ opacity:var(--pk,.26); } }

/* the continuous life: one expanding ring, distance-staggered, opacity only */
.tess-fx .t-loop{ opacity:0; animation:tess-bloom var(--dur,14s) ease-in-out var(--del,0s) infinite; }
@keyframes tess-bloom{ 0%,10%{ opacity:0; } 30%{ opacity:var(--pk,.22); } 50%{ opacity:0; } 100%{ opacity:0; } }

/* pointer ink pool (driven by WAAPI from tess-hero.js) */
.tess-fx .t-ink{ opacity:0; }

/* paused off-viewport or in a hidden tab */
.tess-fx.paused *{ animation-play-state:paused; }

/* the reduced-motion contract lives here, not per page: bare line field,
   accents hidden — never frozen at partial opacity */
@media(prefers-reduced-motion:reduce){
  .tess-fx *{ animation:none !important; }
  .tess-fx .t-loop, .tess-fx .t-hold, .tess-fx .t-ink{ opacity:0 !important; }
}

/* ============================================================
   TOUCH & SMALL-SCREEN REFINEMENTS
   Measured at 390 / 768 / 1280 across all six pages. Everything
   below fixes a real reading found at those widths — undersized
   hit areas and mono labels that fall under 11px on a phone.
   ============================================================ */

/* ---- hit areas: 44px minimum wherever the burger is showing ---- */
/* width is a proxy below; pointer:coarse is the real signal — a 1280px
   tablet needs the same hit areas as a phone. */
@media(max-width:1039px), (pointer:coarse){
  .az-jump a{ min-width:var(--tap); min-height:var(--tap); }
  .btn-sm{ min-height:var(--tap); padding:12px 18px; }
  .branch .bcontact a{ min-height:var(--tap); }
}
/* (.cta-band .meta children get their 44px in the CTA BAND block, where the
   alignment they share with it lives too. The footer's own targets are sized
   in the FOOTER block — every row, link, stamp and icon carries its min-height
   there rather than being patched from here.) */

/* ---- label legibility: nothing under 11.5px on a small screen ---- */
@media(max-width:900px){
  .icard--more .kicker,
  .icard .tags,
  .branch .region,
  .wcard .mod,
  .wcard .role,
  .job .jmeta,
  .kv .k,
  .cred-cap,
  .cred-list .yr,
  .pill,
  .result-bar,
  .side-label,
  .fbtn .n,
  .side-reset,
  .pd-cat,
  .pd-label,
  .tile-label,
  .stat-cell .l,
  .feature-tile .tile-label,
  .leader span{ font-size:var(--label-md); }

  .foot-row-k,
  .foot-est,
  .foot-stamp,
  .foot-reg-k,
  .mnav-foot{ font-size:var(--label-md); }
}

/* ---- phones: stack the button rows so nothing sits half-width ---- */
@media(max-width:520px){
  .page-hero .ctas,
  .cta-band .ctas{ flex-direction:column; align-items:stretch; }
  .page-hero .ctas .btn,
  .cta-band .ctas .btn{ width:100%; }
}

@media(prefers-reduced-motion: reduce){
  *{ scroll-behavior:auto; }
  .js .reveal, .reveal{ transition:none; opacity:1; transform:none; }
  .rise{ animation:none; }
  .btn, .fbtn, .icard, .wcard, .lead-card, .person, .icard .ph img, .branch, .job, .az-item{ transition:none; }
  .btn:hover, .fbtn:hover, .icard:hover, .wcard:hover, .lead-card:hover, .person:hover, .branch:hover, .job:hover{ transform:none; }
  .icard:hover .ph img{ transform:none; }
  .az-item:hover::after{ transform:rotate(-45deg); }
  .pdrawer-panel, .pdrawer-scrim{ transition:none; }
}

/* scroll hardening (mobile) */
@media (pointer:coarse){ html{ scroll-behavior:auto; } }
.cta,.site-foot,.px-sky,.callout-px{ overflow-anchor:none; }
