/* ============================================================================
   QUANTRO Therapeutics — site stylesheet
   One design: 1B molecular hero (dark, blurred backdrop + cursor focus)
   over 1A-style light content below the header.
   ============================================================================ */

@import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;500;600;700;800&family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap');

:root{
  /* navy scale */
  --navy-900:#0d1f36; --navy-800:#132b4a; --navy-700:#18375e; --navy-600:#24497a;
  --navy-500:#3a6296; --navy-400:#6d8cb2; --navy-300:#a4b9d0; --navy-100:#e4ebf3; --navy-50:#f2f6fa;
  /* red scale */
  --red-700:#8f181c; --red-600:#bb2025; --red-500:#ce2a30; --red-400:#e05055;
  --red-300:#ef8f92; --red-100:#fbdfe0; --red-50:#fdf1f1;
  /* a lit brand red for dark backgrounds: brighter than --red-400 and a purer
     red than it, so it reads as QUANTRO red switched on rather than as coral */
  --red-bright:#ff3b41;
  /* sampled straight from QUANTRO_Logo_white_red.svg — the mark's own red */
  --red-logo:#ba191a;
  /* the same hue lightened until large text clears 3:1 on the hero */
  --red-em:#d67576;
  /* deck accents (hero) */
  --azure:#277ce0; --sky:#85c8fc; --tint:#d9edfd; --petrol:#043861; --coral:#ff6b74;
  /* neutrals */
  --ink:#101418; --body:#3b4552; --muted:#6b7480; --line:#dbe3ec; --surface:#fff; --surface-sunken:#f5f8fb;
  --paper-warm:#fcf7f2;
  /* type */
  --font-display:'Sora','Segoe UI',system-ui,sans-serif;
  --font-body:'IBM Plex Sans','Segoe UI',system-ui,sans-serif;
  --font-mono:'IBM Plex Mono',ui-monospace,monospace;
  /* fluid type */
  --fs-display-xl:clamp(2.75rem,2.1rem + 2.9vw,4.9rem);
  --fs-display-lg:clamp(2.15rem,1.7rem + 1.9vw,3.35rem);
  --fs-display-md:clamp(1.9rem,1.55rem + 1.5vw,2.75rem);
  --fs-h2:clamp(1.4rem,1.2rem + .7vw,1.9rem);
  --fs-h3:1.25rem; --fs-h4:1.0625rem;
  --fs-body-lg:1.125rem; --fs-body:1rem; --fs-body-sm:.9375rem; --fs-eyebrow:.9375rem;
  --lh-tight:1.06; --lh-snug:1.22; --lh-normal:1.5; --lh-relaxed:1.65;
  --ls-tight:-.02em; --ls-wide:.08em; --ls-wider:.16em;
  /* shape */
  --radius-sm:6px; --radius-md:10px; --radius-lg:16px; --radius-pill:999px;
  --container:1200px;
  --shadow-sm:0 1px 2px rgba(13,31,54,.06),0 1px 1px rgba(13,31,54,.04);
  --shadow-md:0 4px 14px rgba(13,31,54,.08),0 1px 3px rgba(13,31,54,.06);
  --shadow-lg:0 16px 40px rgba(13,31,54,.14),0 4px 10px rgba(13,31,54,.06);
  --shadow-card-hover:0 22px 48px rgba(13,31,54,.15);
  --ease:cubic-bezier(.4,0,.2,1);
}

*{box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-top:82px}
body{margin:0;background:#fff;color:var(--body);font-family:var(--font-body);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;line-height:var(--lh-normal)}
h1,h2,h3,h4{margin:0;font-family:var(--font-display);color:var(--navy-700);letter-spacing:var(--ls-tight)}
p{margin:0}
img{max-width:100%;display:block}
a{color:var(--red-600);text-decoration:none}
a:hover{color:var(--red-700)}
::selection{background:var(--red-100);color:var(--navy-900)}
:focus-visible{outline:2px solid var(--azure);outline-offset:3px;border-radius:var(--radius-sm)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}

/* ---- layout ---- */
.wrap{max-width:var(--container);margin:0 auto;padding-left:clamp(20px,4.4vw,56px);padding-right:clamp(20px,4.4vw,56px)}
.wrap-md{max-width:1000px}
.sec{padding:clamp(72px,8.5vw,124px) 0}
.sec--sunken{background:var(--surface-sunken)}
.sec--navy{background:var(--navy-900);color:#fff}
.eyebrow{font-family:var(--font-display);color:var(--red-600);font-size:var(--fs-eyebrow);
  font-weight:700;letter-spacing:var(--ls-wider);text-transform:uppercase}
.sec--navy .eyebrow{color:var(--sky)}
.lede{font-size:var(--fs-body-lg);line-height:var(--lh-relaxed);color:var(--body);max-width:64ch}
.rule{height:1px;background:var(--line);border:0;margin:0}

.grid{display:grid;gap:24px}
.g-2{grid-template-columns:1fr 1fr}
.g-3{grid-template-columns:repeat(3,1fr)}
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(40px,5vw,72px);align-items:center}
.split--wide-l{grid-template-columns:1.1fr .9fr}

/* ---- buttons ---- */
.btn{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-display);font-weight:600;
  font-size:15px;padding:14px 28px;border-radius:var(--radius-pill);white-space:nowrap;
  transition:background .2s var(--ease),color .2s,border-color .2s,transform .2s}
.btn--primary{background:var(--red-600);color:#fff;box-shadow:0 8px 22px rgba(187,32,37,.26)}
.btn--primary:hover{background:var(--red-700);color:#fff}
.btn--on-dark{background:rgba(133,200,252,.08);color:#fff;border:1px solid rgba(133,200,252,.4)}
.btn--on-dark:hover{background:rgba(133,200,252,.16);border-color:var(--sky);color:#fff}
.link-arrow{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-display);
  font-weight:600;font-size:15px;color:var(--red-600)}
.link-arrow:hover{gap:11px;transition:gap .2s var(--ease)}

/* ============================ NAV ============================ */
/* The glass effect lives on a pseudo-element, not on .nav itself: any filter
   or backdrop-filter on an element makes it a containing block for fixed
   descendants, which trapped the mobile menu overlay inside the header bar. */
.nav{position:sticky;top:0;z-index:60;display:flex;align-items:center;justify-content:space-between;gap:24px;
  padding:12px clamp(20px,4.4vw,56px);
  border-bottom:1px solid rgba(133,200,252,.14)}
.nav::before{content:"";position:absolute;inset:0;z-index:-1;background:rgba(11,23,42,.92);
  -webkit-backdrop-filter:saturate(150%) blur(16px);backdrop-filter:saturate(150%) blur(16px)}
.nav__links{display:flex;gap:26px;font-family:var(--font-display);font-weight:500;font-size:14.5px}
.nav__links a{position:relative;color:rgba(234,241,251,.82)}
.nav__links a:hover,.nav__links a[aria-current]{color:#fff}
.nav__links a::after{content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;background:var(--red-logo);
  transform:scaleX(0);transform-origin:left;transition:transform .2s var(--ease)}
.nav__links a:hover::after,.nav__links a[aria-current]::after{transform:scaleX(1)}
.nav__right{display:flex;align-items:center;gap:20px}

@media (max-width:760px){
  /* At 138% of a 390px screen the picture is 538px wide and only ~360px tall,
     so it covered a band across the middle and the reveal ran off its top edge
     as a hard horizontal line. Let it cover the hero instead. */
  .hero__fx img{top:50%;width:auto;height:100%;min-width:100%;object-fit:cover}
}

/* ============================ HERO (1B) ============================ */
.hero{position:relative;overflow:hidden;isolation:isolate;
  padding:clamp(64px,8vw,110px) clamp(20px,4.4vw,56px) clamp(76px,9vw,120px);
  background:
    radial-gradient(95% 75% at 20% 4%, #3a5c7e 0%, rgba(58,92,126,0) 58%),
    linear-gradient(167deg, #234a6f 0%, #123a5e 46%, #05335a 100%)}
.hero__fx{position:absolute;inset:0;z-index:0;pointer-events:none}
.hero__fx img{position:absolute;left:50%;top:45%;transform:translate(-50%,-50%);
  width:min(1500px,138%);max-width:none}
.hero__fx .blur{filter:blur(var(--base-blur,46px)) saturate(1.15);opacity:.82}
.hero__fx .sharp{filter:blur(var(--sharp-blur,0px)) saturate(1.25);opacity:var(--sharp-op,.9);will-change:mask-image;
  -webkit-mask-image:radial-gradient(circle var(--focus-r,290px) at var(--mx,50%) var(--my,40%),#000 0%,#000 36%,rgba(0,0,0,0) var(--focus-edge,76%));
  mask-image:radial-gradient(circle var(--focus-r,290px) at var(--mx,50%) var(--my,40%),#000 0%,#000 36%,rgba(0,0,0,0) var(--focus-edge,76%))}
/* The dark side of the scrim is pegged to where the copy actually ends, which
   heroFit() measures and publishes. Fixed stops only ever suited one width: the
   headline is a ch measure, so it spans 70% of a 1280 screen but 60% of a 2560
   one, and at the narrow end it ran well past a gradient that had already
   faded out. */
.hero{--hero-copy-edge:66%}
.hero__scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(102deg,
      rgba(6,26,48,.86) 0%,
      rgba(6,26,48,.60) calc(var(--hero-copy-edge) * .5),
      rgba(6,26,48,.34) calc(var(--hero-copy-edge) * .86),
      rgba(6,26,48,.10) calc(var(--hero-copy-edge) + 13%),
      rgba(6,26,48,.30) 100%),
    linear-gradient(0deg, rgba(4,24,46,.55) 0%, rgba(4,24,46,0) 42%)}
.hero .wrap{position:relative;z-index:2}
.hero__eyebrow{font-family:var(--font-mono);font-size:clamp(15px,.9rem + .25vw,17px);
  letter-spacing:.18em;text-transform:uppercase;color:var(--sky)}
.hero h1{color:#fff;font-weight:800;line-height:var(--lh-tight);font-size:var(--fs-display-xl);max-width:17ch;margin-top:22px}
.hero h1 em{font-style:normal;color:var(--red-em)}
.hero__lede{font-size:clamp(1.05rem,1rem + .35vw,1.25rem);line-height:1.6;color:rgba(233,241,251,.84);max-width:58ch;margin-top:26px}
.hero__cta{display:flex;gap:14px;margin-top:34px;flex-wrap:wrap}
/* interior page hero: shorter band, no molecular effect */
.hero--page{padding:clamp(52px,6vw,84px) clamp(20px,4.4vw,56px)}
.hero--page h1{font-size:var(--fs-display-lg);max-width:22ch}


/* ============================ SECTION PATTERNS (1A) ============================ */


/* stat rail (light) */

/* kicker / quote band */

/* ---- interactive time-resolved chart ---- */
.readout{background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);padding:26px;box-shadow:var(--shadow-lg)}
.readout input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:4px;border-radius:999px;margin:14px 0 6px;
  background:linear-gradient(90deg,var(--red-600) 0%,var(--red-600) var(--fill,20%),#c9d3e0 var(--fill,20%),#c9d3e0 100%)}
.readout input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;border-radius:50%;
  background:var(--red-600);border:3px solid #fff;box-shadow:0 2px 8px rgba(13,31,54,.3);cursor:pointer}
.readout input[type=range]::-moz-range-thumb{width:20px;height:20px;border-radius:50%;background:var(--red-600);border:3px solid #fff;cursor:pointer}

/* ---- comparison / spec tables ---- */
.tbl{width:100%;border-collapse:collapse;margin-top:clamp(32px,4vw,48px);font-size:15px}
.tbl th,.tbl td{text-align:left;padding:18px 20px;border-bottom:1px solid var(--line);vertical-align:top;line-height:1.5}
.tbl thead th{font-family:var(--font-display);font-weight:700;color:var(--navy-700);font-size:1.05rem;border-bottom:2px solid var(--navy-300)}
.tbl thead th small{display:block;font-family:var(--font-mono);font-weight:400;font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--red-600);margin-top:6px}
.tbl th[scope=row]{font-family:var(--font-mono);font-weight:400;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);width:200px;white-space:nowrap}
.tbl td b{font-family:var(--font-display);font-weight:700;color:var(--navy-700);font-size:1.1rem}
.tbl .hi{background:rgba(39,124,224,.07)}
.tbl-scroll{overflow-x:auto}

/* ---- FAQ ---- */

/* ---- team ---- */
.team{display:grid;grid-template-columns:repeat(3,1fr);gap:28px;margin-top:clamp(36px,4vw,52px)}
.person img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:var(--radius-lg);background:var(--navy-100)}
.person h3{font-size:var(--fs-h3);font-weight:700;margin-top:18px}
.person .role{font-family:var(--font-display);font-weight:600;font-size:14px;color:var(--red-600);margin-top:4px}
.person p{font-size:var(--fs-body-sm);line-height:var(--lh-relaxed);color:var(--body);margin-top:12px}

/* ---- media / figure ---- */
.figure{border-radius:var(--radius-lg);overflow:hidden;border:1px solid var(--line);box-shadow:var(--shadow-md);background:var(--navy-900)}
.figure img{width:100%;height:100%;object-fit:cover;display:block}

/* logo strip */
.logos{display:flex;align-items:center;justify-content:center;gap:clamp(28px,5vw,64px);flex-wrap:wrap}
.logos img{height:44px;width:auto;opacity:.85;filter:grayscale(1);transition:opacity .2s,filter .2s}
.logos img:hover{opacity:1;filter:none}

/* timeline */
.timeline{display:grid;gap:0;margin-top:clamp(36px,4vw,52px);border-left:2px solid var(--line);padding-left:0}
.timeline li{list-style:none;position:relative;padding:0 0 30px 30px}
.timeline li::before{content:"";position:absolute;left:-7px;top:4px;width:12px;height:12px;border-radius:50%;background:var(--red-600);border:2px solid #fff}
.timeline b{font-family:var(--font-display);color:var(--navy-700);font-weight:700}
.timeline p{font-size:var(--fs-body);color:var(--body);margin-top:4px}

/* contact / form */
.field{display:flex;flex-direction:column;gap:7px;margin-bottom:18px}
.field label{font-family:var(--font-display);font-weight:600;font-size:14px;color:var(--navy-700)}
.field input,.field select,.field textarea{font-family:var(--font-body);font-size:15px;padding:12px 14px;
  border:1px solid var(--line);border-radius:var(--radius-md);background:#fff;color:var(--ink)}
.field textarea{min-height:130px;resize:vertical}
.checkline{display:flex;gap:10px;align-items:flex-start;font-size:14px;line-height:1.5}

/* note callout (CONFIRM/placeholder) */
.note{border-left:3px solid var(--red-600);background:var(--red-50);border-radius:0 var(--radius-md) var(--radius-md) 0;
  padding:16px 20px;font-size:14px;line-height:1.6;color:var(--navy-700)}
.note b{font-family:var(--font-display)}

/* ============================ FOOTER ============================ */
.footer{background:var(--navy-900);color:rgba(255,255,255,.62);padding:72px clamp(20px,4.4vw,56px) 40px}
.footer__grid{max-width:var(--container);margin:0 auto;display:grid;grid-template-columns:1.8fr repeat(2,1fr);gap:40px;
  border-bottom:1px solid rgba(255,255,255,.12);padding-bottom:44px}
.footer__brand{max-width:290px}
.footer__brand img{height:26px;margin-bottom:16px}
.footer__brand p{font-size:14px;line-height:1.7}
.footer__col{display:flex;flex-direction:column;gap:11px;font-size:14px}
.footer__col b{color:#fff;font-family:var(--font-display);font-weight:600;margin-bottom:3px;font-size:14px}
.footer__col a{color:rgba(255,255,255,.62)}
.footer__col a:hover{color:#fff}
/* ============================================================================
   Legal pages — EN/DE switch and long-form prose
   ============================================================================ */
.langswitch{display:inline-flex;gap:2px;padding:3px;margin-top:26px;
  border:1px solid var(--line);border-radius:var(--radius-pill);background:var(--surface-sunken)}
.langswitch button{font-family:var(--font-display);font-weight:600;font-size:13px;letter-spacing:.01em;
  padding:7px 17px;border:0;border-radius:var(--radius-pill);background:transparent;color:var(--muted);
  cursor:pointer;transition:background .2s var(--ease),color .2s}
.langswitch button:hover{color:var(--navy-700)}
.langswitch button[aria-pressed="true"]{background:var(--navy-700);color:#fff}
/* without JS both languages stay on the page, each under its own heading */
html:not(.no-js) [data-lang-panel]{display:none}
html:not(.no-js) [data-lang-panel].is-active{display:block}

.legal{max-width:78ch;margin-top:clamp(28px,3.4vw,40px)}
.legal h2{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h3);color:var(--navy-700);
  line-height:var(--lh-snug);margin-top:clamp(34px,4vw,46px)}
.legal h3{font-family:var(--font-display);font-weight:700;font-size:var(--fs-body-lg);color:var(--navy-700);
  margin-top:26px}
.legal p{font-size:var(--fs-body);line-height:var(--lh-relaxed);color:var(--body);margin-top:14px}
.legal ul{margin:14px 0 0;padding-left:22px}
.legal li{font-size:var(--fs-body);line-height:var(--lh-relaxed);color:var(--body);margin-top:10px}
.legal a{color:var(--red-600);border-bottom:1px solid rgba(187,32,37,.32)}
.legal a:hover{border-bottom-color:var(--red-600)}
.legal__addr{padding:16px 20px;background:var(--surface-sunken);border-left:3px solid var(--navy-300);
  border-radius:0 var(--radius-md) var(--radius-md) 0}
.legal .kv{display:grid;grid-template-columns:230px 1fr;gap:14px 32px;margin-top:26px;
  padding-top:22px;border-top:1px solid var(--line)}
.legal .kv dt{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);padding-top:3px}
.legal .kv dd{margin:0;font-size:var(--fs-body);line-height:var(--lh-relaxed);color:var(--body)}
@media (max-width:640px){
  .legal .kv{grid-template-columns:1fr;gap:4px}
  .legal .kv dd{margin-bottom:16px}
}
/* Event facts. The dl wraps each pair in a div, so the row is the grid rather
   than the list itself. Label typography matches the legal key/value list. */
.eventfacts{margin:clamp(26px,3.2vw,36px) 0 0;padding:0;border-top:1px solid var(--line)}
.eventfacts > div{display:grid;grid-template-columns:150px 1fr;gap:6px 30px;align-items:baseline;
  padding:13px 0;border-bottom:1px solid var(--line)}
.eventfacts dt{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted)}
.eventfacts dd{margin:0;font-size:var(--fs-body);line-height:var(--lh-relaxed);color:var(--body)}
.eventfacts time{white-space:nowrap}
@media (max-width:640px){
  .eventfacts > div{grid-template-columns:1fr;gap:3px;padding:12px 0}
}

/* inline source line under a platform claim */
.srcline{font-size:13.5px;line-height:1.6;color:var(--muted);margin-top:14px}
.srcline a{color:var(--navy-600);border-bottom:1px solid var(--navy-300)}
.srcline a:hover{color:var(--red-600);border-bottom-color:var(--red-600)}

/* Funder / campus / association marks. All three are supplied as dark ink on
   transparency, so each sits on a light plate rather than being inverted —
   inverting would throw away colours that are not ours to change. */
.footer__logos{max-width:var(--container);margin:clamp(38px,4.4vw,54px) auto 0;
  padding-top:clamp(26px,3vw,34px);border-top:1px solid rgba(255,255,255,.11);
  list-style:none;display:flex;flex-wrap:wrap;align-items:center;gap:clamp(12px,1.6vw,18px)}
.footer__logos li{background:#fff;border-radius:var(--radius-md);padding:11px 18px;
  display:flex;align-items:center;transition:transform .2s var(--ease)}
.footer__logos li:hover{transform:translateY(-2px)}
.footer__logos img{display:block;width:auto;height:30px}
@media (max-width:560px){ .footer__logos img{height:26px} .footer__logos li{padding:9px 14px} }

.footer__legal{max-width:var(--container);margin:0 auto;padding-top:22px;display:flex;justify-content:space-between;
  gap:24px;flex-wrap:wrap;font-size:12.5px;color:rgba(255,255,255,.45);line-height:1.6}
.footer__legal p{max-width:78ch}

/* ============================ RESPONSIVE ============================ */
@media (max-width:1040px){
  .split,.split--wide-l{grid-template-columns:1fr;gap:36px}
  .g-3{grid-template-columns:1fr 1fr}
  .team{grid-template-columns:1fr 1fr}
  .footer__grid{grid-template-columns:1fr 1fr;gap:32px}
}
@media (max-width:760px){
  .g-2,
.g-3,
.team,
.footer__grid{grid-template-columns:1fr}
  .tbl thead{display:none}
  .tbl tr{display:block;border-bottom:1px solid var(--line);padding:6px 0}
  .tbl th[scope=row]{display:block;width:auto;padding:14px 0 2px}
  .tbl td{display:block;padding:2px 0 12px;border:0}
  .tbl td::before{content:attr(data-label);display:block;font-family:var(--font-mono);font-size:11px;
    letter-spacing:.1em;text-transform:uppercase;color:var(--red-600);margin-bottom:4px}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
}

/* reveal on scroll */
[data-reveal]{opacity:0;transform:translateY(18px);transition:opacity .55s var(--ease),transform .55s var(--ease)}
[data-reveal].in{opacity:1;transform:none}
.no-js [data-reveal]{opacity:1;transform:none}

/* ============================================================================
   v2 — HIERARCHY COMPONENTS (story-driven layout)
   Distinct archetypes so consecutive sections never read the same.
   ============================================================================ */
:root{ --navy-200:#c8d5e5; }

/* oversized display heading for narrative peaks */
.h-display{font-size:var(--fs-display-lg);line-height:var(--lh-tight);letter-spacing:var(--ls-tight)}
.lead-xl{font-size:clamp(1.2rem,1.02rem + .8vw,1.7rem);line-height:1.32;color:var(--navy-700);
  font-family:var(--font-display);font-weight:500;letter-spacing:-.01em}
.sec--navy .lead-xl{color:#fff}
/* A lead that carries a whole argument rather than one line runs smaller and
   looser: at the display size a four-sentence paragraph reads as a wall of
   type, which is the opposite of what the size is for. */
.lead-xl--long{font-size:clamp(1.05rem,.96rem + .4vw,1.3rem);line-height:1.5;
  font-weight:400;letter-spacing:0;max-width:74ch}
/* An argument split across paragraphs needs the gap that makes it read as
   separate steps. The section rhythm zeroes every margin, so this pairing has
   to ask for its own. */
.sec > .wrap > .lead-xl + .lead-xl{margin-top:1.1em}

/* two-column section intro: title left, lead right (breaks the stacked rhythm) */
.leadin{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,72px);align-items:end}
.leadin--top{align-items:start}

/* PROOF BAR — big numerals right after the hero */

/* COMPARE — binding/endpoint vs functional readout */
.compare{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-top:clamp(30px,3.6vw,46px)}

/* STEPS — process sequence (not cards) */
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(20px,2.6vw,34px);margin-top:clamp(44px,5vw,64px)}
.step{border-top:2px solid var(--navy-200);padding-top:24px}
.step__n{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;
  background:var(--navy-700);color:#fff;font-family:var(--font-mono);font-size:14px;margin-top:-44px;margin-bottom:16px;border:4px solid #fff;position:relative}
.sec--sunken .step__n{border-color:var(--surface-sunken)}
.step__t{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h4);color:var(--navy-700)}
.step__d{font-size:var(--fs-body-sm);line-height:var(--lh-relaxed);color:var(--body);margin-top:10px}

/* EVIDENCE LIST — numbered proof points (dark feature) */
.evidence{list-style:none;padding:0;margin:26px 0 0;counter-reset:ev;display:grid;gap:0}
.evidence li{display:grid;grid-template-columns:auto 1fr;gap:18px;padding:18px 0;border-top:1px solid rgba(255,255,255,.14)}
.evidence li::before{counter-increment:ev;content:counter(ev,decimal-leading-zero);font-family:var(--font-mono);font-size:13px;color:var(--sky);padding-top:3px}
.evidence b{display:block;font-family:var(--font-display);font-weight:600;color:#fff;font-size:var(--fs-body-lg)}
.evidence span{display:block;color:rgba(255,255,255,.72);font-size:var(--fs-body);line-height:1.5;margin-top:4px}

/* ROUTE FORK — two large decision panels */

@media (max-width:1040px){
  .leadin{grid-template-columns:1fr;gap:18px;align-items:start}
  .steps{grid-template-columns:1fr 1fr;gap:34px 24px}
}
@media (max-width:640px){
  .compare{grid-template-columns:1fr}
  .steps{grid-template-columns:1fr}
}

/* ============================================================================
   v3 — homepage feature graphics
   ============================================================================ */

/* ---- SIGNAL TIMELINE (Problem section) ---- */
.signalviz{position:relative;margin-top:clamp(30px,4vw,48px)}
.signalviz svg{width:100%;height:auto;display:block;overflow:visible}
/* branching signal: one trunk that repeatedly splits as time passes.
   stroke-width is set per segment inline so the trunk reads strongest. */
.signalviz .br{fill:none;stroke:url(#sigGrad);stroke-linecap:round;
  stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset .85s var(--ease)}
.signalviz.in .br{stroke-dashoffset:0}
/* The chart marks the same four branching columns as the hero field, and reads
   them the same way: the first pair of readings is faint, each column after it
   is darker and more solid, so the picture gets heavier as the signal gets less
   certain. Navy scale rather than sky — these sit on white. */
.signalviz .tip{opacity:0;transition:opacity .6s var(--ease)}
.signalviz .tip--0{fill:var(--navy-300)}
.signalviz .tip--1{fill:var(--navy-400)}
.signalviz .tip--2{fill:var(--navy-600)}
.signalviz .tip--3{fill:var(--navy-700)}
.signalviz.in .tip--0{opacity:.55}
.signalviz.in .tip--1{opacity:.7}
.signalviz.in .tip--2{opacity:.85}
.signalviz.in .tip--3{opacity:1}
/* The chart makes the same point as the hero field: QUANTRO is a place on the
   line, the conventional reading is a cloud over a dozen strands with its
   wording inside it. Nothing to point at, so nothing points. */
.signalviz .cloud__haze{fill:url(#cHaze)}
.signalviz .cloud__t{font-family:var(--font-display);font-size:15px;font-weight:700;fill:var(--navy-700)}
.signalviz .cloud__time{font-family:var(--font-mono);font-size:13px;font-weight:600;letter-spacing:.06em;fill:var(--navy-600)}
.signalviz .cloud__s{font-family:var(--font-display);font-size:12px;font-weight:500;fill:var(--navy-600)}
.signalviz .cloud text{paint-order:stroke;stroke:#fff;stroke-width:3.4px;stroke-linejoin:round}
.signalviz .cloud{opacity:0;transition:opacity .7s var(--ease) .55s}
.signalviz.in .cloud{opacity:1}
.no-js .signalviz .cloud{opacity:1}
/* The flow scaffold ships in the markup on every viewport but is scenery for
   phone flow mode only: hidden until JS turns that mode on, so the cards never
   appear as stray text beside the desktop chart. */
.signalviz .flowmark,
.signalviz__playhead,.signalviz__cards,.signalviz__ruler{display:none}
.signalviz .axis{stroke:var(--navy-300);stroke-width:1.5}
.signalviz .axis-lbl{fill:var(--muted);font-family:var(--font-mono);font-size:12px;letter-spacing:.04em}
.signalviz .tick-lbl{font-family:var(--font-mono);font-size:12px;letter-spacing:.06em;text-transform:uppercase}
.signalviz .node{transform-box:fill-box;transform-origin:center;transform:scale(0);
  transition:transform .55s var(--ease)}
.signalviz.in .node{transform:scale(1)}
.signalviz .ring{fill:none;stroke:var(--red-400);stroke-width:1.5;stroke-dasharray:4 5;opacity:0;transform-box:fill-box;transform-origin:center}
.signalviz.in .ring{opacity:.9;animation:sig-pulse 3.2s ease-in-out .8s infinite}
@keyframes sig-pulse{0%,100%{transform:scale(1);opacity:.8}50%{transform:scale(1.14);opacity:.35}}
.signalviz .lbl{opacity:0;transition:opacity .6s var(--ease) .5s}
.signalviz.in .lbl{opacity:1}
.signalviz .lbl-t{font-family:var(--font-display);font-weight:700;font-size:15px}
.signalviz .lbl-s{font-family:var(--font-display);font-weight:500;font-size:12px}
.signalviz .pill-t{font-family:var(--font-display);font-weight:600;font-size:13px}
.signalviz .cap{font-family:var(--font-body);font-size:11.5px}
.signalviz .tick{stroke:var(--navy-300);stroke-width:1.5}
.signalviz .lbl-t,.signalviz .lbl-s,.signalviz .pill-t,.signalviz .cap{paint-order:stroke;stroke:#fff;stroke-width:3;stroke-linejoin:round}
.no-js .signalviz .br{stroke-dashoffset:0}
.no-js .signalviz .tip--0{opacity:.55}
.no-js .signalviz .tip--1{opacity:.7}
.no-js .signalviz .tip--2{opacity:.85}
.no-js .signalviz .tip--3{opacity:1}
.no-js .signalviz .node{transform:scale(1)}
.no-js .signalviz .lbl,.no-js .signalviz .ring{opacity:1}
@media (prefers-reduced-motion:reduce){.signalviz.in .ring{animation:none}}

/* ---- PIPELINE CHART ---- */
.pipeline{margin-top:clamp(34px,4vw,50px)}
.pipeline__chart{min-width:740px}
.pipeline__row{display:grid;grid-template-columns:230px 1fr;align-items:center;padding:8px 0}
.pipeline__row + .pipeline__row{border-top:1px solid var(--line)}
.pipeline__label b{font-family:var(--font-display);font-weight:700;color:var(--navy-700);font-size:15px;display:block;line-height:1.2}
.pipeline__label span{font-size:12px;color:var(--muted);display:block;margin-top:3px}
.pipeline__label .tag{display:inline-block;font-family:var(--font-mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--red-600);background:var(--red-50);border-radius:var(--radius-pill);padding:3px 9px;margin-top:6px}
.pipeline__track{position:relative;height:40px;
  background:repeating-linear-gradient(90deg,transparent 0,transparent calc(100%/5 - 1px),var(--line) calc(100%/5 - 1px),var(--line) calc(100%/5))}
.pipeline__bar{position:absolute;top:50%;left:0;transform:translateY(-50%);height:24px;border-radius:7px;width:0;
  display:flex;align-items:center;justify-content:flex-end;padding:0 12px;white-space:nowrap;
  color:#fff;font-family:var(--font-display);font-weight:600;font-size:12px;transition:width 1.2s var(--ease)}
.pipeline.in .pipeline__bar{width:var(--w)}
.pipeline__bar--lead{height:30px;background:linear-gradient(90deg,var(--navy-700) 0%,var(--red-600) 100%);
  box-shadow:0 8px 20px rgba(187,32,37,.24)}
.pipeline__bar--mid{background:var(--navy-600)}
.pipeline__bar--soft{background:repeating-linear-gradient(45deg,var(--navy-400),var(--navy-400) 7px,#7f96b8 7px,#7f96b8 14px)}
.pipeline__bar--future{background:var(--navy-100);color:var(--navy-600);border:1px dashed var(--navy-300)}
.pipeline__ms{position:absolute;top:50%;transform:translate(-50%,-50%) rotate(45deg);width:13px;height:13px;
  background:#fff;border:2px solid var(--red-600);z-index:2;box-shadow:0 2px 6px rgba(13,31,54,.25)}
.pipeline__ms-lbl{position:absolute;top:-14px;font-family:var(--font-mono);font-size:10px;color:var(--red-600);
  white-space:nowrap;transform:translateX(-50%)}

/* ---- LATEST NEWS ---- */
.news{display:grid;grid-template-columns:1.5fr 1fr;gap:clamp(24px,3vw,40px);margin-top:clamp(34px,4vw,50px);align-items:start}
.newsfeature{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);
  overflow:hidden;box-shadow:var(--shadow-sm);transition:transform .22s var(--ease),box-shadow .22s,border-color .22s}
.newsfeature:hover{transform:translateY(-3px);box-shadow:var(--shadow-card-hover);border-color:var(--navy-300)}
.newsfeature__media{aspect-ratio:16/8;background:var(--navy-900);overflow:hidden}
.newsfeature__media img{width:100%;height:100%;object-fit:cover}
.newsfeature__body{padding:clamp(22px,2.4vw,30px)}
.news .meta{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--red-600)}
.news .meta time{color:var(--muted)}
.newsfeature h3{font-size:var(--fs-h2);font-weight:700;line-height:var(--lh-snug);margin-top:12px}
.newsfeature p{font-size:var(--fs-body);line-height:var(--lh-relaxed);color:var(--body);margin-top:12px}
.newsfeature .link-arrow{margin-top:20px}
.newslist{display:flex;flex-direction:column}
.newsitem{display:block;padding:20px 0;border-top:1px solid var(--line);color:inherit}
.newsitem:first-child{border-top:0;padding-top:0}
.newsitem h4{font-family:var(--font-display);font-weight:600;font-size:var(--fs-h4);color:var(--navy-700);line-height:var(--lh-snug);margin-top:8px;
  transition:color .2s}
.newsitem:hover h4{color:var(--red-600)}

@media (max-width:1040px){
  .news{grid-template-columns:1fr}
}
@media (max-width:760px){
  .pipeline__row{grid-template-columns:150px 1fr}
  .pipeline__chart{min-width:640px}
}

/* ---- HOW-IT-WORKS oversized fingerprint watermark ---- */
.workflow{position:relative;overflow:hidden}
.workflow > .wrap{position:relative;z-index:1}
@media (max-width:760px){ }

/* below ~820px the chart would scale its labels down to a few pixels —
   keep a legible minimum width and let the container scroll instead */
@media (max-width:820px){
  .signalviz{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .signalviz svg{min-width:800px}
}

/* signal graph as a soft, clearly-visible background behind the problem copy */
.problem{position:relative;overflow:hidden}
.problem > .wrap{position:relative;z-index:2}
.problem::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(92deg,rgba(255,255,255,0) 34%,rgba(255,255,255,.22) 66%,rgba(255,255,255,.46) 100%)}
.signalviz--bg{position:absolute;inset:0;z-index:0;margin:0;display:flex;align-items:center;justify-content:center}
.signalviz--bg svg{width:min(1200px,108%);height:auto;opacity:.62}
.signalviz--bg text,.signalviz--bg rect{display:none}
@media (max-width:820px){
  .problem::after{background:rgba(255,255,255,.45)}
  .signalviz--bg svg{opacity:.4;width:150%}
}


/* ============================================================================
   SLAMseq® 5-step flow — number + heading above image, explanation below
   ============================================================================ */
.slamflow{display:grid;grid-template-columns:repeat(4,1fr) 1.3fr;gap:clamp(18px,2.2vw,30px);
  margin-top:clamp(30px,3.6vw,44px)}
.slamstep{position:relative}
.slamstep__head{min-height:64px}
.slamstep__n{display:block;font-family:var(--font-mono);font-size:12px;color:var(--red-600);letter-spacing:.06em}
.slamstep__t{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--navy-700);
  line-height:1.25;margin-top:5px;letter-spacing:-.01em}
.slamstep__fig{position:relative;height:152px;display:flex;align-items:center;justify-content:center;
  background:#fff;border:1px solid var(--line);border-radius:var(--radius-md);padding:10px;margin-top:6px}
.slamstep__fig img{max-width:100%;max-height:100%;width:auto;object-fit:contain}
/* SLAMseq step figures — drawn in the page's own language: line work, navy for
   RNA already in the cell, red for RNA made during the labelling window. */
.slamfig{display:block;width:100%;height:100%}
.slamfig .sf-cell{fill:var(--navy-50);stroke:var(--navy-300);stroke-width:1.3}
.slamfig .sf-memb{fill:none;stroke:var(--navy-200);stroke-width:1}
.slamfig .sf-rna{fill:none;stroke:var(--navy-400);stroke-width:1.7;stroke-linecap:round}
.slamfig .sf-rna--new{stroke:var(--red-600)}
.slamfig .sf-mark{fill:var(--red-600)}
/* markers sit on top of the strands, so the labels carry a white halo —
   same paint-order trick as the homepage timeline captions */
.slamfig .sf-tag{font-family:var(--font-mono);font-weight:600;font-size:10.5px;fill:var(--red-600);
  paint-order:stroke;stroke:#fff;stroke-width:2.8;stroke-linejoin:round}
/* the reads sit on a plain white card and run at the font's natural 0.6em
   pitch, so no halo here — it would bleed white into the T-to-C highlights */
.slamfig .sf-base{font-family:var(--font-mono);font-size:11px;fill:var(--navy-600)}
.slamfig .sf-base--old{fill:var(--navy-300)}
.slamfig .sf-base--hl{fill:#fff}
.slamfig .sf-hl{fill:var(--red-600)}
.slamfig .sf-rule{stroke:var(--line);stroke-width:1}
.slamfig .sf-grp--old{fill:var(--navy-200)}
.slamfig .sf-grp--new{fill:var(--red-600)}
/* flow arrow sits in the gutter, auto-centred on the figure */
.slamstep__fig::after{content:"";position:absolute;top:50%;right:calc(-1 * clamp(18px,2.2vw,30px) / 2);
  width:11px;height:11px;border-top:2px solid var(--navy-300);border-right:2px solid var(--navy-300);
  transform:translate(50%,-50%) rotate(45deg)}
.slamstep:last-child .slamstep__fig::after{display:none}
.slamstep__d{font-size:13.5px;line-height:1.55;color:var(--body);margin-top:12px}

@media (max-width:1040px){
  .slamflow{grid-template-columns:repeat(3,1fr);gap:28px}
  .slamstep__fig::after{display:none}
  .slamstep__head{min-height:0}
}
@media (max-width:720px){
  .slamflow{grid-template-columns:1fr;gap:30px}
  .slamstep__fig{height:140px}
}

/* ============================================================================
   ASSAY FORMAT CARDS
   ============================================================================ */
.assays{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2.2vw,26px);margin-top:clamp(32px,4vw,48px)}
.assay{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:clamp(24px,2.6vw,32px);overflow:hidden;display:flex;flex-direction:column;
  transition:transform .22s var(--ease),box-shadow .22s,border-color .22s}
.assay:hover{transform:translateY(-3px);box-shadow:var(--shadow-card-hover);border-color:var(--navy-300)}
.assay__badge{display:inline-block;align-self:flex-start;font-family:var(--font-mono);font-size:12.5px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--navy-600);background:var(--navy-50);
  border-radius:var(--radius-pill);padding:5px 12px}
.assay--c .assay__badge{color:var(--red-600);background:var(--red-50)}
.assay__name{font-family:var(--font-display);font-weight:700;font-size:1.35rem;color:var(--navy-700);
  margin-top:14px;letter-spacing:-.02em}
.assay__readout{margin-top:18px;padding-top:18px;border-top:1px solid var(--line)}
.assay__num{display:block;font-family:var(--font-display);font-weight:800;letter-spacing:-.03em;line-height:1;
  font-size:clamp(1.9rem,1.5rem + 1.2vw,2.6rem);color:var(--navy-700)}
.assay--c .assay__num{color:var(--red-600)}
.assay__unit{display:block;font-family:var(--font-mono);font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin-top:8px}
.assay__meters{margin-top:20px;display:grid;gap:11px}
.assay__meters div{display:grid;grid-template-columns:46px 1fr;gap:10px;align-items:center}
.assay__meters span{font-family:var(--font-mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.assay__meters i{display:block;height:5px;border-radius:3px;background:var(--navy-100);position:relative}
.assay__meters i::after{content:"";position:absolute;left:0;top:0;bottom:0;width:0;border-radius:3px;
  background:var(--navy-600);transition:width 1s var(--ease)}
.assay__meters .m-depth i::after{background:var(--red-600)}
.in .assay__meters i::after,.no-js .assay__meters i::after{width:var(--v)}
.assay__facts{margin-top:20px;padding-top:18px;border-top:1px solid var(--line)}
.assay__facts b{display:block;font-family:var(--font-mono);font-size:9.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);margin-bottom:5px}
.assay__facts p{font-size:14px;line-height:1.55;color:var(--body)}
.assay__facts b + p + b{margin-top:14px}
@media (max-width:900px){ .assays{grid-template-columns:1fr} }

/* Closing CTA band — a lighter blue so it reads as its own section
   instead of merging into the navy-900 footer directly beneath it.
   Echoes the hero gradient, bookending the page. */
.sec--cta{background:linear-gradient(135deg,#25507a 0%,#1c3f68 52%,#173659 100%)}

/* ============================================================================
   Full-viewport hero — always fills the space above the fold
   (--nav-h is measured at runtime in site.js; 66px is the fallback)
   ============================================================================ */
.hero{min-height:calc(100vh - var(--nav-h,77px));min-height:calc(100svh - var(--nav-h,77px));
  display:flex;flex-direction:column;justify-content:center}
/* heroFit() measures how far the copy runs into one of the field's own labels
   and lifts it by exactly that, clamped so it never crowds the top. Nothing
   moves where there is no collision, which is every viewport from ~1900px up. */
.hero > .wrap{width:100%;transform:translateY(calc(-1 * var(--hero-lift,0px)))}

/* ============================================================================
   Timing comparison (measurement-gap section)
   ============================================================================ */
.timing{position:relative;padding-left:30px}
.timing::before{content:"";position:absolute;left:5px;top:9px;bottom:34px;width:2px;
  background:linear-gradient(180deg,var(--red-600) 0%,var(--navy-300) 100%)}
.timing__start{position:relative;font-family:var(--font-mono);font-size:11.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--navy-700);margin-bottom:20px}
.timing__start::before{content:"";position:absolute;left:-30px;top:3px;width:12px;height:12px;
  border-radius:50%;background:#fff;border:2px solid var(--red-600)}
.timing__card{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:clamp(20px,2.2vw,26px);box-shadow:var(--shadow-sm);
  transition:transform .22s var(--ease),box-shadow .22s,border-color .22s}
.timing__card + .timing__card{margin-top:18px}
.timing__card:hover{transform:translateY(-2px);box-shadow:var(--shadow-md);border-color:var(--navy-300)}
.timing__card::before{content:"";position:absolute;left:-31px;top:26px;width:10px;height:10px;border-radius:50%;
  background:var(--navy-300);border:2px solid var(--surface)}
.timing__card--q::before{background:var(--red-600)}
.timing__head{display:flex;align-items:center;gap:9px;color:var(--navy-400)}
.timing__card--q .timing__head{color:var(--red-600)}
.timing__head svg{width:17px;height:17px;flex:none}
.timing__time{font-family:var(--font-mono);font-size:12.5px;letter-spacing:.06em}
.timing__card h3{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h4);
  color:var(--navy-700);margin-top:11px}
.timing__card p{font-size:14px;line-height:1.55;color:var(--body);margin-top:5px}
@media (max-width:1040px){ .timing{margin-top:8px} }

/* ============================================================================
   Graph cutouts — the two cards are literal crops of the homepage branching
   timeline. Both windows are the same size (300 x 125 user units) so the pair
   is one graph at one magnification, read at two points in time: the strands
   run off every edge because the picture continues beyond the frame.
   ============================================================================ */
.sigcut{display:block;width:100%;height:auto;margin-top:16px;
  border:1px solid var(--line);border-radius:10px;
  background:linear-gradient(180deg,#fcfdff 0%,#f2f7fc 100%)}
.timing__card--q .sigcut{border-color:rgba(187,32,37,.16);
  background:linear-gradient(180deg,#fffcfc 0%,#fdf4f4 100%)}
.sigcut .cut-br path{fill:none;stroke-linecap:round}
.sigcut .cut-tip{fill:var(--sky);opacity:.72}
.sigcut .cut-ring{fill:none;stroke:var(--red-400);stroke-width:1.4;stroke-dasharray:4 5;opacity:.9}
.cut-guide{stroke:var(--navy-400);stroke-width:1;stroke-dasharray:3 3.5;opacity:.45;
  vector-effect:non-scaling-stroke}
.cut-guide--q{stroke:var(--red-400);opacity:.6}

/* ============================================================================
   Pipeline page — fuller chart + programme evidence
   ============================================================================ */
/* chart gains a third column carrying the public milestone */
.pipeline--full .pipeline__chart{min-width:920px}
.pipeline--full .pipeline__row{grid-template-columns:236px 1fr 214px}
.pipeline__note{font-size:12.5px;line-height:1.45;color:var(--body);padding-left:20px}
.pipeline__label .sub{font-size:12px;color:var(--muted);display:block;margin-top:3px}

/* three-column evidence strip (only for columns holding real data/imagery) */

/* milestone progress strip */

/* evidence bullets + stage pair */
.factlist{list-style:none;padding:0;margin:22px 0 0}
.factlist li{display:grid;grid-template-columns:auto 1fr;gap:12px;padding:12px 0;
  border-top:1px solid var(--line);font-size:15px;line-height:1.5;color:var(--body)}
.factlist li::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--red-600);margin-top:7px}

@media (max-width:900px){ }
@media (max-width:760px){
  .pipeline--full .pipeline__row{grid-template-columns:150px 1fr 160px}
}

/* ---- sub-heading inside a section ---- */
.subhead{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h4);color:var(--navy-700);
  padding-top:clamp(30px,3.6vw,44px);margin-top:clamp(30px,3.6vw,44px);border-top:1px solid var(--line)}
.sec--navy .subhead{color:#fff;border-top-color:rgba(133,200,252,.18)}

/* ---- dark-section variants of the milestone strip and evidence columns ---- */

/* ============================================================================
   Interactive body map — pipeline expansion
   ============================================================================ */
.bodymap{margin-top:clamp(34px,4.4vw,56px)}
.bodymap__stage{position:relative;height:640px;max-width:var(--container);margin:0 auto}
.bodymap__sil{position:absolute;left:50%;top:0;height:100%;width:auto;transform:translateX(-50%);
  opacity:.5;pointer-events:none;user-select:none}

.bmnode{position:absolute;top:var(--y);display:flex;align-items:center;gap:14px}
.bmnode--l{right:calc(50% + 132px);flex-direction:row-reverse;text-align:right}
.bmnode--r{left:calc(50% + 132px)}
/* connector stub pointing at the body */
.bmnode__btn{position:relative;flex:none;width:78px;height:78px;border-radius:50%;cursor:pointer;padding:0;
  background:rgba(6,26,48,.72);border:1px solid rgba(133,200,252,.32);
  display:flex;align-items:center;justify-content:center;
  transition:border-color .2s var(--ease),background .2s,transform .2s}
.bmnode__btn img{width:38px;height:38px;object-fit:contain}
.bmnode__btn:hover,.bmnode.is-open .bmnode__btn{background:rgba(39,124,224,.22);border-color:var(--sky);transform:scale(1.06)}
.bmnode__lbl b{display:block;font-family:var(--font-display);font-weight:700;font-size:15.5px;color:#fff;line-height:1.2}

/* information panel */
.bmpanel{position:absolute;width:300px;z-index:5;opacity:0;visibility:hidden;transform:translateY(-6px);
  background:rgba(9,26,46,.97);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border:1px solid rgba(133,200,252,.3);border-radius:var(--radius-lg);padding:20px 22px;text-align:left;
  box-shadow:0 22px 50px rgba(0,0,0,.5);transition:opacity .2s var(--ease),transform .2s var(--ease),visibility .2s}
.bmnode.is-open .bmpanel{opacity:1;visibility:visible;transform:translateY(0)}
/* The panel layer fills the stage and the panel centres in it, so a panel
   always opens over the map and inside its own column. It used to hang off its
   node, which needed room beside the silhouette — room a full-width section had
   and a half-width column does not. */
.bodymap__panels{position:absolute;inset:0;z-index:30;pointer-events:none}
.bodymap__panels .bmpanel{position:absolute;left:50%;top:50%;right:auto;bottom:auto;
  width:min(340px,84%);max-height:86%;overflow:auto;pointer-events:auto;
  transform:translate(-50%,-50%) translateY(-6px)}
.bodymap__panels .bmpanel.is-open{opacity:1;visibility:visible;
  transform:translate(-50%,-50%)}
.bmpanel__close{position:absolute;top:6px;right:10px;width:30px;height:30px;
  display:grid;place-items:center;border:0;background:none;cursor:pointer;
  font-size:22px;line-height:1;color:rgba(255,255,255,.62)}
.bmpanel__close:hover{color:#fff}
.bmpanel__t{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h4);color:#fff}
.bmpanel p{font-size:13.5px;line-height:1.55;color:rgba(255,255,255,.76);margin-top:12px}
.bmpanel dl{margin:14px 0 0;padding-top:12px;border-top:1px solid rgba(133,200,252,.2)}
.bmpanel dt{font-family:var(--font-mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;
  display:flex;align-items:center;gap:7px;margin-top:14px}
.bmpanel dt:first-child{margin-top:0}
.bmpanel dt::before{content:"";width:8px;height:8px;border-radius:2px;flex:none}
/* new targets read warm and filled; established read cool and outlined, so the
   two groups separate at a glance without needing to read the labels */
.bmpanel dt.new{color:var(--coral)}
.bmpanel dt.new::before{background:var(--coral)}
.bmpanel dt.est{color:rgba(133,200,252,.85)}
.bmpanel dt.est::before{border:1.5px solid rgba(133,200,252,.75)}
.bmpanel dd{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 0}
.bmpanel dd span{font-family:var(--font-display);font-weight:600;font-size:12.5px;line-height:1.35;
  border-radius:var(--radius-pill);padding:3px 10px}
.bmpanel dd.new span{color:#ffdcdc;background:rgba(255,107,116,.18);border:1px solid rgba(255,107,116,.5)}
.bmpanel dd.est span{color:rgba(255,255,255,.9);background:rgba(133,200,252,.09);border:1px solid rgba(133,200,252,.32)}

@media (max-width:1040px){
  .bodymap__stage{height:560px}
  .bmnode--l{right:calc(50% + 112px)} .bmnode--r{left:calc(50% + 112px)}
  .bmnode__btn{width:64px;height:64px} .bmnode__btn img{width:31px;height:31px}
    .bmpanel{width:260px}
}
/* stacked list on small screens — same markup, no absolute positioning */
@media (max-width:820px){
  .bodymap__sil{display:none}
  .bodymap__stage{height:auto;display:flex;flex-direction:column;gap:10px}
  .bmnode{position:static;flex-direction:row;text-align:left;gap:14px;flex-wrap:wrap;
    border:1px solid rgba(133,200,252,.22);border-radius:var(--radius-lg);padding:14px}
  .bmnode__btn{width:56px;height:56px} .bmnode__btn img{width:28px;height:28px}
  .bmpanel{position:static;width:auto;opacity:1;visibility:visible;transform:none;display:none;
    flex-basis:100%;box-shadow:none;background:rgba(133,200,252,.06);margin-top:12px}
  .bmnode.is-open .bmpanel{display:block}
}
/* full desktop only: the panel has room, so set it a size up. Widened to match
   so the extra type buys readability rather than extra panel height. */
@media (min-width:1041px){
  .bmpanel{width:330px;padding:22px 24px}
  .bmpanel__t{font-size:1.15rem}
  .bmpanel p{font-size:14.5px;line-height:1.6;margin-top:13px}
  .bmpanel dt{font-size:10.5px}
  .bmpanel dd span{font-size:13.5px;padding:4px 11px}
}
/* The panel is a <dialog> now, so it can open modally on a phone. On a pointer
   screen it is still shown in place beside its node, which means undoing the
   element default of display:none and the browser chrome that comes with it. */
.bmpanel{display:block;border:0;margin:0;max-width:none;max-height:none;color:inherit}
.bmpanel__close{display:none}

@media (max-width:820px){
  /* card mode: the whole card is the target, not the icon */
  .bmnode{position:relative}
  .bmnode__btn::after{content:"";position:absolute;inset:0;border-radius:inherit}
  .bmnode__btn:focus-visible::after{outline:2px solid var(--sky);outline-offset:2px}
  /* closed dialogs stay out of the flow; open ones are the modal */
  .bmpanel:not([open]){display:none}
  .bmpanel[open]{position:fixed;inset:0;width:auto;height:auto;
    margin:auto;max-width:min(440px,calc(100vw - 32px));max-height:calc(100dvh - 96px);
    overflow:auto;padding:24px 22px;border-radius:var(--radius-lg);
    background:var(--navy-800);box-shadow:0 24px 60px rgba(2,10,22,.5);
    opacity:1;visibility:visible;transform:none;flex-basis:auto;margin-top:auto}
  .bmpanel::backdrop{background:rgba(3,12,26,.72)}
  .bmpanel__close{display:block;position:absolute;top:10px;right:12px;
    background:none;border:0;color:rgba(233,241,251,.7);font-size:26px;line-height:1;
    padding:4px 8px;cursor:pointer}
  .bmpanel__close:hover{color:#fff}
  .bmnode.is-open .bmpanel:not([open]){display:none}
}

/* anatomical connector lines — same box as the silhouette, so they scale with it */
.bodymap__links{position:absolute;left:50%;top:0;height:100%;width:auto;transform:translateX(-50%);
  overflow:visible;pointer-events:none;z-index:0}
.bodymap__links line{stroke:rgba(133,200,252,.42);stroke-width:1;vector-effect:non-scaling-stroke;
  transition:stroke .2s var(--ease)}
.bodymap__links circle{fill:rgba(133,200,252,.75);transition:fill .2s var(--ease),r .2s var(--ease)}
.bodymap__links .is-active line{stroke:var(--sky)}
.bodymap__links .is-active circle{fill:#fff;r:3.6}
.bmnode{z-index:1}
@media (max-width:820px){ .bodymap__links{display:none} }

/* ---- pipeline chart: no stage header, so the track can use the freed width ---- */
.pipeline--full .pipeline__chart{min-width:760px}
.pipeline--full .pipeline__row:first-child{border-top:0}
/* short bars put their label outside, to the right, instead of overflowing left */
.pipeline__bar--outlabel{justify-content:flex-start;padding:0;overflow:visible}
.pipeline__bar--outlabel > span{position:absolute;left:calc(100% + 12px);white-space:nowrap;
  color:var(--navy-600);font-family:var(--font-display);font-weight:600;font-size:12px}
/* programme names that jump to their detail section */
.pipeline__label a{color:var(--navy-700);border-bottom:1px solid transparent;
  transition:color .2s var(--ease),border-color .2s var(--ease)}
.pipeline__label a i{font-style:normal;color:var(--red-600);font-size:12px;opacity:.75}
.pipeline__label a:hover{color:var(--red-600);border-bottom-color:rgba(187,32,37,.4)}
.pipeline__label a:hover i{opacity:1}

/* ---- nav sizing fixes ----
   The logo anchor is a flex item; without flex:none it gets shrunk and the
   global img{max-width:100%} then squashes the logo out of aspect ratio. */
.nav > a{flex:none}

/* Each .bmnode is its own stacking context (z-index:1), so the open one is
   lifted clear of its neighbours — otherwise a later marker in DOM order paints
   over it. The panels layer sits above this (z-index:30): the panel is no longer
   a child of its node, so it no longer rides the node's stacking context and has
   to outrank it explicitly. The opaque background stops the silhouette showing
   through the card. */
.bmnode.is-open{z-index:20}
.bmpanel{background:#0a1e36}

/* ============================================================================
   About page — company highlights + roster lists
   ============================================================================ */
/* Figure over label, stacked. The old side-by-side grid put a nowrap display
   number next to its caption, so a long value ("Around €500 million") forced
   the panel wider than its column and collided with the label. Stacking lets
   the value use the full width and wrap when it needs to. */
.highlights{background:var(--surface-sunken);border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:clamp(26px,2.8vw,36px)}
.highlights dl{margin:20px 0 0}
.highlights .row{padding:18px 0;border-top:1px solid var(--line)}
.highlights .row:first-child{border-top:0;padding-top:0}
.highlights .row:last-child{padding-bottom:0}
.highlights dt{font-family:var(--font-display);font-weight:800;letter-spacing:var(--ls-tight);
  line-height:1.05;color:var(--navy-700);font-size:clamp(1.5rem,1.15rem + 1.05vw,2.1rem)}
.highlights dd{margin:7px 0 0;font-family:var(--font-mono);font-size:11.5px;letter-spacing:.09em;
  text-transform:uppercase;line-height:1.5;color:var(--muted)}

/* board / advisor rosters — text only, so management keeps the visual weight */
.rosters{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,4vw,56px);margin-top:clamp(34px,4vw,50px);
  padding-top:clamp(30px,3.6vw,44px);border-top:1px solid var(--line)}
.roster h3{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h4);color:var(--navy-700)}
.roster ul{list-style:none;padding:0;margin:16px 0 0}
.roster li{padding:13px 0;border-top:1px solid var(--line);font-size:16.5px;line-height:1.5}
.roster li:first-child{border-top:0}
.roster b{font-family:var(--font-display);font-weight:600;color:var(--navy-700);display:block}
.roster span{color:var(--muted);font-size:14.5px}

.figure--photo img{width:100%;height:100%;object-fit:cover;display:block}
.figcaption{font-family:var(--font-mono);font-size:11px;color:var(--muted);margin-top:10px;letter-spacing:.03em}

@media (max-width:820px){ .rosters{grid-template-columns:1fr} }

/* ---- hero with a highlights panel alongside ---- */
.hero-split{display:grid;grid-template-columns:1.12fr .88fr;gap:clamp(36px,5vw,72px);align-items:center}
.hero .highlights{background:rgba(133,200,252,.07);border-color:rgba(133,200,252,.24)}
.hero .highlights .eyebrow{color:var(--sky)}
.hero .highlights .row{border-top-color:rgba(133,200,252,.18)}
.hero .highlights dt{color:#fff}
.hero .highlights dd{color:rgba(133,200,252,.85)}
@media (max-width:900px){ .hero-split{grid-template-columns:1fr;gap:32px} }

/* ---- roster entries carry portraits at a size you can actually read a face
       at. Still well short of the 300px management portraits, so the hierarchy
       holds — these columns are over 500px wide, so the old 46px thumbnail was
       leaving most of that room unused. ---- */
.roster li{display:grid;grid-template-columns:76px 1fr;gap:18px;align-items:center}
.roster img{width:76px;height:76px;border-radius:50%;object-fit:cover;background:var(--navy-100);display:block}

/* ---- simplified pipeline teaser ---- */
.minipipe{margin-top:4px}
.minipipe__row{padding:15px 0;border-top:1px solid rgba(133,200,252,.16)}
.minipipe__row:last-child{padding-bottom:0}
.minipipe__row:first-child{border-top:0;padding-top:0}
.minipipe__lbl{display:flex;justify-content:space-between;align-items:baseline;gap:14px;margin-bottom:9px}
.minipipe__lbl b{font-family:var(--font-display);font-weight:700;font-size:14px;color:#fff}
.minipipe__lbl em{font-style:normal;font-family:var(--font-mono);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:rgba(133,200,252,.8);white-space:nowrap}
.minipipe__track{display:block;height:10px;border-radius:5px;background:rgba(133,200,252,.12);position:relative}
.minipipe__bar{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:5px;transition:width 1.1s var(--ease)}
.in .minipipe__bar,.no-js .minipipe__bar{width:var(--w)}
.minipipe__bar--lead{background:linear-gradient(90deg,var(--sky),var(--red-500))}
.minipipe__bar--mid{background:var(--azure)}
.minipipe__bar--soft{background:repeating-linear-gradient(45deg,rgba(133,200,252,.5),rgba(133,200,252,.5) 5px,rgba(133,200,252,.26) 5px,rgba(133,200,252,.26) 10px)}
/* the expansion row: not started, so it reads as an outline rather than a fill —
   the dark-background counterpart of .pipeline__bar--future */
.minipipe__bar--future{background:rgba(133,200,252,.10);border:1px dashed rgba(133,200,252,.45)}
/* the teaser chart had an axis with a label at each end; the bars carry their
   own stage names, so the axis said nothing the rows did not */

/* Grid items default to min-width:auto and refuse to shrink below their
   min-content width — which pushed the hero column wider than its container
   on narrow screens. Let the columns shrink, and let long stat labels wrap. */
.hero-split > *,.split > *,.leadin > *{min-width:0}

/* ============================================================================
   News & Events page
   ============================================================================ */
.newstop{display:grid;grid-template-columns:1.5fr 1fr;gap:clamp(24px,3vw,40px);align-items:start;
  margin-top:clamp(30px,3.6vw,44px)}

/* featured press release */
.prfeat{display:block;background:#fff;border:1px solid var(--line);
  border-radius:0 var(--radius-lg) var(--radius-lg) 0;padding:clamp(26px,3vw,38px);color:inherit;
  box-shadow:var(--shadow-sm);transition:transform .22s var(--ease),box-shadow .22s,border-color .22s}
.prfeat:hover{transform:translateY(-3px);box-shadow:var(--shadow-card-hover)}
.prmeta{display:flex;align-items:center;gap:10px;font-family:var(--font-mono);font-size:11.5px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.prmeta .tag{background:var(--red-50);color:var(--red-600);border-radius:var(--radius-pill);padding:4px 11px}
.prfeat__t{font-size:clamp(1.35rem,1.1rem + 1vw,1.9rem);line-height:var(--lh-snug);font-weight:700;margin-top:14px}
.prfeat p{font-size:var(--fs-body);line-height:var(--lh-relaxed);color:var(--body);margin-top:12px;max-width:62ch}
.prfeat .link-arrow{margin-top:20px}

/* upcoming events panel */
.events{background:var(--surface-sunken);border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:clamp(24px,2.6vw,32px)}
.events__list{margin-top:18px}
.event{padding:18px 0;border-top:1px solid var(--line)}
.event:first-child{border-top:0;padding-top:0}
.event__t{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h4);color:var(--navy-700);line-height:1.25}
.event .when{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.05em;color:var(--red-600);margin-top:7px}
.event p{font-size:13.5px;line-height:1.55;color:var(--body);margin-top:9px}
.event .link-arrow{font-size:13.5px;margin-top:11px}
.events__empty{padding-top:4px}
.events__empty p{font-size:14px;line-height:1.6;color:var(--body)}
.events__empty p + p{margin-top:10px}

/* press-release archive */
/* publications — same rhythm as the press-release archive, but these are
   citations, not links, so no hover state and no "read more" affordance */
.publist{list-style:none;margin-top:clamp(28px,3.4vw,40px);border-top:1px solid var(--line)}
.publist li{display:grid;grid-template-columns:150px 1fr;gap:clamp(18px,2.4vw,34px);
  padding:clamp(22px,2.4vw,30px) 0;border-bottom:1px solid var(--line)}
.publist .yr{font-family:var(--font-mono);font-size:12.5px;letter-spacing:.05em;color:var(--muted)}
.publist .yr em{display:block;font-style:normal;font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--red-600);margin-top:6px;line-height:1.4}
.publist h3{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h3);
  color:var(--navy-700);line-height:var(--lh-snug)}
.publist .ref{font-family:var(--font-mono);font-size:12px;color:var(--navy-500);margin-top:8px}
.publist .ref + p{font-size:var(--fs-body-sm);line-height:var(--lh-relaxed);color:var(--body);
  margin-top:10px;max-width:70ch}
@media (max-width:720px){ .publist li{grid-template-columns:1fr;gap:6px} }

.prlist{margin-top:clamp(28px,3.4vw,40px);border-top:1px solid var(--line)}
.pritem{display:grid;grid-template-columns:150px 1fr auto;gap:clamp(18px,2.4vw,34px);align-items:baseline;
  padding:clamp(22px,2.4vw,30px) 0;border-bottom:1px solid var(--line);color:inherit;
  transition:background .2s var(--ease)}
.pritem:hover{background:var(--surface-sunken)}
.pritem time{font-family:var(--font-mono);font-size:12.5px;letter-spacing:.05em;color:var(--muted);white-space:nowrap}
.pritem__t{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h3);color:var(--navy-700);line-height:var(--lh-snug)}
.pritem p{font-size:var(--fs-body-sm);line-height:var(--lh-relaxed);color:var(--body);margin-top:8px;max-width:70ch}
.pritem .go{font-family:var(--font-display);font-weight:600;font-size:14px;color:var(--red-600);white-space:nowrap}
.pritem:hover .go{color:var(--red-700)}

@media (max-width:1040px){ .newstop{grid-template-columns:1fr} }
@media (max-width:700px){
  .pritem{grid-template-columns:1fr;gap:6px}
  .pritem .go{margin-top:10px}
}

/* ---- page header for pages that start straight into content (no hero) ---- */
.sec--first{padding-top:clamp(52px,6.5vw,88px)}
/* The wrap resets every direct child group to max-width:none at (0,2,0), which
   outranked this at (0,1,0) — so the page head ran the full width and its lede
   set across both columns below it. Matched here so it wins. */
.wrap > .pagehead,.pagehead{max-width:64ch}
.pagehead h1{font-size:var(--fs-display-lg);line-height:var(--lh-snug);margin-top:16px}
.pagehead .lede,.pagehead .is-style-lede{margin-top:18px}

/* ============================================================================
   WORDPRESS INTEGRATION
   The design system above is unchanged; this section maps core block markup
   onto it so editors work with normal WordPress blocks and menus.
   ============================================================================ */

/* the site header is a template part built from core blocks */
.nav .wp-block-navigation__container{display:flex;gap:26px;align-items:center;
  font-family:var(--font-display);font-weight:500;font-size:14.5px}
.nav .wp-block-navigation-item__content{position:relative;color:rgba(234,241,251,.82);text-decoration:none}
.nav .wp-block-navigation-item__content:hover,
.nav .current-menu-item > .wp-block-navigation-item__content{color:#fff}
.nav .wp-block-navigation-item__content::after{content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;
  background:var(--red-logo);transform:scaleX(0);transform-origin:left;transition:transform .2s var(--ease)}
.nav .wp-block-navigation-item__content:hover::after,
.nav .current-menu-item > .wp-block-navigation-item__content::after{transform:scaleX(1)}
.nav .wp-block-navigation__responsive-container-open,
.nav .wp-block-navigation__responsive-container-close{color:#fff}
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container{
  flex-direction:column;align-items:flex-start;gap:6px;font-size:1.15rem}
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content{color:#fff}
/* The three things in the bar are each sized by something different — the logo
   by its own box, the menu by its text line, the CTA by its padding box — so
   each is given a flex box to centre its content in and the bar centres those
   against one another. That puts them on one midline whatever their heights. */
.nav > *{display:flex;align-items:center;margin:0}
.nav .wp-block-site-logo img{height:clamp(38px,4.4vw,52px);width:auto;display:block}
.nav .wp-block-site-logo{flex:none;line-height:0}
/* Below core's navigation breakpoint the nav collapses to its menu button,
   which sits between the logo and the CTA in source order. Reorder so the
   button is the last thing in the bar and the CTA groups with it. */
@media (max-width:599px){
	.nav .nav__links{order:3}
	.nav .nav__right{order:2;margin-left:auto}
}

/* header CTA rendered as a core button */
.nav .wp-block-button__link{background:var(--red-logo);color:#fff;font-size:13.5px;font-weight:600;
  padding:10px 20px;border-radius:var(--radius-pill);white-space:nowrap;text-decoration:none;box-shadow:none}
.nav .wp-block-button__link:hover{background:#8f1213;color:#fff}

/* The header needed 428px on a 390px phone — logo, a 20-character CTA, the menu
   button and the gaps between them. iOS answers an over-wide page by shrinking
   the whole document to fit, which is where the white gutter down the right and
   the half-cut menu button came from. The CTA carries a short label below the
   breakpoint; nothing else had to move. */
.nav__cta-short{display:none}
@media (max-width:560px){
  .nav__cta-long{display:none}
  .nav__cta-short{display:inline}
  .nav .wp-block-button__link{padding:10px 18px}
}

/* core buttons elsewhere pick up the existing button system */
.wp-block-button.is-style-primary .wp-block-button__link{background:var(--red-600);color:#fff;
  box-shadow:0 8px 22px rgba(187,32,37,.26)}
.wp-block-button.is-style-primary .wp-block-button__link:hover{background:var(--red-700)}
.wp-block-button.is-style-dark .wp-block-button__link{background:var(--navy-700);color:#fff}
.wp-block-button.is-style-dark .wp-block-button__link:hover{background:var(--navy-800)}
.wp-block-button.is-style-on-dark .wp-block-button__link{background:rgba(133,200,252,.08);color:#fff;
  border:1px solid rgba(133,200,252,.4)}
.wp-block-button.is-style-on-dark .wp-block-button__link:hover{background:rgba(133,200,252,.16);border-color:var(--sky)}
.wp-block-button.is-style-ghost .wp-block-button__link{background:transparent;color:var(--navy-700);
  border:1px solid rgba(24,55,94,.32)}
.wp-block-buttons{gap:14px}

/* group style variations mapped to the band system */
.wp-block-group.is-style-sunken{background:var(--surface-sunken)}
.wp-block-group.is-style-navy{background:linear-gradient(158deg,#1f4472,#0d1f36);color:#fff}
.wp-block-group.is-style-navy :is(h1,h2,h3,h4){color:#fff}
.wp-block-group.is-style-navy p{color:rgba(255,255,255,.8)}
.wp-block-group.is-style-cta{background:linear-gradient(135deg,#25507a 0%,#1c3f68 52%,#173659 100%);color:#fff}
.wp-block-group.is-style-cta :is(h1,h2,h3,h4){color:#fff}
.wp-block-group.is-style-note{border-left:3px solid var(--red-600);background:var(--red-50);
  border-radius:0 var(--radius-md) var(--radius-md) 0;padding:16px 20px;font-size:var(--fs-body-sm);color:var(--body)}

/* paragraph style variations */
p.is-style-eyebrow{font-family:var(--font-display);color:var(--red-600);font-size:var(--fs-eyebrow);
  font-weight:600;letter-spacing:.14em;text-transform:uppercase;margin:0}
.is-style-navy p.is-style-eyebrow,.is-style-cta p.is-style-eyebrow{color:var(--sky)}
p.is-style-lede{font-size:var(--fs-body-lg);line-height:var(--lh-relaxed);color:var(--body)}
.is-style-navy p.is-style-lede{color:rgba(255,255,255,.82)}

/* editor parity: the reveal animation must not hide content while editing */
.editor-styles-wrapper [data-reveal]{opacity:1;transform:none}
.editor-styles-wrapper .nav{position:static}
.editor-styles-wrapper .hero{min-height:520px}

/* WordPress core alignment helpers inside our sections */
.sec .alignwide{max-width:1360px;margin-left:auto;margin-right:auto}
.sec .alignfull{margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);max-width:100vw}

/* admin bar must not hide the sticky nav */
.admin-bar .nav{top:32px}
@media (max-width:782px){ .admin-bar .nav{top:46px} }

/* skip link */
.skip-link{position:absolute;left:-9999px;top:0;z-index:100;background:var(--navy-900);color:#fff;
  padding:12px 20px;border-radius:0 0 var(--radius-md) 0}
.skip-link:focus{left:0;color:#fff}

/* ============================================================================
   CORE LAYOUT RECONCILIATION
   WordPress ships its own layout CSS with higher specificity than the design
   system. These rules hand control back where the two disagree.
   ============================================================================ */

/* 1. Sticky header. The template part is wrapped in a plain div that is only
      as tall as the header itself, which gives position:sticky nothing to
      travel inside. display:contents removes the wrapper from layout. */
.wp-block-template-part{display:contents}

/* 2. No gaps between full-bleed sections. Core's flow layout puts a 24px
      block gap between every top-level child, which showed as white bars
      between the coloured bands. */
.wp-block-post-content > *,
main > .wp-block-post-content > .wp-block-group,
.wp-site-blocks > *{margin-block-start:0;margin-block-end:0}
.wp-block-post-content > * + *{margin-block-start:0}
main.wp-block-group{gap:0}

/* 3. Two-column layouts are grids in this design, not core's flex columns.
      Core's .wp-block-columns rules would otherwise force equal widths. */
.wp-block-columns.split,
.wp-block-columns.leadin,
.wp-block-columns.newstop,
.wp-block-columns.hero-split,
.wp-block-columns.steps,
.wp-block-columns.milestones,
.wp-block-columns.rosters{display:grid}
/* No align-items here: core ships .wp-block-columns{align-items:normal!important},
   which discards it whatever the specificity, so the columns stretch. To align a
   particular pair, set align-self on the columns — see .split--center. */
.wp-block-columns.split{grid-template-columns:1fr 1fr;gap:clamp(40px,5vw,72px)}
.wp-block-columns.split--wide-l{grid-template-columns:1.1fr .9fr}
/* Core sets align-items:normal!important on every .wp-block-columns, so a
   wrapper cannot align its own children whatever the specificity. align-self on
   the columns is uncontested — core only sets it for is-vertically-aligned-*. */
.wp-block-columns.split--center > .wp-block-column{align-self:center}
.wp-block-columns.leadin{grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,72px)}
/* align-self on the columns, not align-items on the wrapper: core ships
   .wp-block-columns{align-items:normal!important} and discards the latter. */
.wp-block-columns.leadin > .wp-block-column{align-self:end}
.wp-block-columns.leadin--top > .wp-block-column{align-self:start}
.wp-block-columns.newstop{grid-template-columns:1.5fr 1fr;gap:clamp(24px,3vw,40px)}
.wp-block-columns.newstop > .wp-block-column{align-self:start}
.wp-block-columns.steps{grid-template-columns:repeat(4,1fr);gap:clamp(20px,2.6vw,34px);margin-top:clamp(44px,5vw,64px)}
.wp-block-columns.milestones{grid-template-columns:repeat(4,1fr);gap:clamp(18px,2.4vw,32px)}
/* core sets a percentage flex-basis on every column; grid must ignore it */
.wp-block-columns.split > .wp-block-column,
.wp-block-columns.leadin > .wp-block-column,
.wp-block-columns.newstop > .wp-block-column,
.wp-block-columns.hero-split > .wp-block-column,
.wp-block-columns.steps > .wp-block-column,
.wp-block-columns.milestones > .wp-block-column,
.wp-block-columns.rosters > .wp-block-column{flex-basis:auto!important;min-width:0}
@media (max-width:900px){
  .wp-block-columns.split,.wp-block-columns.leadin,.wp-block-columns.newstop,
  .wp-block-columns.hero-split{grid-template-columns:1fr}
  .wp-block-columns.steps,.wp-block-columns.milestones{grid-template-columns:1fr 1fr}
}
@media (max-width:560px){ .wp-block-columns.steps{grid-template-columns:1fr} }
@media (max-width:480px){ .wp-block-columns.milestones{grid-template-columns:1fr} }

/* Milestones on a partnered programme: four fixed points, each a value over a
   caption. Deliberately not drawn as a timeline — the fourth is a sum, not a
   date — so they read as a row of facts. The sum takes the accent colour to
   mark it as the one item that is not a year. */
.milestones > .wp-block-column{border-top:2px solid var(--navy-200);padding-top:16px}
/* One size for all four values, chosen so the longest string still fits the
   narrowest four-column case: unequal sizes would leave the value boxes
   different heights and drop one caption out of line with the rest. */
.milestones__v{font-family:var(--font-display);font-weight:800;color:var(--navy-700);
  letter-spacing:var(--ls-tight);line-height:1;font-size:clamp(1.2rem,.72rem + 1.1vw,1.75rem);
  margin:0;white-space:nowrap}
/* the three dates are figures and must not break; the deal value is a phrase,
   so it wraps and balances instead of running out of its column */
.milestones__v--sum{color:var(--red-600);white-space:normal;text-wrap:balance}
.milestones__c{font-size:14px;line-height:1.45;color:var(--muted);margin:10px 0 0;max-width:24ch}

/* Secondary detail that supports a section without competing with its body. */
.sidenote{font-size:14.5px;line-height:1.65;color:var(--muted);border-left:2px solid var(--navy-200);
  padding-left:18px;max-width:74ch}

/* 4. Header legibility. Core doubles the navigation class to win the cascade
      (color:inherit), which left the links reading as body grey on navy. */
.nav .wp-block-navigation-item__content.wp-block-navigation-item__content{color:rgba(240,246,255,.92)}
.nav .wp-block-navigation-item__content.wp-block-navigation-item__content:hover,
.nav .current-menu-item > .wp-block-navigation-item__content.wp-block-navigation-item__content{color:#fff}
.nav .wp-block-navigation{font-family:var(--font-display);font-weight:500;font-size:14.5px}

/* 5. Core's constrained layout tries to re-centre content inside our wraps. */
.sec > .wp-block-group.wrap{max-width:var(--container);margin-inline:auto}
.wrap > .wp-block-group,.wrap > .wp-block-columns{max-width:none}

/* ============================================================================
   FOOTER — rebuilt
   Four columns plus a brand block, a proper logo lockup, and the funder marks
   sitting on their own row above a single legal line.
   ============================================================================ */
.footer{padding:clamp(64px,7vw,96px) clamp(20px,4.4vw,56px) clamp(32px,3.4vw,44px)}
.footer__grid{grid-template-columns:1.7fr repeat(3,1fr);gap:clamp(32px,4vw,56px) clamp(28px,3.4vw,48px)}
.footer__brand{max-width:340px}
/* the logo is an SVG with a 3.36:1 ratio — give it width, not a forced height */
.footer__brand .footer__mark{margin:0 0 20px}
.footer__brand .footer__mark img{width:168px;height:auto;display:block}
.footer__brand p{font-size:14px;line-height:1.7;color:rgba(255,255,255,.62);margin:0}
.footer__addr{margin-top:16px!important;font-size:13.5px;line-height:1.7;color:rgba(255,255,255,.5)}
.footer__addr a{color:rgba(255,255,255,.72)}
.footer__addr a:hover{color:#fff}
.footer__col{gap:0}
.footer__head{color:#fff;font-family:var(--font-display);font-weight:600;font-size:13px;
  letter-spacing:.1em;text-transform:uppercase;margin:0 0 14px}
.footer__col p{margin:0}
.footer__col p + p{margin-top:10px}
.footer__col a{color:rgba(255,255,255,.62);font-size:14px;text-decoration:none}
.footer__col a:hover{color:#fff}
.footer__legal{border-top:1px solid rgba(255,255,255,.11);margin-top:clamp(30px,3.4vw,40px);
  padding-top:24px;display:block;font-size:12.5px;color:rgba(255,255,255,.42);line-height:1.6}
.footer__legal p{margin:0;max-width:none}
.footer__logos{margin-top:clamp(38px,4.4vw,54px);padding-top:clamp(28px,3vw,36px)}
@media (max-width:1000px){ .footer__grid{grid-template-columns:1fr 1fr} .footer__brand{grid-column:1/-1;max-width:520px} }
@media (max-width:560px){ .footer__grid{grid-template-columns:1fr} }

/* ============================================================================
   SPACING RHYTHM
   One scale for section padding so bands stack predictably, and a consistent
   gap under every section heading group.
   ============================================================================ */
.sec{padding-block:clamp(72px,8.5vw,120px)}
.sec--first{padding-top:clamp(56px,6.5vw,92px)}
.sec > .wrap > * + *{margin-top:0}
/* the page head is a block of its own; whatever follows it needs its own gap,
   or the section runs straight into the heading */
.sec > .wrap > .pagehead + *{margin-top:clamp(34px,4.2vw,56px)}
.sec .wrap > .is-style-eyebrow + h2,
.sec .wrap > .is-style-eyebrow + .wp-block-heading{margin-top:16px}
.sec .wrap > h2 + .is-style-lede,
.sec .wrap > .wp-block-heading + .is-style-lede{margin-top:20px}
.sec .wrap > .is-style-lede + *{margin-top:clamp(30px,3.6vw,44px)}
/* a lede continued in a second paragraph is one argument, not two blocks */
.sec .wrap > .is-style-lede + .is-style-lede{margin-top:clamp(14px,1.5vw,20px)}
.sec .wrap > .wp-block-heading + .wp-block-columns,
.sec .wrap > .is-style-lede + .wp-block-columns,
.sec .wrap > * + .wp-block-quantro-pipeline-chart,
.sec .wrap > * + .wp-block-quantro-body-map,
.sec .wrap > * + .wp-block-quantro-assay-cards,
.sec .wrap > * + .wp-block-quantro-team,
.sec .wrap > * + .wp-block-quantro-publication-list,
.sec .wrap > * + .wp-block-quantro-press-list,
.sec .wrap > * + .wp-block-quantro-news-teaser,
.sec .wrap > * + .wp-block-quantro-slam-flow{margin-top:clamp(34px,4vw,52px)}
.sec .wrap > * + .wp-block-buttons,
.sec .wrap > * + p:has(.link-arrow){margin-top:clamp(28px,3.2vw,40px)}
.sec .wrap > .milestones + *{margin-top:clamp(34px,4vw,52px)}
.sec .wrap > * + .sidenote{margin-top:clamp(30px,3.4vw,44px)}
/* Science & Platform's newer parts. The rule above zeroes every sibling gap, so
   each of these has to name its own — without them the section runs together. */
.sec .wrap > * + .wp-block-quantro-signal-timeline{margin-top:clamp(34px,4vw,52px)}
.sec .wrap > .wp-block-heading + .shortfall{margin-top:clamp(20px,2.4vw,30px)}
.sec .wrap > * + .shortfall{margin-top:clamp(26px,3vw,36px)}
.sec .wrap > * + .bridge{margin-top:clamp(38px,4.4vw,58px)}
.sec .wrap > .is-style-lede + .wp-block-heading{margin-top:clamp(30px,3.4vw,44px)}
.wp-block-columns .wp-block-column > * + *{margin-top:16px}
.wp-block-columns .wp-block-column > .wp-block-heading + *{margin-top:20px}
.wp-block-columns .wp-block-column > * + .wp-block-buttons{margin-top:28px}

/* ============================================================================
   MISSION — full-width heading, two text columns beneath
   ============================================================================ */
.mission__head{max-width:26ch}
@media (max-width:820px){ }

/* ============================================================================
   FIGURE EMBED — framed photo with a caption bar rather than a bare image
   ============================================================================ */
.figframe{position:relative;border-radius:var(--radius-lg);overflow:hidden;
  box-shadow:0 30px 60px rgba(13,31,54,.18);background:var(--navy-900);margin:0}
.figframe img{width:100%;height:100%;object-fit:cover;display:block;aspect-ratio:4/3}
.figframe figcaption{position:absolute;left:0;right:0;bottom:0;margin:0;
  padding:36px 22px 16px;color:#fff;font-family:var(--font-mono);font-size:11.5px;
  letter-spacing:.04em;text-align:left;
  background:linear-gradient(to top,rgba(13,31,54,.86),rgba(13,31,54,0))}
@media (max-width:900px){ .figframe img{aspect-ratio:16/10} }

/* ============================================================================
   TEAM — bolder names, clearer separation
   ============================================================================ */
.team{gap:clamp(28px,3.2vw,44px) clamp(24px,2.8vw,36px)}
.team .member img{border-radius:var(--radius-lg);margin-bottom:18px}
.team .member h3{font-family:var(--font-display);font-weight:800;font-size:1.2rem;
  letter-spacing:-.015em;color:var(--navy-700);margin:0}
.team .member .role{font-family:var(--font-mono);font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--red-600);margin:8px 0 0;font-weight:500}
.team .member p:not(.role){font-size:14.5px;line-height:1.65;color:var(--body);margin-top:14px}
.subhead{font-family:var(--font-display);font-weight:800;color:var(--navy-700);
  letter-spacing:-.015em;margin-bottom:4px}
.rosters{margin-top:clamp(44px,5vw,68px);padding-top:clamp(34px,4vw,48px);border-top:1px solid var(--line)}
.roster ul{margin-top:20px}
.roster li{padding:16px 0}
.roster li b{font-weight:700}

/* ---- contact form ---- */
.contactform .field + .field{margin-top:18px}
.contactform label .req{color:var(--red-600);margin-left:2px}
.contactform .checkline{margin-top:22px}
.formerror{margin-top:16px;padding:12px 16px;border-radius:var(--radius-md);
  background:var(--red-50);border-left:3px solid var(--red-600);color:var(--red-700);
  font-size:var(--fs-body-sm);line-height:1.5}
.formactions{margin-top:26px;display:flex;align-items:center;gap:16px;flex-wrap:wrap}

/* ---- Contact Form 7 ----
   The form template keeps the theme's own classes, so nearly all of the styling
   above already applies. What is left is CF7's own scaffolding: it wraps each
   control in a span, which would otherwise sit in the .field flex column as a
   bare box, and it appends status and validation output that needs to read as
   part of this form rather than as the plugin's default. */
.contactform .wpcf7-form-control-wrap{display:block}
.contactform .field input,
.contactform .field select,
.contactform .field textarea{width:100%}
.contactform .wpcf7-not-valid{border-color:var(--red-600)}

/* the per-field message, under the control it belongs to */
.contactform .wpcf7-not-valid-tip{display:block;margin-top:6px;
  font-family:var(--font-body);font-size:13px;line-height:1.4;color:var(--red-700)}

/* The consent line is a checkbox followed by the sentence that carries the
   privacy-policy link. CF7 buries that in three nested spans inside a label, and
   the sentence itself is .wpcf7-list-item-label — the only copy of it, not a
   duplicate of anything. So the wrappers collapse and the label becomes the row
   the design expects. */
.contactform .checkline .wpcf7-form-control-wrap,
.contactform .checkline .wpcf7-acceptance,
.contactform .checkline .wpcf7-list-item{display:contents;margin:0}
.contactform .checkline label{display:flex;gap:10px;align-items:flex-start;
  font-family:var(--font-body);font-weight:400;font-size:14px;line-height:1.5;
  color:var(--body);cursor:pointer}
.contactform .checkline input[type="checkbox"]{flex:none;margin-top:2px}
.contactform .checkline .wpcf7-list-item-label{display:inline}

/* the result banner, styled as the form error the page already used */
.contactform .wpcf7-response-output{margin:18px 0 0;padding:12px 16px;
  border:0;border-left:3px solid var(--red-600);border-radius:var(--radius-md);
  background:var(--red-50);color:var(--red-700);
  font-size:var(--fs-body-sm);line-height:1.5}
.contactform.sent .wpcf7-response-output{border-left-color:var(--navy-600);
  background:var(--surface-sunken);color:var(--navy-700)}

/* CF7's inline spinner sits beside the button rather than after the form */
.contactform .wpcf7-spinner{margin:0 0 0 12px}

/* ---- source line closing a section ---- */
.srcline--foot{margin-top:clamp(30px,3.6vw,44px);padding-top:22px;border-top:1px solid var(--line)}

/* Display headings inside a half-width column step down to the section-title
   scale — 4rem type in a 500px column wraps into a wall. */
.wp-block-columns .wp-block-column .h-display,
.wp-block-columns .wp-block-column h2.h-display{font-size:var(--fs-display-md);line-height:1.12}
.wp-block-columns .wp-block-column .h-display{max-width:20ch}
/* the mission headline keeps the full display scale — it spans the section */
.sec .wrap > .mission__head{font-size:var(--fs-display-lg)}

/* ============================================================================
   LIST COMPONENTS UNDER CORE MARKUP
   The design's evidence list was built around <li><div><b>+<span></div></li>.
   Core's list block emits <li><strong>+<span></li>, so the grid is told
   explicitly which cell each part belongs in.
   ============================================================================ */
ul.wp-block-list.evidence,ul.wp-block-list.factlist{list-style:none;padding-left:0}
.evidence li{grid-template-columns:auto 1fr;gap:2px 18px;align-items:start}
.evidence li::before{grid-column:1;grid-row:1 / span 2;padding-top:4px}
.evidence li > strong,.evidence li > b{grid-column:2;grid-row:1;display:block;
  font-family:var(--font-display);font-weight:600;color:#fff;font-size:var(--fs-body-lg);line-height:1.3}
.evidence li > span{grid-column:2;grid-row:2;display:block;color:rgba(255,255,255,.72);
  font-size:var(--fs-body);line-height:1.55;margin-top:5px}
.evidence li:last-child{border-bottom:1px solid rgba(255,255,255,.14)}
.factlist li{align-items:start}

/* the figure beside the lead programme fills its column */
@media (max-width:900px){ }

/* core adds its own figure margins inside our framed embeds */
.wp-block-image.figframe{margin:0}

/* ============================================================================
   DARK BANDS — readability
   theme.json colours every heading navy and every lede body-grey, which on a
   navy band measured 1.38:1 and 1.7:1. Dark sections restate their own text
   colours so the cascade cannot leave text unreadable on its own background.
   ============================================================================ */
.sec--navy,.sec--cta{color:rgba(255,255,255,.82)}
.sec--navy :is(h1,h2,h3,h4,h5,h6),
.sec--cta :is(h1,h2,h3,h4,h5,h6),
.sec--navy .wp-block-heading,
.sec--cta .wp-block-heading{color:#fff}
.sec--navy p,.sec--cta p{color:rgba(255,255,255,.78)}
.sec--navy p.is-style-lede,.sec--cta p.is-style-lede{color:rgba(255,255,255,.86)}
.sec--navy p.is-style-eyebrow,.sec--cta p.is-style-eyebrow,
.sec--navy .eyebrow,.sec--cta .eyebrow{color:var(--sky)}
.sec--navy strong,.sec--cta strong,.sec--navy b,.sec--cta b{color:#fff}
.sec--navy li,.sec--cta li{color:rgba(255,255,255,.78)}
.sec--navy a:not(.btn):not(.wp-block-button__link),
.sec--cta a:not(.btn):not(.wp-block-button__link){color:var(--sky)}
.sec--navy a:not(.btn):not(.wp-block-button__link):hover,
.sec--cta a:not(.btn):not(.wp-block-button__link):hover{color:#fff}
.sec--navy .link-arrow,.sec--cta .link-arrow{color:var(--sky)}
.sec--navy .figcaption,.sec--cta .figcaption{color:rgba(133,200,252,.75)}
.sec--navy .srcline,.sec--cta .srcline{color:rgba(255,255,255,.6)}
.sec--navy .note,.sec--cta .note{background:rgba(133,200,252,.08);border-left-color:var(--sky);
  color:rgba(255,255,255,.82)}
.sec--navy .note b,.sec--cta .note b{color:#fff}
/* the dark-band figure caption sits on the image, so it keeps its own colour */
.sec--navy .figframe figcaption{color:#fff}

/* ============================================================================
   FOOTER SEPARATION
   Pipeline expansion is a navy band and the footer was the identical #0d1f36,
   so the page ran into the footer with no seam. The footer now sits a shade
   deeper with a lit top edge.
   ============================================================================ */
.footer{background:#08172a;border-top:1px solid rgba(133,200,252,.16);position:relative}
.footer::before{content:"";position:absolute;left:0;right:0;top:0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(133,200,252,.45) 22%,rgba(187,32,37,.5) 55%,transparent);
  pointer-events:none}

/* ============================================================================
   FINGERPRINT WATERMARK
   Applied as a background layer rather than an image block, so editors cannot
   move or delete it by accident and it travels with the section class.
   ============================================================================ */
.workflow{position:relative;overflow:hidden;isolation:isolate}
.workflow::before{content:"";position:absolute;z-index:0;pointer-events:none;
  width:min(1150px,120vw);aspect-ratio:1;right:-15%;top:50%;
  transform:translateY(-46%) rotate(6deg);opacity:.06;
  background:url("../img/quantro-fingerprint-mark.png") center/contain no-repeat}
.workflow > .wrap{position:relative;z-index:1}
/* on a dark band the mark has to lighten the background, not darken it */
.workflow.sec--navy::before,.sec--navy.workflow::before{opacity:.075;filter:brightness(0) invert(1)}
@media (max-width:760px){ .workflow::before{right:-40%;opacity:.05} }
@media (prefers-reduced-motion:no-preference){ .workflow::before{will-change:auto} }

/* ---- release downloads ---- */
.downloads{margin-top:clamp(38px,4.4vw,56px);padding-top:clamp(28px,3.2vw,38px);border-top:1px solid var(--line)}
.downloads__title{font-family:var(--font-display);font-weight:700;font-size:var(--fs-h4);color:var(--navy-700);margin:0}
.downloads__note{font-size:var(--fs-body-sm);line-height:1.6;color:var(--muted);margin-top:8px;max-width:70ch}
.downloads__list{list-style:none;padding:0;margin:18px 0 0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
.downloads__list a{display:flex;align-items:center;gap:14px;padding:16px 18px;text-decoration:none;
  background:#fff;border:1px solid var(--line);border-radius:var(--radius-md);color:inherit;
  transition:border-color .2s var(--ease),box-shadow .2s,transform .2s}
.downloads__list a:hover{border-color:var(--navy-300);box-shadow:var(--shadow-md);transform:translateY(-2px)}
.downloads__icon{flex:none;width:38px;height:38px;border-radius:50%;display:grid;place-items:center;
  background:var(--red-50);color:var(--red-600)}
.downloads__icon svg{width:19px;height:19px}
.downloads__meta b{display:block;font-family:var(--font-display);font-weight:600;font-size:14.5px;color:var(--navy-700)}
.downloads__meta span{display:block;font-family:var(--font-mono);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);margin-top:3px}
.sec--sunken .downloads__list a{background:#fff}

/* ============================================================================
   ARTICLE PAGES — press releases and events
   These are documents, not landing pages: the headline runs at an editorial
   size, the standfirst carries weight, and the body sits close underneath.
   ============================================================================ */
.single-quantro_press .sec--first,
.single-quantro_event .sec--first{padding-bottom:clamp(16px,1.8vw,24px)}
.single-quantro_press .sec--sunken,
.single-quantro_event .sec--sunken{padding-top:clamp(24px,2.6vw,34px)}

/* headline: editorial scale, not the marketing display scale */
.single-quantro_press .pagehead__title,
.single-quantro_event .pagehead__title,
.single-quantro_press h1.wp-block-post-title,
.single-quantro_event h1.wp-block-post-title{
  font-size:clamp(1.75rem,1.28rem + 1.7vw,2.6rem);line-height:1.18;letter-spacing:-.02em;
  max-width:30ch;margin-top:18px}

/* standfirst */
.single-quantro_press .wp-block-post-excerpt,
.single-quantro_event .wp-block-post-excerpt{margin-top:18px;max-width:62ch}
.single-quantro_press .wp-block-post-excerpt p,
.single-quantro_event .wp-block-post-excerpt p,
.single-quantro_press .wp-block-post-excerpt__excerpt,
.single-quantro_event .wp-block-post-excerpt__excerpt{
  font-size:clamp(1.05rem,.97rem + .34vw,1.2rem);line-height:1.55;color:var(--navy-600);font-weight:400}

/* body headings: readable, with air above and the text close beneath */
.single-quantro_press .legal h2,
.single-quantro_event .legal h2{font-size:clamp(1.2rem,1.05rem + .5vw,1.45rem);line-height:1.25;
  margin-top:clamp(38px,4.2vw,54px);margin-bottom:0}
.single-quantro_press .legal h2 + *,
.single-quantro_event .legal h2 + *{margin-top:12px}
.single-quantro_press .legal p,
.single-quantro_event .legal p{max-width:72ch}
.single-quantro_press .legal > * + *,
.single-quantro_event .legal > * + *{margin-top:18px}

/* ---- pull quotes ---- */
.legal blockquote,.prquote{
  margin:clamp(30px,3.4vw,42px) 0;padding:2px 0 2px 26px;
  border-left:3px solid var(--navy-300);background:none}
.legal blockquote p,.prquote p{font-size:clamp(1.02rem,.96rem + .28vw,1.15rem);line-height:1.6;
  color:var(--navy-700);font-style:normal;margin:0;max-width:64ch}
/* attribution on its own line */
.legal blockquote cite,.prquote cite{display:block;margin-top:12px;font-style:normal;
  font-family:var(--font-mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--red-600)}
/* consecutive quotes: break the bar so they read as two voices, not one block */
.legal blockquote + blockquote,.prquote + .prquote{margin-top:clamp(26px,3vw,36px)}
.legal blockquote + blockquote::before{content:none}

/* the sunken article body keeps quotes legible on its tint */
.sec--sunken .legal blockquote{border-left-color:var(--navy-300)}

/* the article body opens flush — no leading margin on its first element */
.single-quantro_press .legal > *:first-child,
.single-quantro_event .legal > *:first-child{margin-top:0}
.single-quantro_press .legal .factlist,
.single-quantro_event .legal .factlist{margin-top:0}

/* contact / media-contact blocks carried over from the release */
.prcontact{font-size:var(--fs-body-sm);line-height:1.85;color:var(--body);
  padding:16px 20px;background:var(--surface-sunken);border-left:3px solid var(--navy-200);
  border-radius:0 var(--radius-md) var(--radius-md) 0}
.sec--sunken .prcontact{background:#fff}
.single-quantro_press .legal h2 + .prcontact,
.single-quantro_event .legal h2 + .prcontact{margin-top:12px}

/* ============================================================================
   HERO FIELDS
   Same grammar as the homepage: a base layer states the idea on its own, and
   the pointer reveals a sharp copy through a soft circular mask. Everything
   still reads with no JavaScript, no pointer, or reduced motion.
   ============================================================================ */
.herofx{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.herofx__base,.herofx__lens{position:absolute;inset:0}
.herofx__base svg,.herofx__lens svg{position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:118%;height:118%}
/* the lens: a sharp copy revealed around the pointer */
/* The lens was a flat 260px at every resolution: a fifth of a 1280 screen but
   an eighth of a 1920 one, so it washed out proportionally far more of the copy
   exactly where the complaint was. */
.herofx{--focus-r:clamp(190px,15.5vw,430px)}
/* No will-change here. A mask is re-resolved whenever its position changes,
   which is every frame, so promoting the layer cannot make it cheap — it only
   pins a full-viewport surface in memory, which is exactly what a weaker
   machine has least of. */
.herofx__lens{
  -webkit-mask-image:radial-gradient(circle var(--focus-r,260px) at var(--mx,50%) var(--my,45%),#000 0%,#000 34%,rgba(0,0,0,0) var(--focus-edge,78%));
  mask-image:radial-gradient(circle var(--focus-r,260px) at var(--mx,50%) var(--my,45%),#000 0%,#000 34%,rgba(0,0,0,0) var(--focus-edge,78%))}
/* without a pointer there is no lens to show */
/* On touch the lens still runs — the hero drives itself, so there is something
   to see without a pointer. Only the probe goes: it is a readout of where the
   pointer is, and there is no pointer. */
@media (hover:none){ .herofx__probe{display:none} }
.no-js .herofx__lens,.no-js .herofx__probe{display:none}

/* ---- Science & Platform: one signal, branching as time passes ---- */
.herofx--timeline .hfx-b path{fill:none;stroke:var(--sky);stroke-linecap:round;stroke-linejoin:round}
/* the tapering pieces of a strand that ends mid-field — each thinner and
   fainter than the last, so the line dissolves rather than stopping */
/* Clarity is cheap early and expensive late. Eight bands so the ramp reads as
   a gradient rather than as steps; the trunk sits in band 0, dead sharp. */
.herofx--timeline .herofx__base .hfx-b--0{opacity:.44;filter:blur(0)}
.herofx--timeline .herofx__base .hfx-b--1{opacity:.38;filter:blur(.6px)}
.herofx--timeline .herofx__base .hfx-b--2{opacity:.32;filter:blur(1.4px)}
.herofx--timeline .herofx__base .hfx-b--3{opacity:.27;filter:blur(2.6px)}
.herofx--timeline .herofx__base .hfx-b--4{opacity:.22;filter:blur(4.2px)}
.herofx--timeline .herofx__base .hfx-b--5{opacity:.18;filter:blur(6px)}
.herofx--timeline .herofx__base .hfx-b--6{opacity:.15;filter:blur(8px)}
.herofx--timeline .herofx__base .hfx-b--7{opacity:.12;filter:blur(10.5px)}
/* inside the focus band everything resolves */
.herofx--timeline .herofx__lens .hfx-b{opacity:.66;filter:none}
.herofx--timeline .herofx__lens .hfx-b path{stroke:#c6e2ff}

/* ---- the two measurements ----
   Both are near-invisible until the focus band reaches them, so the field stays
   quiet and the labels are a reward for exploring rather than clutter. The
   pings live in both layers: a soft bloom in the base, the resolved marker and
   its label in the masked layer. */
.herofx--timeline .hfx-mark__halo{fill:none}
.herofx--timeline .hfx-mark__ring{fill:none;stroke-width:1.6}
.herofx--timeline .hfx-mark__ring--open{stroke-dasharray:7 9}   /* an unclean reading */
.herofx--timeline .hfx-mark__t,.herofx--timeline .hfx-cloud__t{
  font-family:var(--font-display);font-size:13.5px;font-weight:600;letter-spacing:-.005em}
.herofx--timeline .hfx-mark__time,.herofx--timeline .hfx-cloud__time{
  font-family:var(--font-mono);font-size:12.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase}
.herofx--timeline .hfx-mark__s,.herofx--timeline .hfx-cloud__s{
  font-family:var(--font-display);font-size:12px;font-weight:500;letter-spacing:.01em}
/* The labels sit over a field of strands, so colour alone cannot carry them.
   A dark halo painted behind the glyphs lifts them off whatever they land on. */
.herofx--timeline .hfx-mark__t,
.herofx--timeline .hfx-mark__time,
.herofx--timeline .hfx-mark__s{
  paint-order:stroke;stroke:rgba(6,22,42,.85);stroke-width:3.4px;stroke-linejoin:round}

/* QUANTRO reads while the signal is still one line — brand red, resolved */
.herofx--timeline .hfx-mark--q .hfx-mark__dot{fill:var(--red-500)}
.herofx--timeline .hfx-mark--q .hfx-mark__ring{stroke:var(--coral)}
.herofx--timeline .hfx-mark--q .hfx-mark__halo{fill:var(--red-500);opacity:.16;filter:blur(18px)}
.herofx--timeline .hfx-mark--q .hfx-mark__t{fill:#ffd9db}
.herofx--timeline .hfx-mark--q .hfx-mark__time{fill:var(--coral)}
.herofx--timeline .hfx-mark--q .hfx-mark__s{fill:#fff4f4}

/* The late reading is a cloud, not a point. It has no ring and no dot because
   there is nothing precise left to point at: by eight to twelve hours the one
   line has become a dozen, and the haze covers all of them. Its wording sits
   inside it rather than on a leader, since a leader would imply a place. */
.hfx-defs{position:absolute;width:0;height:0;overflow:hidden}
.herofx--timeline .hfx-cloud__haze{fill:url(#hfxHaze)}
.herofx--timeline .hfx-cloud__t{fill:#eaf4ff}
.herofx--timeline .hfx-cloud__time{fill:var(--sky)}
.herofx--timeline .hfx-cloud__s{fill:#dcefff}
.herofx--timeline .hfx-mark__lead{stroke-width:1;stroke-dasharray:2 4;opacity:.5}
.herofx--timeline .hfx-mark--q .hfx-mark__lead{stroke:var(--coral)}
.herofx--timeline .hfx-cloud__lead{stroke:var(--sky)}
.herofx--timeline .hfx-cloud text{paint-order:stroke;stroke:rgba(6,22,42,.8);stroke-width:3.6px;
  stroke-linejoin:round}

/* base layer: a red ping blooming under the blur, and the haze on the right */
.herofx--timeline .herofx__base .hfx-mark--q{opacity:.55}
.herofx--timeline .herofx__base .hfx-mark--q .hfx-mark__ring{opacity:.30;filter:blur(1px)}
.herofx--timeline .herofx__base .hfx-cloud__haze{opacity:.8}
.herofx--timeline .herofx__base .hfx-cloud text{opacity:0}
.herofx--timeline .herofx__lens .hfx-cloud__haze{opacity:1}
.herofx--timeline .herofx__lens .hfx-cloud text{opacity:1}
.herofx--timeline .herofx__base .hfx-mark__t,
.herofx--timeline .herofx__base .hfx-mark__time,
.herofx--timeline .herofx__base .hfx-mark__s,
.herofx--timeline .herofx__base .hfx-mark__lead{opacity:0}   /* text only on approach */

/* masked layer: the marker resolves and names itself */
.herofx--timeline .herofx__lens .hfx-mark{opacity:1;filter:none}
.herofx--timeline .herofx__lens .hfx-mark__ring{opacity:.9}
.herofx--timeline .herofx__lens .hfx-mark__t,
.herofx--timeline .herofx__lens .hfx-mark__s{opacity:1}

/* a slow breath on the QUANTRO ping so the eye finds it */
@media (prefers-reduced-motion:no-preference){
  .herofx--timeline .herofx__base .hfx-mark--q .hfx-mark__halo{animation:hfx-ping 4.2s ease-in-out infinite}
}
@keyframes hfx-ping{0%,100%{opacity:.10;transform:scale(.94)}50%{opacity:.22;transform:scale(1.06)}}
.herofx--timeline .hfx-mark__halo{transform-box:fill-box;transform-origin:center}

/* The focus is a full-height vertical band, not a circle: it is a moment in
   time, so it must take in every strand at that moment. */
/* This field fits rather than covers: with "slice" the sides are cropped on a
   narrow window and the two labels can end up off screen. Fitting keeps the
   whole span — trunk, fork and tangle — and both labels in frame.
   Held above the phone breakpoint: this selector outranks the mobile sizing
   rule, so without the query it would take the zoom away from phones too. */
@media (min-width:761px){
  .hero--fx-timeline .herofx__base svg,
  .hero--fx-timeline .herofx__lens svg{width:100%;height:100%}
}
.herofx--timeline .herofx__lens{
  -webkit-mask-image:radial-gradient(ellipse var(--band-w,225px) 200% at var(--mx,50%) 50%,#000 0%,#000 46%,rgba(0,0,0,0) 100%);
  mask-image:radial-gradient(ellipse var(--band-w,225px) 200% at var(--mx,50%) 50%,#000 0%,#000 46%,rgba(0,0,0,0) 100%)}

/* Every branching column is marked, and each one reads a step stronger than the
   one before it: the first pair of readings is barely there, the last column is
   the loudest thing in the field. Under the lens the whole ramp lifts. */
.herofx--timeline .hfx-dots circle{fill:var(--sky)}
.herofx--timeline .herofx__base .hfx-dots--0{opacity:.16;filter:blur(1px)}
.herofx--timeline .herofx__base .hfx-dots--1{opacity:.22;filter:blur(1.6px)}
.herofx--timeline .herofx__base .hfx-dots--2{opacity:.28;filter:blur(2.4px)}
.herofx--timeline .herofx__base .hfx-dots--3{opacity:.34;filter:blur(3.2px)}
.herofx--timeline .herofx__lens .hfx-dots{filter:none}
.herofx--timeline .herofx__lens .hfx-dots--0{opacity:.5}
.herofx--timeline .herofx__lens .hfx-dots--1{opacity:.68}
.herofx--timeline .herofx__lens .hfx-dots--2{opacity:.84}
.herofx--timeline .herofx__lens .hfx-dots--3{opacity:1}
.herofx--timeline .herofx__lens .hfx-dots--2 circle{fill:#b9dcff}
.herofx--timeline .herofx__lens .hfx-dots--3 circle{fill:#dcefff}
/* The scrim is painted above the field, so revealing a marker was not enough:
   its caption was still being read through as much as 83% navy, around 1.3:1.
   The scrim is thinned to a third inside the band, and only across the lower
   part of the hero where the captions hang — by the height the lede sits at it
   is back to ~58%, which keeps that text above 4.5:1 even where a bright
   strand passes directly behind it. */
@media (hover:hover){
  .hero--fx-timeline .hero__scrim{
    -webkit-mask-image:radial-gradient(ellipse calc(var(--band-w,150px) + 100px) 34% at var(--mx,50%) 84%,
      rgba(0,0,0,.35) 0%,rgba(0,0,0,.35) 45%,#000 100%);
    mask-image:radial-gradient(ellipse calc(var(--band-w,150px) + 100px) 34% at var(--mx,50%) 84%,
      rgba(0,0,0,.35) 0%,rgba(0,0,0,.35) 45%,#000 100%)}
}

/* the time readout that rides with the pointer */
.herofx__probe{position:absolute;top:0;bottom:0;left:var(--mx,50%);width:1px;
  background:linear-gradient(180deg,transparent,rgba(133,200,252,.42) 22%,rgba(133,200,252,.42) 78%,transparent);
  opacity:0;transition:opacity .35s var(--ease)}
.hero--fx-timeline:hover .herofx__probe,
.hero--fx-timeline.is-auto .herofx__probe{opacity:1}
.herofx__time{position:absolute;top:22%;left:10px;font-family:var(--font-mono);font-size:11px;
  letter-spacing:.12em;color:var(--sky);white-space:nowrap;
  background:rgba(8,23,42,.72);padding:3px 8px;border-radius:var(--radius-pill)}

/* Three stages, but five figures — so the columns are weighted by how many
   figures each stage holds. Every figure then gets the same fifth of the width
   it had before grouping, and the row still fills the section. */
.slamflow--grouped{display:grid;grid-template-columns:2fr 2fr 1fr;
  grid-template-rows:auto auto auto;
  column-gap:clamp(18px,2.4vw,34px);row-gap:0;align-items:start}
/* The three stages share their row tracks, so a caption wrapping to two lines
   pushes only its own figure block taller and all three explanations still
   start on one line. Hard-coding a break into every caption would achieve the
   same alignment, but only until the wording or the breakpoint changed. */
@supports (grid-template-rows:subgrid){
  .slamflow--grouped .slamstep{display:grid;grid-template-rows:subgrid;grid-row:span 3}
}
.slamflow--grouped .slamstep__figs{display:flex;gap:clamp(8px,1vw,14px);
  align-items:flex-start;justify-content:center}
.slamflow--grouped .slamstep__figs .slamfigure{flex:1 1 0;min-width:0}
/* The stage heading says where in the protocol you are; the caption under each
   drawing says what that drawing is. Captions align on a shared baseline so a
   two-line one does not shove its neighbour's figure upward. */
.slamfigure{display:flex;flex-direction:column;margin:0}
.slamfig__cap{font-family:var(--font-mono);font-size:12px;line-height:1.35;
  letter-spacing:.01em;color:var(--navy-600);text-align:center;margin-top:8px}
/* The five drawings do not share an aspect ratio (160x120, 160x140, 214x120),
   so sizing them by width alone gave each box a different height and let the
   taller ones spill. Filling the box and letting preserveAspectRatio fit the
   drawing inside keeps the row of boxes level whatever is in them. */
.slamflow--grouped .slamfig{width:100%;height:100%}
@media (max-width:860px){
  .slamflow--grouped{grid-template-columns:1fr;gap:clamp(26px,4vw,40px)}
}

/* ---- Science & Platform: the two hurdles ----
   One word naming the hurdle, then what it actually is. Stacked rather than
   side by side: they are read in sequence, not compared. */
/* The two boxes and the picture are one row: the boxes share the picture's
   height between them rather than ending short of it. */
.split--top:has(.hurdles){align-items:stretch}
.split--top > .wp-block-column:has(.hurdles){display:flex}
.wp-block-columns.hurdles{display:grid;grid-template-columns:1fr;grid-auto-rows:1fr;
  gap:clamp(18px,2.2vw,26px);flex:1;margin-top:0}
/* A supplied graphic carries its credit in the corner of its own frame. The
   artwork is transparent at that corner, so the line sits on the section
   background and takes the muted body colour instead of needing a plate. It
   also has to undo the caption bar that .figframe figcaption otherwise gives
   every caption in a frame. */
/* Clear of the frame's 16px corner radius: at 2px from the left and flush to
   the bottom the © sat inside the curve, and overflow:hidden clipped it. */
.figframe .figcredit{position:absolute;left:12px;right:auto;bottom:6px;
  margin:0;padding:0;background:none;text-align:left;pointer-events:none;
  font-family:var(--font-mono);font-size:10px;letter-spacing:.03em;
  line-height:1.4;color:var(--muted);opacity:.9}
/* The expansion split: the map is the taller half, so it takes the wider
   column and the copy is held to a comfortable measure beside it. */
.expansion__split{align-items:start}
.expansion__split .bodymap{margin-top:0}
.expansion__split .bodymap__stage{max-width:none}
/* The map is meant to start on the heading, not on the eyebrow above it. Rather
   than pad the figure down by whatever the eyebrow currently measures — which
   changes with the type scale — the two columns share row tracks and the figure
   simply begins at the heading's row. */
@supports (grid-template-rows:subgrid){
  @media (min-width:901px){
    /* two classes deep, to clear .wp-block-columns.split which sets both the
       columns and the gap at that same specificity */
    .wp-block-columns.expansion__split{display:grid;grid-template-columns:0.85fr 1.15fr;
      grid-template-rows:auto auto 1fr;
      column-gap:clamp(28px,4vw,64px);row-gap:0}
    /* Beside its icon a label had about 120px in a half-width column, which
       broke the longer indication names into as many as ten lines. Under the
       icon it gets the node's full width instead. The nodes themselves stay
       where they are — the connector lines are drawn to those positions. */
    .expansion__split .bmnode{flex-direction:column;gap:7px}
    .expansion__split .bmnode--l{align-items:flex-end;text-align:right}
    .expansion__split .bmnode--r{align-items:flex-start;text-align:left}
    .expansion__split .bmnode__lbl{font-size:11.5px;line-height:1.3}
    .expansion__split > .wp-block-column:first-child{display:grid;
      grid-template-rows:subgrid;grid-row:1 / 4}
    .expansion__split > .wp-block-column:last-child{grid-row:2 / 4}
  }
}
.split--top .figframe--flat{margin-top:0}
.figframe--flat img{display:block;width:100%;height:auto;border-radius:var(--radius-lg)}
.wp-block-columns.hurdles > .wp-block-column{flex-basis:auto!important;min-width:0;
  padding:clamp(20px,2.2vw,28px);border-radius:var(--radius-lg);
  background:var(--surface-sunken)}
.hurdle__tag{font-family:var(--font-mono);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--red-600)}
.hurdle__t{font-family:var(--font-display);font-size:var(--fs-h4);color:var(--navy-700);margin-top:8px}
.hurdle__t strong{font-weight:700}
.hurdle__d{margin-top:8px;line-height:var(--lh-relaxed);color:var(--body)}

/* the three ways the conventional readout falls short */
.shortfall{list-style:none;padding:0;margin:clamp(26px,3vw,36px) 0 0;display:grid;gap:0}
.shortfall li{display:grid;grid-template-columns:minmax(120px,180px) 1fr;gap:10px 28px;
  padding:16px 0;border-top:1px solid var(--line)}
.shortfall li:last-child{border-bottom:1px solid var(--line)}
.shortfall strong{font-family:var(--font-display);font-weight:700;color:var(--red-600);
  font-size:var(--fs-body-lg)}
.shortfall span{color:var(--body);line-height:var(--lh-relaxed)}
/* The bridge: the chart states the problem, the line under it names what
   QUANTRO built and hands over to the next section, so it is set larger than
   body copy and separated from the list above. */
.bridge{position:relative}
.bridge__lead{margin-top:clamp(22px,2.6vw,32px);font-family:var(--font-display);
  font-size:clamp(1.15rem,1rem + .6vw,1.5rem);line-height:var(--lh-snug);
  font-weight:600;color:var(--navy-700);max-width:60ch}

/* the binding-versus-function pull-out that closes the workflow */

/* the workflow steps gained a middle line naming the method */
.step__sub{font-family:var(--font-mono);font-size:13.5px;letter-spacing:.03em;
  color:var(--red-600);margin-top:6px}

/* The four steps are read across, so the descriptions have to start on the same
   line whatever the heading and the method line above them do — at 1080p
   "Assay development, screen" fits on one line while its neighbours take two,
   and step 03's text then sat a line high. Handing each step the same four rows
   makes every row as tall as the tallest step needs, so this holds at any width
   and survives the client rewording any of it. Row gaps are taken from the
   parent grid, so they are zeroed inside a step; the gap between the two bands
   at narrower widths still belongs to the parent and is untouched. */
@supports (grid-template-rows:subgrid){
  .steps,.wp-block-columns.steps{grid-template-rows:auto auto auto auto}
  .steps > .step,.wp-block-columns.steps > .step{
    display:grid;grid-row:span 4;grid-template-rows:subgrid;row-gap:0}
}

@media (min-width:860px){
  .wp-block-columns.hurdles{grid-template-columns:1fr 1fr}
}
@media (max-width:560px){
  .shortfall li{grid-template-columns:1fr;gap:4px}
}

/* ---- The QUANTRO fingerprint ----
   The supplied brand mark, drawn as-is. Its two fills are mapped to the site's
   own tokens so it matches the rest of the page; the source files beside it are
   untouched. It used to wipe itself in ridge by ridge on scroll — that is gone,
   so there is nothing here to reveal, delay or reduce-motion around. */
.fpwrap{display:flex;justify-content:center}
.fp{width:min(300px,58vw)}
.fp__svg{display:block;width:100%;height:auto;overflow:visible}
.fp__ridge{fill:var(--red-600)}
.fp__dot{fill:var(--navy-700)}
.fp__dot--red{fill:var(--red-600)}

/* the programme dialog was replaced by a row that unfolds in place; its
   styles went with it */


/* auto margin alone aligns the buttons across cards of unequal height; the
   gap above comes from the takeaway, so the button keeps its own padding */

/* ---- pipeline: the row unfolds rather than opening a dialog ----
   Hover previews it and a click pins it, so a pointer can browse the chart
   without committing and a tap still works. The panel is a grid row animated
   from 0fr to 1fr, which is the one way to transition to content height without
   guessing a max-height. */
.pipeline__row--foldable{cursor:pointer;border-radius:var(--radius-md);
  transition:background .2s var(--ease)}
.pipeline__row--foldable:hover{background:var(--navy-50)}
.pipeline__open i{font-style:normal;display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;margin-left:2px;border:1px solid rgba(187,32,37,.4);border-radius:50%;
  color:var(--red-600);font-size:11px;line-height:1;transition:all .2s var(--ease)}
.pipeline__open i::before{content:"+"}
.pipeline__row--foldable:hover .pipeline__open i,
.pipeline__open[aria-expanded="true"] i{background:var(--red-600);color:#fff;border-color:var(--red-600)}
.pipeline__open[aria-expanded="true"] i::before{content:"−"}

.pipeline__fold{grid-column:1 / -1;display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .38s var(--ease)}
.pipeline__row--foldable:hover .pipeline__fold,
.pipeline__row--foldable:focus-within .pipeline__fold,
.pipeline__row--foldable.is-open .pipeline__fold{grid-template-rows:1fr}
.pipeline__fold__inner{overflow:hidden;min-height:0}
.pipeline__fold__body{padding:2px 0 16px}
.pipeline__fold__body p{color:var(--body);line-height:var(--lh-relaxed)}
.pipeline__fold__body p + p{margin-top:10px}
@media (prefers-reduced-motion:reduce){ .pipeline__fold{transition:none} }

/* A programme with detail opens it from its own chart row, so the row label is
   a real button styled to sit in the chart rather than to look like a control. */
.pipeline__open{display:inline-flex;align-items:baseline;gap:6px;background:none;border:0;padding:0;
  cursor:pointer;font:inherit;color:var(--navy-700);text-align:left;
  border-bottom:1px solid transparent;transition:color .2s var(--ease),border-color .2s var(--ease)}
.pipeline__open i{font-style:normal;color:var(--red-600);font-size:13px;line-height:1;
  border:1px solid rgba(187,32,37,.35);border-radius:50%;width:15px;height:15px;
  display:inline-flex;align-items:center;justify-content:center;transition:all .2s var(--ease)}
.pipeline__open:hover{color:var(--red-600);border-bottom-color:rgba(187,32,37,.4)}
.pipeline__open:hover i{background:var(--red-600);color:#fff;border-color:var(--red-600)}
.pipeline__open:focus-visible{outline:2px solid var(--red-600);outline-offset:3px}
/* Without script the fold cannot be toggled, so it is simply left open. */
.no-js .pipeline__fold{grid-template-rows:1fr}
.no-js .pipeline__open i{display:none}
/* ---- Pipeline: a compound library, screened ---- */
.herofx--screen .hfx-dots circle{fill:var(--sky)}
.herofx--screen .hfx-hit__c{fill:var(--sky)}
/* QUANTRO red, not the coral used elsewhere on dark: a found compound should
   carry the brand colour. --red-500 sits next to the brand #bb2025 in hue but
   clears the navy behind it, which #bb2025 alone does not. */
.herofx--screen .hfx-hit__r{fill:none;stroke:var(--red-bright);stroke-width:1.5}
/* A hit centre sits at exactly the noise level: before it is found there is
   nothing to tell it apart from the library around it. Set per element rather
   than on the group, so the ring can be animated to its own brightness. */
.herofx--screen .herofx__base .hfx-dots{opacity:.21}
.herofx--screen .herofx__base .hfx-hit__c{opacity:.21}
.herofx--screen .herofx__base .hfx-hit__r{opacity:0}      /* hits hide in the noise */
.herofx--screen .herofx__lens .hfx-dots{opacity:.5}
/* Found. The core lifts to a hot red rather than white so the marker reads as
   QUANTRO red overall, and the glow sits on the group — one filter for all the
   hits instead of one per circle. */
.herofx--screen .herofx__lens .hfx-hit__c{opacity:1;fill:var(--red-bright)}
.herofx--screen .herofx__lens .hfx-hit__r{opacity:1;stroke-width:1.8}
/* Three stops: a tight hot core, a mid bloom, then a wide brand-red haze. The
   brand red is dark against this navy, so the glow is what buys back the
   luminance the hue gives up — without it, "redder" would read as "dimmer". */
.herofx--screen .herofx__lens .hfx-hit{
  filter:drop-shadow(0 0 3px rgba(255,59,65,1))
         drop-shadow(0 0 8px rgba(255,59,65,.78))
         drop-shadow(0 0 18px rgba(206,42,48,.55))}

/* Hits also resolve on their own, not only under the cursor: each ring blooms
   once per cycle in eight staggered waves, so somewhere in the library a
   compound is always being found. Held off on touch, where the base layer
   already shows every hit outright and blinking would just be noise. */
@media (prefers-reduced-motion:no-preference) and (hover:hover){
  .herofx--screen .herofx__base .hfx-hit__r{
    transform-box:fill-box;transform-origin:center;
    animation:hfx-find 18s ease-out infinite;animation-delay:var(--d,0s)}
}
/* Quick to arrive, slow to fade — a reading settling rather than a blink. The
   ring starts near full size, so it swells into view instead of popping. */
@keyframes hfx-find{
  0%,86.5%{opacity:0;transform:scale(.88)}
  89.5%{opacity:.75;transform:scale(1)}
  100%{opacity:0;transform:scale(1.12)}
}
/* quieter than the platform hero — the page below already carries two charts */
.hero--fx-screen .hero__scrim{background:radial-gradient(120% 90% at 20% 40%,rgba(13,31,54,.52),rgba(13,31,54,.86))}

@media (prefers-reduced-motion:reduce){
  .herofx__lens{transition:none}
  .herofx__probe{display:none}
}

/* ---- mobile menu overlay ---- */
/* Core sets a white overlay via .wp-block-navigation:not(.has-background) …,
   which is (0,4,0) — the block now carries its own overlay colours, and this
   matches that weight as a belt-and-braces net so the menu can never render
   white text on a white sheet. */
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open{
  position:fixed;inset:0;background-color:var(--navy-900);padding:88px clamp(20px,6vw,32px) 40px;
  display:flex;flex-direction:column;overflow-y:auto}
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content{
  width:100%;align-items:flex-start}
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container{
  flex-direction:column;align-items:flex-start;gap:2px;width:100%}
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item{width:100%}
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content{
  display:block;width:100%;padding:16px 0;font-size:1.28rem;font-weight:600;color:#fff;
  border-bottom:1px solid rgba(133,200,252,.14)}
.nav .wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content::after{display:none}
.nav .wp-block-navigation__responsive-container-close{position:absolute;top:22px;right:clamp(20px,6vw,32px);
  width:40px;height:40px;color:#fff}

/* ============================================================================
   MOBILE — PIPELINE AS CARDS
   A five-stage track needs horizontal room it does not have on a phone, and
   side-scrolling a chart hides half the pipeline. Below 760px each programme
   becomes its own card: name, tag, stage, a full-width progress bar and the
   note, all readable without scrolling sideways.
   ============================================================================ */
@media (max-width:760px){
  /* the min-width that guarantees track room on desktop must be dropped here,
     or the cards inherit it and the side-scroll survives */
  .tbl-scroll{overflow:visible}
  .pipeline .pipeline__chart,
  .pipeline--full .pipeline__chart{min-width:0}
  .pipeline{margin-top:clamp(24px,4vw,34px)}

  .pipeline__row{display:block;padding:0;border-top:0;background:#fff;
    border:1px solid var(--line);border-radius:var(--radius-lg);
    padding:18px 18px 20px;box-shadow:var(--shadow-sm)}
  .pipeline__row + .pipeline__row{margin-top:12px}

  .pipeline__label{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px}
  .pipeline__label b{font-size:16px;flex:1 1 100%}
  .pipeline__label .sub{margin-top:0;font-size:12.5px}
  .pipeline__label .tag{margin-top:0}

  /* the track loses its stage gridlines and becomes a plain progress bar */
  .pipeline__track{height:auto;background:none;margin-top:14px;
    display:flex;flex-direction:column;gap:8px}
  .pipeline__track::before{content:attr(data-stage);order:2}
  .pipeline__row::after{content:attr(data-stage);display:block;order:2;
    font-family:var(--font-display);font-weight:600;font-size:13px;color:var(--navy-700);margin-top:10px}
  .pipeline__bar{position:relative;height:8px!important;border-radius:5px;width:var(--w)!important;
    padding:0;overflow:hidden;text-indent:-9999px;box-shadow:none}
  .pipeline__bar--outlabel > span{display:none}
  /* the bar sits in a full-width groove so the proportion still reads */
  .pipeline__track{position:relative;padding-top:8px}
  .pipeline__track::after{content:"";position:absolute;left:0;right:0;top:8px;height:8px;
    border-radius:5px;background:var(--navy-100);z-index:0}
  .pipeline__bar{z-index:1;position:absolute;top:8px;left:0}
  .pipeline__track{min-height:16px}

  .pipeline__ms,.pipeline__ms-lbl{display:none}
  .pipeline__note{margin-top:14px;padding-top:12px;border-top:1px solid var(--line);
    padding-left:0;font-size:13px;line-height:1.5;color:var(--body)}

  /* milestone, restated as a line of text rather than a marker on a track */
  .pipeline__row[data-ms]::before{content:"◆ " attr(data-ms);display:block;margin-top:12px;
    font-family:var(--font-mono);font-size:11px;letter-spacing:.06em;color:var(--red-600)}
}

/* ============================================================================
   MOBILE — FIGURES
   ============================================================================ */
@media (max-width:820px){
  /* Indication map: the icon and its name share a row. The longest name wraps
     to two lines beside the icon instead of dropping underneath it. */
  .bmnode{flex-wrap:nowrap;align-items:center}
  .bmnode__btn{flex:0 0 auto}
  .bmnode__lbl{flex:1 1 auto;min-width:0}
  .bmnode__lbl b{white-space:normal;overflow-wrap:break-word;line-height:1.25}
  .bmnode .bmpanel{flex-basis:100%;order:3;width:100%}
}

@media (max-width:760px){
  /* SLAMseq on a phone: each stage reads straight down — number and title,
     then its figures side by side, each captioned under itself, then the
     description. The side-by-side arrangement squeezed two 160-unit drawings
     into a 118px column, which is where the layout gave out. */
  .slamflow,.slamflow--grouped{display:grid;grid-template-columns:1fr;gap:14px}
  .slamstep{display:flex;flex-direction:column;
    border:1px solid var(--line);border-radius:var(--radius-lg);padding:16px;background:#fff}
  .slamstep__head{min-height:0;order:1}
  .slamstep__figs{order:2;display:flex;gap:12px;align-items:flex-start;margin-top:12px}
  .slamflow--grouped .slamstep__figs .slamfigure{flex:1 1 0;min-width:0}
  .slamstep__fig{height:auto;aspect-ratio:4/3;margin-top:0}
  .slamflow--grouped .slamfig{width:100%;height:100%}
  .slamfig__cap{font-size:11px;line-height:1.3;margin-top:6px}
  .slamstep__d{order:3;margin-top:12px;font-size:13px;line-height:1.5}
  .slamstep__n{font-size:11px}
  .slamstep__t{font-size:14.5px;margin-top:2px}
  .slamstep__fig::after{display:none}

  /* ---- Signal timeline on phones: the chart flows past a fixed playhead ----
     The full 900-unit chart is unreadable at phone width and asking someone to
     drag it sideways buries the argument. Instead the viewport crops to a
     window, the chart translates beneath it, and each marker is labelled as it
     arrives — so the story reads itself: one clean signal at 1–2h, a tangle by
     8–12h. Geometry is untouched; all of this is scenery around it. */
  .signalviz{overflow:visible;padding:0;
    border:1px solid var(--line);border-radius:var(--radius-lg);
    background:var(--surface-sunken)}

  .is-flowing .signalviz__flow{position:relative;overflow:hidden;border-radius:inherit;
    height:clamp(280px,85vw,340px);
    /* vertical panning stays with the page; horizontal is the scrub */
    touch-action:pan-y}

  /* The track is wider than the frame and is moved by JS. Its height comes from
     the SVG's own aspect, so the negative offset centres the spine (y=172 of
     400) on the frame rather than fitting the whole picture in. */
  .is-flowing .signalviz__track{position:absolute;left:0;top:0;
    width:var(--flow-w,1900px);
    transform:translate3d(var(--flow-x,0px),0,0);
    will-change:transform}
  .is-flowing .signalviz__track svg{width:100%;height:auto;display:block;overflow:visible}

  /* Nothing that assumes the whole chart is on screen survives the crop: the
     axis, its tick labels and the in-chart captions all go, replaced by the
     ruler and the cards below. */
  .is-flowing .axis,.is-flowing .axis-lbl,.is-flowing .tick,.is-flowing .tick-lbl,
  .is-flowing .lbl,.is-flowing .cloud__t,.is-flowing .cloud__time,.is-flowing .cloud__s{display:none}

  /* Markers are held on the playhead by JS and belong to it, not to the chart
     travelling behind. Each is absent until its window opens, then fades in on
     the line and back out when it closes. */
  .is-flowing [data-flow-ride]{opacity:0;transition:opacity .55s var(--ease)}
  .is-flowing [data-flow-ride].is-on{opacity:1}
  .is-flowing .flowmark{display:block;fill:var(--navy-700)}
  .is-flowing .flowmark.is-on{opacity:.92}

  /* the playhead: fixed at the centre, the one thing that never moves */
  .is-flowing .signalviz__playhead{display:block;position:absolute;top:0;bottom:34px;left:50%;width:0;
    border-left:2px dashed var(--navy-700);opacity:.75;transform:translateX(-1px)}

  /* the arriving label, top left, out of the chart's way */
  .is-flowing .signalviz__cards{display:block;position:absolute;top:0;left:0;right:38%;padding:12px 0 0 12px}
  .svcard{position:absolute;top:12px;left:12px;margin:0;padding:9px 12px 8px;
    border-radius:10px;background:var(--surface-sunken);border:1px solid var(--line);
    box-shadow:0 1px 2px rgba(3,21,54,.06);
    opacity:0;transform:translateY(-4px);pointer-events:none;
    transition:opacity .32s var(--ease),transform .32s var(--ease)}
  .svcard.is-on{opacity:1;transform:none}
  .svcard__t{font-family:var(--font-display);font-weight:700;font-size:14px;
    line-height:1.2;color:var(--navy-700)}
  .svcard__s{margin-top:3px;font-family:var(--font-display);font-weight:500;
    font-size:11.5px;line-height:1.3;color:var(--navy-600);max-width:20ch}
  .svcard__time{margin-top:5px;font-family:var(--font-mono);font-size:11px;
    letter-spacing:.06em;color:var(--muted)}
  .svcard[data-flow-card="quantro"] .svcard__t{color:var(--red-600,#8f181c)}
  .svcard[data-flow-card="quantro"] .svcard__s{color:var(--red-400,#bb2025)}

  /* the ruler: a uniform hatch that travels with the chart, and the one hour
     that matters — the one under the playhead */
  .is-flowing .signalviz__ruler{display:block;position:absolute;left:0;right:0;bottom:0;height:34px;
    overflow:hidden;border-top:1px solid var(--line)}
  .is-flowing .signalviz__hatch{position:absolute;left:0;top:0;height:11px;width:400%;
    transform:translate3d(var(--flow-x,0px),0,0);
    background-image:repeating-linear-gradient(90deg,
      var(--navy-300) 0 1px,transparent 1px 9px);
    opacity:.85}
  .is-flowing .signalviz__now{position:absolute;left:50%;bottom:3px;transform:translateX(-50%);
    font-family:var(--font-mono);font-size:15px;font-weight:600;letter-spacing:.04em;
    color:var(--navy-700)}

  /* Without JS, or with reduced motion, `is-flowing` is never set and none of
     the above applies: the frame is just the chart, whole, with its own labels.
     It then needs somewhere to go at 390px, so it keeps the old sideways scroll
     as the fallback rather than being squeezed to nothing. */
  .signalviz:not(.is-flowing){overflow-x:auto;-webkit-overflow-scrolling:touch;padding:10px 0}
  .signalviz:not(.is-flowing) svg{min-width:680px}
}

/* ---- the timeline field on phones ----
   Two stacked copies of the field, one sharp under a mask and one blurred
   beneath it, read as doubled content on a small screen — and a 1600-unit-wide
   picture never had room to say anything at 390px. Below the breakpoint the
   field is dropped for a gradient in the same palette, which keeps the hero
   looking like itself without pretending to carry the diagram. */
@media (max-width:760px){
  .hero--fx-timeline .herofx{display:none}
  .hero--fx-timeline{background:
    radial-gradient(120% 80% at 76% 32%,rgba(133,200,252,.22),rgba(133,200,252,0) 60%),
    radial-gradient(90% 60% at 12% 62%,rgba(206,42,48,.20),rgba(206,42,48,0) 58%),
    linear-gradient(163deg,#1b3d61 0%,#10314f 48%,#071f38 100%)}
  .hero--fx-timeline .hero__scrim{background:linear-gradient(180deg,rgba(6,20,38,.30),rgba(6,20,38,.62))}
}

/* ---- interactive heroes on touch ----
   The lens now runs on touch as well, driven by the hero itself, so the base
   layer no longer has to carry the whole picture on its own — but it still sits
   a little more readable than on desktop, because nothing here is a reward for
   exploring. */
@media (hover:none){
  .hero--fx .herofx__base .hfx-b--0{opacity:.40;filter:none}
  .hero--fx .herofx__base .hfx-b--1{opacity:.34;filter:blur(.5px)}
  .hero--fx .herofx__base .hfx-b--2{opacity:.29;filter:blur(1.1px)}
  .hero--fx .herofx__base .hfx-b--3{opacity:.25;filter:blur(1.8px)}
  .hero--fx .herofx__base .hfx-b--4{opacity:.21;filter:blur(2.6px)}
  .hero--fx .herofx__base .hfx-b--5{opacity:.18;filter:blur(3.4px)}
  .hero--fx .herofx__base .hfx-b--6{opacity:.15;filter:blur(4.2px)}
  .hero--fx .herofx__base .hfx-b--7{opacity:.13;filter:blur(5px)}
  /* the two measurements name themselves without needing a sweep */
  .hero--fx .herofx__base .hfx-mark--q{opacity:1}
  .hero--fx .herofx__base .hfx-mark--q .hfx-mark__ring{opacity:.75;filter:none}
  .hero--fx .herofx__base .hfx-cloud__haze{opacity:.85}
  .hero--fx .herofx__base .hfx-cloud text{opacity:.9}
  .hero--fx .herofx__base .hfx-mark__lead{opacity:.5}
  .hero--fx .herofx__base .hfx-mark__t{opacity:.92}
  .hero--fx .herofx__base .hfx-mark__s{opacity:.75}
  /* screening field: show that hits exist rather than hiding them all, in the
     same red the cursor reveals on pointer devices */
  .hero--fx-screen .herofx__base .hfx-dots{opacity:.20}
  .hero--fx-screen .herofx__base .hfx-hit__c{opacity:1;fill:var(--red-bright)}
  .hero--fx-screen .herofx__base .hfx-hit__r{opacity:.85}
}
@media (max-width:760px){
  /* the field is 1600 units wide; on a phone show the meaningful middle of it */
  .herofx__base svg,.herofx__lens svg{width:200%;height:150%}
  .hero--fx .hero__scrim{background:radial-gradient(120% 80% at 30% 45%,rgba(13,31,54,.5),rgba(13,31,54,.9))}
}
