/* =========================================================
   Biota Trace — Design System
   Palette derived from the brand logo:
     #035071 navy   #28baf1 cyan   #8bc53f lime   #2387c3 blue
   ========================================================= */

/* ---------- 1. Tokens ---------------------------------- */
:root{
  /* Brand — dark */
  --navy-900:#012029;
  --navy-800:#032d3a;
  --navy-700:#04455c;
  --navy-600:#035071;

  /* Brand — accents (safe on DARK surfaces) */
  --cyan:#28baf1;
  --cyan-600:#2387c3;
  --lime:#8bc53f;

  /* Brand — accents (safe on LIGHT surfaces, WCAG AA verified) */
  --cyan-ink:#0b7fae;   /* 4.51:1 on white */
  --cyan-deep:#0a719c;  /* 4.95:1 on --sky, for text on tinted surfaces */
  --lime-ink:#4f7a19;   /* 5.08:1 on white */

  /* Neutrals */
  --ink:#0d2b33;        /* 14.9:1 on white */
  --muted:#4a5f66;      /* 6.73:1 on white */
  --line:#dce7ea;
  --line-strong:#c3d6db;
  --surface:#ffffff;
  --pale:#f2f8ea;       /* lime tint */
  --sky:#eaf6fb;        /* cyan tint */
  --shell-bg:#f6fafb;

  /* On-dark text */
  --on-dark:#ffffff;
  --on-dark-soft:#c8dee6;  /* 9.8:1 on navy-800 */

  /* Spacing scale (4pt rhythm) */
  --space-1:4px;  --space-2:8px;   --space-3:12px; --space-4:16px;
  --space-5:24px; --space-6:32px;  --space-7:48px; --space-8:64px;
  --space-9:96px; --space-10:128px;

  /* Radii */
  --r-sm:8px; --r-md:12px; --r-lg:18px; --r-xl:26px; --r-pill:999px;

  /* Elevation */
  --sh-1:0 1px 2px rgba(1,32,41,.06), 0 2px 8px rgba(1,32,41,.05);
  --sh-2:0 4px 12px rgba(1,32,41,.07), 0 12px 32px rgba(1,32,41,.07);
  --sh-3:0 18px 50px rgba(1,32,41,.16);

  /* Layout */
  --max:1400px;
  --gutter:clamp(20px, 4vw, 48px);
  --frame:clamp(10px, 1.4vw, 20px);   /* inset of the rounded panels */

  /* Motion */
  --dur-1:140ms; --dur-2:240ms; --dur-3:420ms;
  --ease:cubic-bezier(.22,.61,.36,1);

  /* Type */
  --font-display:"Inter Tight","Inter",-apple-system,"Segoe UI",Arial,sans-serif;
  --font-body:"Inter Tight","Inter",-apple-system,"Segoe UI",Arial,sans-serif;
  --font-eyebrow:"Saira Semi Condensed","Arial Narrow",Arial,sans-serif;

  /* The header must sit ABOVE the drawer: the drawer is fixed inset:0 and
     would otherwise paint over the toggle, which is also the close button.
     Nothing can then dismiss the menu except following a link. */
  --z-header:1150; --z-dropdown:1000; --z-drawer:1100; --z-skip:1200;
}

/* ---------- 2. Reset & base ---------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{
  margin:0;
  font-family:var(--font-body);
  font-size:17px;
  line-height:1.6;
  color:var(--ink);
  background:var(--shell-bg);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img,svg,picture,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;margin:0;padding:0;cursor:pointer}
ul{margin:0;padding:0;list-style:none}

/* Visible, consistent focus for keyboard users */
:focus-visible{
  outline:3px solid var(--cyan);
  outline-offset:3px;
  border-radius:4px;
}
.dark :focus-visible,.hero :focus-visible,.cta :focus-visible{outline-color:var(--lime)}

.skip-link{
  position:absolute;left:var(--space-4);top:-100px;z-index:var(--z-skip);
  background:var(--navy-900);color:#fff;padding:14px 22px;border-radius:var(--r-sm);
  font-weight:700;transition:top var(--dur-1) var(--ease);
}
.skip-link:focus{top:var(--space-4)}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ---------- 3. Layout ---------------------------------- */
.shell{width:min(100% - (var(--gutter) * 2), var(--max));margin-inline:auto}

.section{padding-block:clamp(64px,8vw,112px)}
.panel{
  margin-inline:var(--frame);
  border-radius:var(--r-xl);
  overflow:hidden;
}
/* The tint has to survive further down the panel — at 65% it had faded to plain
   white by the time it reached the cards, so white cards had nothing to sit on */
.soft{background:linear-gradient(165deg,#e9f4da 0%,#f4f9ec 42%,#fbfdf8 100%)}
/* Same fix as .soft — the tint has to reach the cards, not fade out above them */
.sky-panel{background:linear-gradient(165deg,#dff0f8 0%,#eef7fb 42%,#fbfdfe 100%)}
.plain{background:#fff}
.dark{
  background:
    radial-gradient(120% 90% at 12% 0%, rgba(40,186,241,.16) 0%, transparent 55%),
    radial-gradient(90% 80% at 96% 100%, rgba(139,197,63,.14) 0%, transparent 55%),
    var(--navy-800);
  color:var(--on-dark);
}
.dark p,.dark .lead{color:var(--on-dark-soft)}

.split{
  display:grid;
  grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:clamp(32px,5vw,72px);
  align-items:center;
}
.split.reverse > *:first-child{order:2}
/* Top-align when one column is much shorter, so it does not float mid-row */
.split.top{align-items:start}
.center{text-align:center;max-width:820px;margin-inline:auto;margin-bottom:clamp(40px,5vw,64px)}
.center .lead{margin-inline:auto}

/* Two-column section intro: heading left, argument right. Use where a
   full-width figure follows — a single 820px column above a 1060px panel
   stacks two different measures and reads as a mismatch. */
.intro-split{margin-bottom:clamp(40px,5vw,64px)}
.intro-split > div > :last-child{margin-bottom:0}
/* Where an intro-split is the last thing in its shell, the section padding
   already provides the gap below it. */
.shell > .intro-split:last-child{margin-bottom:0}
/* Two intro-splits carrying one continuous thought: a rule reads them as two
   parts of a section rather than two sections that lost their grounds. */
.intro-split + .intro-split{
  border-top:1px solid var(--line);
  padding-top:clamp(36px,4.5vw,60px);
}
.dark .intro-split + .intro-split{border-top-color:rgba(255,255,255,.13)}

/* The one line in a block that carries the argument, lifted just enough to be
   found on a scan without becoming a second heading. */
.statement{
  color:var(--ink);
  font-size:clamp(17px,1.2vw,19px);
  font-weight:600;
  letter-spacing:-.01em;
  text-wrap:pretty;
}
/* As a standfirst under a heading it needs air above it, and the same left
   edge as the heading's TEXT.

   It used to sit flush against the container, which lines it up with the
   bracket accent rather than with the words. That put two text edges in one
   short column — eyebrow and standfirst at one, heading 23px inside it — and
   the standfirst read as though it had come loose from the heading above it.
   The accent bar is now the only thing outdented, which is the point of it. */
.intro-split h2 + .statement{margin-top:clamp(18px,2vw,26px)}
.intro-split h2.bracket + .statement{padding-left:clamp(20px,2.5vw,34px)}
/* Orientation for the figure directly below — quieter than body copy */
.figure-lead{font-size:15px;color:var(--muted)}

/* Left-anchored section intro. Use where the content below is full-width or
   left-anchored (a diagram, a table) — a centred intro over those reads as a
   mismatch, and it lets the .bracket accent sit against a real left edge. */
.intro{max-width:820px;margin-bottom:clamp(40px,5vw,64px)}
/* Heading-only intro sitting directly on top of the thing it titles */
.intro.tight{margin-bottom:clamp(20px,2.4vw,30px)}

/* Pulls a section up under a hero so a large figure reaches the fold sooner */
.section.pull-up{padding-top:clamp(36px,4vw,56px)}
/* Tightens the join where two sections carry one continuous thought */
.section.pull-down{padding-bottom:clamp(36px,4vw,56px)}
.section.tight-bottom{padding-bottom:clamp(18px,2vw,28px)}
.section.tight-top{padding-top:clamp(18px,2vw,28px)}
/* Two blocks inside one section: a single controlled gap, not two paddings */
.section > .shell + .shell{margin-top:clamp(44px,5vw,72px)}

.grid2,.grid3,.grid4,.grid5{display:grid;gap:clamp(16px,2vw,24px)}
.grid2{grid-template-columns:repeat(2,minmax(0,1fr))}
.grid3{grid-template-columns:repeat(3,minmax(0,1fr))}
.grid4{grid-template-columns:repeat(4,minmax(0,1fr))}
.grid5{grid-template-columns:repeat(5,minmax(0,1fr))}

/* ---------- 4. Typography ------------------------------ */
h1,h2,h3,h4{
  font-family:var(--font-display);
  font-weight:700;
  margin-top:0;
  line-height:1.08;
  letter-spacing:-.02em;
  text-wrap:balance;
}
h1{font-size:clamp(40px,5.4vw,74px);margin-bottom:var(--space-5);letter-spacing:-.03em}
h2{font-size:clamp(30px,3.6vw,52px);margin-bottom:var(--space-5)}
h3{font-size:clamp(20px,1.5vw,25px);margin-bottom:var(--space-3);letter-spacing:-.015em}

p{margin:0 0 var(--space-4)}
p:last-child{margin-bottom:0}

.lead{
  font-size:clamp(17px,1.25vw,20px);
  line-height:1.65;
  max-width:65ch;
  color:var(--muted);
}
.dark .lead{color:var(--on-dark-soft)}

.eyebrow{
  font-family:var(--font-eyebrow);
  font-size:14px;
  font-weight:600;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--lime-ink);
  margin-bottom:var(--space-4);
  display:flex;
  align-items:center;
  gap:10px;
}
.eyebrow::before{
  content:"";
  width:26px;height:2px;flex:none;
  background:currentColor;
  border-radius:2px;
}
.center .eyebrow{justify-content:center}
.dark .eyebrow,.hero .eyebrow,.cta .eyebrow{color:var(--lime)}

/* Left bracket accent on a feature heading */
.bracket{position:relative;padding-left:clamp(20px,2.5vw,34px)}
.bracket::before{
  content:"";position:absolute;left:0;top:.14em;bottom:.14em;
  width:5px;border-radius:5px;
  background:linear-gradient(180deg,var(--lime),var(--cyan));
}

/* ---------- 5. Buttons & links ------------------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  min-height:48px;                    /* comfortable pointer/touch target */
  padding:13px 26px;
  border-radius:var(--r-sm);
  font-weight:650;
  font-size:16px;
  letter-spacing:-.01em;
  cursor:pointer;
  background:var(--lime);
  color:var(--navy-900);              /* 7.05:1 — white would fail at 2.07:1 */
  border:1px solid transparent;
  transition:transform var(--dur-1) var(--ease),
             box-shadow var(--dur-2) var(--ease),
             background-color var(--dur-2) var(--ease);
  box-shadow:var(--sh-1);
}
.btn:hover{background:#9ad24d;transform:translateY(-2px);box-shadow:var(--sh-2)}
.btn:active{transform:translateY(0)}

.btn.blue{background:var(--cyan);color:var(--navy-900)}   /* 6.52:1 */
.btn.blue:hover{background:#48c8f8}

.btn.ghost{
  background:transparent;color:#fff;
  border-color:rgba(255,255,255,.45);box-shadow:none;
}
.btn.ghost:hover{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.8)}

.btn.outline{
  background:#fff;color:var(--navy-600);border-color:var(--line-strong);
}
.btn.outline:hover{background:var(--sky);border-color:var(--cyan)}

.btn .ico{width:18px;height:18px;flex:none;transition:transform var(--dur-2) var(--ease)}
.btn:hover .ico{transform:translateX(3px)}

.actions{display:flex;gap:var(--space-3);flex-wrap:wrap;margin-top:var(--space-6)}
.actions-center{justify-content:center;margin-top:clamp(32px,4vw,48px)}

/* Inline link inside body copy. The global reset strips underline and colour
   from every <a>, which is right for nav, cards and buttons but leaves a
   link in a paragraph indistinguishable from the text around it. */
.inline-link{
  color:var(--cyan-deep);
  text-decoration:underline;
  text-underline-offset:3px;
  text-decoration-thickness:1px;
}
.inline-link:hover{color:var(--navy-600);text-decoration-thickness:2px}
.dark .inline-link{color:var(--cyan)}
/* A name that links out. The glyph says where to, so the link does not have to
   announce itself in words — the sentence stays about the company. */
.inline-link.named{
  white-space:nowrap;
  text-decoration-color:rgba(10,113,156,.35);
}
.inline-link.named:hover{text-decoration-color:currentColor}
.inline-link.named svg{
  /* the global reset sets svg{display:block}, which breaks the line inside an
     inline link however hard white-space:nowrap tries */
  display:inline-block;
  width:11px;height:11px;
  margin-left:5px;
  vertical-align:baseline;
  opacity:.7;
}

.text-link{
  display:inline-flex;align-items:center;gap:8px;
  font-weight:650;color:var(--cyan-ink);
  min-height:32px;
  transition:gap var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.text-link:hover{gap:13px;color:var(--navy-600)}
.text-link .ico{width:16px;height:16px;flex:none}
.dark .text-link{color:var(--cyan)}
.dark .text-link:hover{color:var(--lime)}

/* ---------- 6. Header & navigation --------------------- */
.site-header{
  position:fixed;inset:0 0 auto 0;
  z-index:var(--z-header);
  padding-block:clamp(14px,1.8vw,22px);
  transition:background-color var(--dur-3) var(--ease),
             box-shadow var(--dur-3) var(--ease),
             padding var(--dur-3) var(--ease);
}
/* Solid, legible bar once the hero has scrolled past */
.site-header.is-stuck{
  background:rgba(1,32,41,.92);
  -webkit-backdrop-filter:blur(18px);
  backdrop-filter:blur(18px);
  box-shadow:0 1px 0 rgba(255,255,255,.08), 0 10px 30px rgba(1,32,41,.28);
  padding-block:10px;
}

.nav{display:flex;align-items:center;justify-content:space-between;gap:var(--space-5)}

.logo{display:flex;align-items:center;flex:none;border-radius:6px}
.logo img{width:clamp(150px,14vw,192px);height:auto}

.links{
  display:flex;align-items:center;gap:2px;
  background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.16);
  -webkit-backdrop-filter:blur(20px) saturate(140%);
  backdrop-filter:blur(20px) saturate(140%);
  border-radius:var(--r-md);
  padding:5px 5px 5px 10px;
}
.is-stuck .links{background:rgba(255,255,255,.07)}

.nav-item{position:relative}
.nav-link{
  display:flex;align-items:center;gap:6px;
  padding:12px 15px;
  min-height:44px;
  border-radius:var(--r-sm);
  color:#fff;
  font-size:15.5px;
  font-weight:600;
  white-space:nowrap;
  transition:background-color var(--dur-1) var(--ease),color var(--dur-1) var(--ease);
}
.nav-link:hover{background:rgba(255,255,255,.14)}
.nav-link[aria-current="page"],
.nav-link.is-current{background:rgba(255,255,255,.16)}
.dropdown a[aria-current="page"]{background:var(--sky);color:var(--cyan-ink)}
.caret{width:12px;height:12px;flex:none;transition:transform var(--dur-2) var(--ease);opacity:.8}
.nav-item.is-open .caret{transform:rotate(180deg)}

.contact-nav{
  background:var(--cyan);
  color:var(--navy-900);
  font-weight:700;
  padding:12px 22px;
  margin-left:8px;
}
.contact-nav:hover{background:#48c8f8}

/* Dropdown — opens on hover AND on keyboard focus */
.dropdown{
  position:absolute;top:calc(100% + 8px);left:0;
  width:330px;
  background:#fff;
  border-radius:var(--r-md);
  border-top:4px solid var(--cyan);
  padding:8px;
  box-shadow:var(--sh-3);
  z-index:var(--z-dropdown);
  opacity:0;visibility:hidden;pointer-events:none;
  transform:translateY(8px);
  transition:opacity var(--dur-2) var(--ease),
             transform var(--dur-2) var(--ease),
             visibility var(--dur-2) var(--ease);
}
/* The menu sits 8px below its trigger. That gap is dead space — a pointer
   crossing it hovers neither element, so the menu closes mid-reach. This pad
   spans the gap and is part of the menu, so the hover never breaks. It is
   inert while the menu is closed, because the menu is pointer-events:none. */
.dropdown::before{
  content:"";
  position:absolute;
  /* 12 = the 8px gap + the menu's 4px top border. An absolutely positioned
     pseudo-element offsets from its parent's PADDING box, which sits below
     that border, so -8px would leave the top 4px of the gap uncovered. */
  left:0;right:0;top:-12px;
  height:12px;
}

.dropdown a{
  display:block;
  padding:12px 14px;
  border-radius:var(--r-sm);
  color:var(--navy-800);
  font-size:15.5px;
  font-weight:600;
  transition:background-color var(--dur-1) var(--ease),color var(--dur-1) var(--ease);
}
.dropdown a:hover{background:var(--sky);color:var(--cyan-ink)}

@media (hover:hover) and (min-width:1101px){
  .nav-item.has-dropdown:hover > .dropdown{
    opacity:1;visibility:visible;pointer-events:auto;transform:translateY(0);
  }
}
/* Keyboard: focus inside the item reveals it (previously this was suppressed) */
.nav-item.has-dropdown:focus-within > .dropdown,
.nav-item.has-dropdown.is-open > .dropdown{
  opacity:1;visibility:visible;pointer-events:auto;transform:translateY(0);
}

/* Mobile drawer trigger */
.nav-toggle{
  display:none;
  width:48px;height:48px;
  align-items:center;justify-content:center;
  border-radius:var(--r-sm);
  background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.18);
  color:#fff;
}
.nav-toggle svg{width:24px;height:24px}
.nav-toggle .icon-close{display:none}
.nav-toggle[aria-expanded="true"] .icon-open{display:none}
.nav-toggle[aria-expanded="true"] .icon-close{display:block}

.drawer{
  position:fixed;inset:0;
  z-index:var(--z-drawer);
  background:var(--navy-900);
  padding:96px var(--gutter) var(--space-7);
  overflow-y:auto;
  overscroll-behavior:contain;
  opacity:0;visibility:hidden;
  transition:opacity var(--dur-2) var(--ease),visibility var(--dur-2) var(--ease);
}
.drawer.is-open{opacity:1;visibility:visible}
.drawer a{
  display:block;color:#fff;font-size:19px;font-weight:600;
  padding:15px 0;min-height:48px;
  border-bottom:1px solid rgba(255,255,255,.10);
}
.drawer .sub a{font-size:16px;font-weight:500;color:var(--on-dark-soft);padding-left:var(--space-4)}
.drawer .group-label{
  font-family:var(--font-eyebrow);font-size:13px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--lime);margin-top:var(--space-6);margin-bottom:var(--space-2);
}
/* .drawer a sets colour, display:block and a divider for the nav links, and
   out-specifies .btn — which turned the button text white on lime (2.07:1,
   exactly the failure .btn warns about in its own comment) and flattened the
   button's centring flexbox, leaving the label against the left edge of a
   full-width button. Restore both. */
.drawer .btn{
  margin-top:var(--space-6);
  width:100%;
  color:var(--navy-900);
  border-bottom:1px solid transparent;
  text-align:center;
}

/* ---------- 7. Hero ------------------------------------ */
.hero{
  position:relative;
  margin:var(--frame) var(--frame) 0;
  border-radius:var(--r-xl);
  overflow:hidden;
  min-height:min(92vh,860px);
  display:flex;
  align-items:center;
  color:#fff;
  isolation:isolate;
  background:var(--navy-900) center/cover no-repeat;
}
.hero-media{position:absolute;inset:0;z-index:-2}
/* <picture> is inline by default and collapses to intrinsic height,
   which would leave the img short of the hero's full height */
.hero-media picture{display:block;width:100%;height:100%}
.hero-media img{
  width:100%;height:100%;
  object-fit:cover;
  object-position:50% 42%;
  /* Slow, subtle drift — disabled under reduced motion */
  animation:heroDrift 32s var(--ease) infinite alternate;
}
@keyframes heroDrift{
  from{transform:scale(1.04) translate3d(0,0,0)}
  to{transform:scale(1.11) translate3d(-1.2%,-1%,0)}
}
/* Scrim: keeps the headline legible over a busy aerial photo */
.hero::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background:
    linear-gradient(100deg,
      rgba(1,32,41,.94) 0%,
      rgba(1,32,41,.86) 34%,
      rgba(1,32,41,.55) 62%,
      rgba(1,32,41,.30) 100%),
    linear-gradient(0deg, rgba(1,32,41,.75) 0%, transparent 45%);
}

/* Sits inside .shell rather than being one, so the 880px measure caps the text
   without re-centring the block — the headline lines up with the left gutter
   that every section below uses. */
.hero-copy{
  position:relative;z-index:2;
  /* Optically centred rather than mathematically: the fixed header covers ~104px
     of the top, so the top padding carries that much extra to keep the open space
     above and below the copy looking even. */
  padding-block:clamp(150px,16vw,200px) clamp(90px,11vw,136px);
  max-width:min(100%,880px);
  margin-inline:0;
}
.hero .lead{color:#e8f3f6;font-size:clamp(18px,1.45vw,22px);max-width:62ch}

/* Compact hero for interior pages */
.hero-mini{
  margin:var(--frame) var(--frame) 0;
  border-radius:var(--r-xl);
  padding:clamp(150px,18vw,200px) 0 clamp(56px,7vw,88px);
  background:
    radial-gradient(90% 120% at 90% 10%, rgba(40,186,241,.22), transparent 60%),
    linear-gradient(135deg,var(--navy-900),var(--navy-600));
  color:#fff;
}
.hero-mini .lead{color:var(--on-dark-soft)}
/* Shorter hero for pages that lead with a large figure — the top value still
   clears the fixed header */
.hero-mini.tight{padding:clamp(132px,15vw,164px) 0 clamp(40px,5vw,56px)}

/* ---------- 8. Cards ----------------------------------- */
.card{
  position:relative;
  background:#fff;
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  padding:clamp(24px,2.2vw,32px);
  display:flex;flex-direction:column;
  box-shadow:var(--sh-1);          /* resting elevation — without it the card edge disappears */
  transition:transform var(--dur-2) var(--ease),
             box-shadow var(--dur-2) var(--ease),
             border-color var(--dur-2) var(--ease);
}
.card:hover{transform:translateY(-4px);box-shadow:var(--sh-2);border-color:var(--line-strong)}
.card p{color:var(--muted);flex:1}
.card .text-link{margin-top:var(--space-4)}

.dark .card{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.14)}
.dark .card:hover{background:rgba(255,255,255,.10);border-color:rgba(40,186,241,.45)}
.dark .card h3{color:#fff}
.dark .card p{color:var(--on-dark-soft)}

/* Card with a photo across the top.
   To drop in real artwork, replace the .ph block inside .card-media with:
   <img src="images/your-photo.webp" alt="..." loading="lazy" decoding="async"> */
.card.has-media{padding:0;overflow:hidden}
.card-media{
  position:relative;
  aspect-ratio:var(--media-ratio, 16/10);  /* reserves space so swapping in a photo causes no shift */
  background:linear-gradient(150deg,#e6f2f5,#f7fbfc);
  border-bottom:1px solid var(--line);
  overflow:hidden;
}
/* Media frames on a dark panel — the light gradient and dark glyphs are
   unreadable there */
.dark .card-media{
  background:linear-gradient(150deg,#083b4e,#0b4a60);
  border-bottom-color:rgba(255,255,255,.14);
}
.dark .card-media .ph{color:var(--on-dark-soft)}
.dark .card-media .ph svg{color:var(--cyan);opacity:.85}
.dark .card-media .ph-note{color:var(--cyan)}
.dark .card-media .ph::before{border-color:rgba(255,255,255,.22)}

/* Sub-heading grouping related cards inside one section */
.group-header{
  margin:clamp(40px,4.5vw,60px) 0 clamp(18px,2vw,24px);
  padding-bottom:var(--space-4);
  border-bottom:1px solid var(--line-strong);
}
.group-header h3{
  font-size:clamp(20px,1.7vw,26px);
  margin-bottom:6px;
}
.group-header p{
  margin:0;font-size:16px;color:var(--muted);max-width:70ch;
}
.dark .group-header{border-bottom-color:rgba(255,255,255,.16)}
.dark .group-header h3{color:#fff}
.dark .group-header p{color:var(--on-dark-soft)}

/* Studio-knockout variant: squarer frame, near-white ground, product not cropped.
   Unused while the photography is field-shot — switch a card to this once
   cut-out product shots on a plain background are available. */
.card-media.shot{
  --media-ratio:4/3;
  background:linear-gradient(170deg,#fbfdfd 0%,#eef5f7 100%);
}
.card-media.shot img{
  object-fit:contain;
  padding:6%;
  /* Mockups arrive on a solid white ground. Multiply drops that white out
     against the frame's tint so there is no visible rectangle seam; the
     devices and their screens composite normally. Degrades to plain
     rendering anywhere the blend mode is unsupported. */
  mix-blend-mode:multiply;
}
.card-media img{width:100%;height:100%;object-fit:cover}
.card-media .ph{
  position:absolute;inset:0;
  display:grid;place-content:center;justify-items:center;gap:10px;
  text-align:center;padding:20px;
  color:var(--muted);
}
.card-media .ph svg{width:30px;height:30px;color:var(--cyan-deep);opacity:.7}
.card-media .ph-note{
  font-family:var(--font-eyebrow);
  font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;font-weight:600;
  color:var(--cyan-deep);
}
/* Hairline grid so an empty frame still reads as a deliberate slot */
.card-media .ph::before{
  content:"";position:absolute;inset:12px;
  border:1px dashed var(--line-strong);
  border-radius:var(--r-sm);
  pointer-events:none;
}
.card-body{
  display:flex;flex-direction:column;flex:1;
  padding:clamp(24px,2.2vw,32px);
}
/* The paragraph absorbs the slack so anything after it (a link) sits on the
   card's baseline. With more than one paragraph only the last should grow —
   otherwise the flex space is split between them and they drift apart. */
.card-body p{margin-bottom:var(--space-3)}
.card-body p:last-of-type{flex:1;margin-bottom:0}
.card.has-media:hover .card-media img{transform:scale(1.03)}
.card-media img{transition:transform var(--dur-3) var(--ease)}

/* Visual entry point for text-only cards, which otherwise read as grey blocks */
.card-icon{
  width:48px;height:48px;
  display:grid;place-items:center;
  border-radius:var(--r-sm);
  background:linear-gradient(140deg,var(--sky),#dff0f8);
  color:var(--cyan-ink);
  margin-bottom:var(--space-4);
  flex:none;
}
.card-icon svg{width:24px;height:24px}
.dark .card-icon{background:rgba(40,186,241,.16);color:var(--cyan)}

.tag{
  display:inline-block;
  align-self:flex-start;
  font-family:var(--font-eyebrow);
  font-size:12px;text-transform:uppercase;letter-spacing:.14em;font-weight:600;
  color:var(--cyan-deep);                /* 4.95:1 on the --sky pill; --cyan-ink is only 4.09:1 there */
  background:var(--sky);
  border-radius:var(--r-pill);
  padding:5px 12px;
  margin-bottom:var(--space-4);
}
.dark .tag{background:rgba(40,186,241,.16);color:var(--cyan)}

.card-note{
  margin-top:var(--space-4);
  padding-top:var(--space-3);
  border-top:1px solid var(--line);
  font-size:14px;
  color:var(--muted);
}
.dark .card-note{border-top-color:rgba(255,255,255,.16);color:var(--on-dark-soft)}

/* ---------- 9. Media frames ---------------------------- */
.media{
  position:relative;
  border-radius:var(--r-lg);
  overflow:hidden;
  aspect-ratio:4/3;                    /* reserves space → no layout shift */
  background:linear-gradient(150deg,#e6f2f5,#fbfdfd);
  border:1px solid var(--line);
  box-shadow:var(--sh-1);
  margin:0;
}
.media img{width:100%;height:100%;object-fit:cover}

/* Deliberate, styled placeholder for assets still to be shot */
.media.placeholder{
  display:grid;place-content:center;justify-items:center;gap:10px;
  text-align:center;padding:32px;
  border-style:dashed;border-color:var(--line-strong);
  color:var(--muted);
}
.media.placeholder svg{width:34px;height:34px;color:var(--cyan-ink);opacity:.75}
.media.placeholder .ph-title{font-weight:700;color:var(--navy-600);font-size:16px}
.media.placeholder .ph-note{font-size:14px;max-width:34ch}
.media.darkmedia{
  background:linear-gradient(150deg,#063445,#0d5468);
  border-color:rgba(255,255,255,.16);color:var(--on-dark-soft);
}
.media.darkmedia .ph-title{color:#fff}
.media.darkmedia svg{color:var(--cyan)}

/* ---------- 9b. Video well ----------------------------- */
/* Single overview film. To go live, replace the .ph block with:
   <video poster="images/platform-poster.webp" controls preload="none" playsinline>
     <source src="images/platform-overview.mp4" type="video/mp4">
   </video>
   Keep preload="none" — this is the heaviest asset on the page. */
/* Diagram alternative to the film. A labelled schematic reads instantly at the
   ~500px this column gives us, where a muted 60s video would not — and it can
   name gateway / EASI precisely, which footage cannot. */
.diagram-well{
  position:relative;
  aspect-ratio:16/9;
  border-radius:var(--r-lg);
  overflow:hidden;
  background:linear-gradient(150deg,#06384a,#0b5066);
  border:1px solid rgba(255,255,255,.16);
  box-shadow:var(--sh-3);
}
.diagram-well svg{
  display:block;width:100%;height:100%;
  font-family:var(--font-display);
}

.video-well{
  position:relative;
  aspect-ratio:16/9;
  border-radius:var(--r-lg);
  overflow:hidden;
  background:linear-gradient(150deg,#06384a,#0b5066);
  border:1px solid rgba(255,255,255,.16);
  box-shadow:var(--sh-3);
}
.video-well video,.video-well img{width:100%;height:100%;object-fit:cover;display:block}
/* A film sitting inside a .media figure shares the frame with its neighbour,
   so the row reads as one media block rather than a photo row with a video
   bolted underneath. */
.media .video-well{border:0;box-shadow:none;border-radius:0;margin:0;max-width:none}
/* Two figures sharing one column of a .split, for sections whose text column
   runs long enough that a single frame leaves half the column empty. */
.media-stack{display:grid;gap:clamp(14px,1.6vw,20px);align-content:start}

/* This row pairs a 16:9 film with a 16:9 still, so the figures match their
   content instead of the default 4:3 — which left a band of empty ground under
   the film once the captions came off. */
.form-factors .media{aspect-ratio:16/9}
.media .video-well video{border-radius:0}

/* Single supporting photo under a product block — same measure as a film so
   the two product sections stay visually consistent. */
/* Two stills under a product block, filling the shell edge to edge instead of
   one frame floating centred at half width. Both sources are 16:10, so the
   frames match their content and neither is cropped. */
.shot-pair{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(16px,2vw,24px);
  margin-top:clamp(32px,4vw,48px);
}
.shot-pair .media{aspect-ratio:16/10}
@media (max-width:760px){
  .shot-pair{grid-template-columns:minmax(0,1fr)}
}

/* A closing note under a step list. Indented to the step text, not the list
   edge — otherwise it lines up with the icon gutter and reads as a fifth step
   that has lost its icon. The rule above marks it as a coda, not another step. */
.step-note{
  margin-top:clamp(20px,2.4vw,30px);
  padding-left:62px;              /* 44px icon + 18px gap */
  font-size:15.5px;color:var(--muted);max-width:70ch;
}
.step-note::before{
  content:"";display:block;
  width:44px;height:1px;
  background:var(--line-strong);
  margin-bottom:clamp(16px,1.8vw,22px);
}
.dark .step-note{color:var(--on-dark-soft)}
.dark .step-note::before{background:rgba(255,255,255,.22)}
@media (max-width:640px){
  .step-note{padding-left:0}
}

/* Two form factors shown side by side, directly under the copy that claims
   the range exists. */
.form-factors{margin-top:clamp(32px,4vw,48px)}

/* Product block: the heading sits above its own body copy, and the checklist
   starts level with the first paragraph rather than level with the tag — which
   otherwise leaves the right column ending 280px short of the left. Explicit
   grid placement keeps that alignment without hard-coding an offset. */
.product-grid{
  display:grid;
  grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  column-gap:clamp(32px,5vw,72px);
  /* rows carry their own margins, so no row gap */
  row-gap:0;
  align-items:start;
}
.pg-head{grid-column:1;grid-row:1}
/* Acronym expansion under a product name. Set in the eyebrow face but without
   the tag's pill, so it reads as a subtitle rather than a second label. */
.pg-sub{
  font-family:var(--font-eyebrow);
  text-transform:uppercase;
  letter-spacing:.14em;
  font-size:12.5px;font-weight:600;
  color:var(--muted);
  margin:-2px 0 0;
}
.pg-lead{grid-column:1;grid-row:2;margin-bottom:var(--space-5)}
.pg-body{grid-column:1;grid-row:3}
/* The card starts on the lead's row, so its top edge is level with the lead
   rather than with the tag above it, and spans down past the body copy. */
.pg-list{grid-column:2;grid-row:2 / span 2;align-self:start}
/* Set as a card so the checklist reads as a distinct object rather than merging
   into the body copy beside it. Beats .feature-list{margin-top}. */
.feature-list.pg-list{
  margin-top:0;
  background:rgba(255,255,255,.72);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  padding:clamp(20px,2.2vw,28px);
}
@media (max-width:900px){
  .product-grid{grid-template-columns:minmax(0,1fr)}
  .pg-head,.pg-lead,.pg-body,.pg-list{grid-column:1;grid-row:auto}
}


.video-well .ph{
  position:absolute;inset:0;
  display:grid;place-content:center;justify-items:center;gap:12px;
  text-align:center;padding:24px;
}
.video-well .play{
  width:64px;height:64px;
  display:grid;place-items:center;
  border-radius:50%;
  background:var(--lime);
  color:var(--navy-900);
  box-shadow:0 8px 26px rgba(1,32,41,.4);
}
.video-well .play svg{width:26px;height:26px;margin-left:3px}
.video-well .ph-title{color:#fff;font-weight:700;font-size:17px}
.video-well .ph-note{
  font-family:var(--font-eyebrow);
  font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--cyan);
}
.video-well .ph::before{
  content:"";position:absolute;inset:14px;
  border:1px dashed rgba(255,255,255,.22);
  border-radius:var(--r-sm);
  pointer-events:none;
}

/* ---------- 10. Flow / steps --------------------------- */
.flow{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-3);margin-top:var(--space-6)}
/* Light is the default: this component was dark-only, which rendered white
   headings on a white section at 1.05:1. Dark styling is now scoped to .dark. */
.flow .step{
  position:relative;
  background:#fff;
  border:1px solid var(--line);
  border-radius:var(--r-md);
  padding:22px 20px;
  box-shadow:var(--sh-1);
}
.flow .step h3{margin-bottom:8px;font-size:19px;color:var(--ink)}
.flow .step h3:last-child{margin-bottom:0}
.flow .step p{margin:0;font-size:15px;color:var(--muted)}

.dark .flow .step{
  background:rgba(255,255,255,.07);
  border-color:rgba(255,255,255,.14);
  box-shadow:none;
}
.dark .flow .step h3{color:#fff}
.dark .flow .step p{color:var(--on-dark-soft)}
.num{
  display:block;
  font-family:var(--font-eyebrow);
  font-size:12px;font-weight:600;letter-spacing:.2em;
  color:var(--cyan-ink);margin-bottom:8px;
}
.dark .num{color:var(--cyan)}
.flow .step:not(:last-child)::after{
  content:"";position:absolute;right:-11px;top:50%;
  width:10px;height:10px;
  border-top:2px solid var(--cyan-ink);border-right:2px solid var(--cyan-ink);
  transform:translateY(-50%) rotate(45deg);
  opacity:.7;
}
/* Stacked variant — used when the flow sits in a narrow split column */
.dark .flow .step:not(:last-child)::after{border-top-color:var(--cyan);border-right-color:var(--cyan)}
.flow.vertical{grid-template-columns:minmax(0,1fr);gap:var(--space-4)}
.flow.vertical .step{display:flex;align-items:baseline;gap:16px}
.flow.vertical .num{margin-bottom:0;flex:none}
.flow.vertical .step:not(:last-child)::after{
  right:auto;left:34px;top:auto;bottom:-13px;
  transform:rotate(135deg);
}

/* ---------- 9c. Full-width diagram panel --------------- */
.diagram-panel{
  position:relative;
  border-radius:var(--r-lg);
  overflow:hidden;
  background:linear-gradient(150deg,#eaf5fa 0%,#fbfdfe 60%);
  border:1px solid #cbe4ef;
  box-shadow:var(--sh-2);
  padding:clamp(18px,2.4vw,30px);
}
/* an img in a diagram panel needs the same treatment as an svg, or the height
   attribute is taken literally and the aspect ratio breaks */
.diagram-panel img,
.diagram-panel svg{
  display:block;width:100%;height:auto;
  font-family:var(--font-display);
}
.diagram-panel.on-dark{
  background:linear-gradient(150deg,#06384a,#0b5066);
  border-color:rgba(255,255,255,.16);
  box-shadow:var(--sh-3);
}
/* Linked diagram nodes: the box naming a product is the thing you click,
   so the figure carries the route instead of a separate list beneath it */
.diagram-panel a{cursor:pointer}

/* On a phone these diagrams scale to about a third, which drops their smallest
   labels to 3-6px — unreadable. Enlarging the type is not an option: the
   labels sit at fixed x positions and collide as soon as they grow. So width
   is the lever. Below 720px the diagram keeps a legible minimum width and the
   panel scrolls, with the same shadows the comparison table uses to show that
   there is more to see. */
@media (max-width:720px){
  .diagram-panel{
    overflow-x:auto;
    overscroll-behavior-x:contain;
    -webkit-overflow-scrolling:touch;
    background:
      linear-gradient(to right, #eaf5fa, rgba(234,245,250,0)) 0 0 / 26px 100% no-repeat local,
      linear-gradient(to left,  #fbfdfe, rgba(251,253,254,0)) 100% 0 / 26px 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%,    rgba(1,32,41,.18), rgba(1,32,41,0)) 0 0 / 14px 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, rgba(1,32,41,.18), rgba(1,32,41,0)) 100% 0 / 14px 100% no-repeat scroll,
      linear-gradient(150deg,#eaf5fa 0%,#fbfdfe 60%);
  }
  /* 780 rather than 620: the denser of the two diagrams still only reached
     7.9px at 620. At 780 its smallest label is ~10px and the simpler one
     ~15px, at the cost of about two screens of panning. */
  .diagram-panel img,
  .diagram-panel svg{min-width:780px}
}
.diagram-panel a rect{transition:stroke var(--dur-2) var(--ease), fill var(--dur-2) var(--ease)}
.diagram-panel a:hover rect,
.diagram-panel a:focus-visible rect{stroke:#0b7fae;stroke-width:2;fill:#f2fafd}
.diagram-panel a:focus-visible{outline:3px solid var(--cyan);outline-offset:2px}

.diagram-caption{
  margin-top:var(--space-4);
  text-align:center;
  font-size:15px;
  color:var(--muted);
  max-width:70ch;margin-inline:auto;
}
.on-dark + .diagram-caption{color:var(--on-dark-soft)}

/* ---------- 9d. Uses grid ------------------------------ */
/* One product shown in several settings. Uniform portrait frames so the set
   reads as a range of uses rather than five unrelated photographs. */
.uses-grid{
  display:grid;
  grid-template-columns:repeat(5,minmax(0,1fr));
  gap:clamp(12px,1.4vw,18px);
}
.uses-grid figure{margin:0}
.use-shot{
  position:relative;
  aspect-ratio:4/5;
  border-radius:var(--r-md);
  overflow:hidden;
  background:var(--sky);
  border:1px solid var(--line);
  box-shadow:var(--sh-1);
}
.use-shot img{
  width:100%;height:100%;object-fit:cover;
  transition:transform var(--dur-3) var(--ease);
}
.uses-grid figure:hover .use-shot img{transform:scale(1.04)}
.use-label{
  display:block;
  margin-top:var(--space-3);
  font-size:15.5px;font-weight:650;color:var(--ink);
  line-height:1.3;
}
.use-note{
  display:block;
  margin-top:3px;
  font-size:13.5px;color:var(--muted);line-height:1.4;
}
@media (max-width:1100px){ .uses-grid{grid-template-columns:repeat(3,minmax(0,1fr))} }
@media (max-width:640px){  .uses-grid{grid-template-columns:repeat(2,minmax(0,1fr))} }

/* ---------- 10b. Step list ----------------------------- */
/* Icon + heading + description, stacked vertically beside a sticky intro column */
.step-list{
  --step-gap:clamp(26px,3vw,38px);
  display:grid;gap:var(--step-gap);
  margin:0;padding:0;list-style:none;
}
.step-list li{position:relative;display:flex;gap:18px;align-items:flex-start}
/* Light by default, dark scoped under .dark — same fix as .flow needed */
.s-icon{
  width:44px;height:44px;flex:none;
  display:grid;place-items:center;
  border-radius:var(--r-sm);
  background:var(--sky);
  border:1px solid #cbe4ef;
  color:var(--cyan-deep);   /* 4.95:1 on --sky, matching .tag */
}
.dark .s-icon{
  background:rgba(40,186,241,.14);
  border-color:rgba(40,186,241,.30);
  color:var(--cyan);
}
.s-icon svg{width:22px;height:22px}
/* Connector rule: carries the sense of progression the 01–04 numbers used to */
.step-list li:not(:last-child)::before{
  content:"";position:absolute;
  left:22px;top:52px;
  height:calc(100% - 52px + var(--step-gap));
  width:1px;
  background:linear-gradient(180deg,#a9c9d8,rgba(169,201,216,0));
}
.dark .step-list li:not(:last-child)::before{
  background:linear-gradient(180deg,rgba(40,186,241,.40),rgba(40,186,241,.04));
}
.s-body h3{margin:0 0 8px;font-size:clamp(19px,1.4vw,22px);color:var(--ink)}
.s-body p{margin:0;color:var(--muted);font-size:16px;line-height:1.6}
.dark .s-body h3{color:#fff}
.dark .s-body p{color:var(--on-dark-soft)}

/* Split with a rule between the columns and an intro that stays put while
   the taller list scrolls past it */
.split.divided{align-items:start}
@media (min-width:901px){
  .split.divided > *:last-child{
    border-left:1px solid var(--line-strong);
    padding-left:clamp(32px,4vw,60px);
  }
  .dark .split.divided > *:last-child{border-left-color:rgba(255,255,255,.13)}
  .sticky-col{position:sticky;top:110px}
}

/* ---------- 11. CTA ------------------------------------ */
.cta{
  position:relative;
  margin:var(--frame);
  border-radius:var(--r-xl);
  overflow:hidden;
  padding-block:clamp(64px,8vw,104px);
  background:
    radial-gradient(80% 130% at 15% 0%, rgba(40,186,241,.26), transparent 60%),
    radial-gradient(70% 120% at 90% 100%, rgba(139,197,63,.22), transparent 60%),
    linear-gradient(135deg,var(--navy-900),var(--navy-600));
  color:#fff;
}
.cta-inner{max-width:820px;margin-inline:auto;text-align:center}
.cta-inner .eyebrow{justify-content:center}
.cta-inner .lead{color:var(--on-dark-soft);margin-inline:auto}
.cta-inner .actions{justify-content:center}

/* Slim mid-page variant — same surface, laid out as a horizontal band
   so it punctuates the page instead of halting it like the closing CTA */
.cta.slim{padding-block:clamp(30px,3.4vw,44px)}
.cta.slim .cta-inner{
  max-width:none;text-align:left;
  display:flex;align-items:center;justify-content:space-between;
  gap:clamp(20px,3vw,48px);
  flex-wrap:wrap;
}
.cta.slim .cta-text{flex:1 1 420px;min-width:0}
.cta.slim .eyebrow{justify-content:flex-start;margin-bottom:10px}
.cta.slim h2{font-size:clamp(22px,2.3vw,31px);margin-bottom:6px}
.cta.slim .lead{
  font-size:clamp(15.5px,1.05vw,17px);
  margin-inline:0;max-width:78ch;
  text-wrap:pretty;
}
.cta.slim .actions{margin-top:0;flex:none;justify-content:flex-start}

/* Ways in — the three commercial arrangements, ordered by how much the
   customer takes on. The meter encodes that progression so the argument is
   visible rather than just asserted. Body text is set brighter than
   --on-dark-soft because the CTA gradient's cyan corner lifts the ground. */

.ladder{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(22px,3vw,44px);
  max-width:1100px;
  margin:clamp(34px,4vw,50px) auto 0;
  text-align:left;
}
.ladder-meter{display:flex;gap:5px;margin-bottom:16px}
.ladder-meter i{
  height:4px;flex:1 1 0;border-radius:999px;
  background:rgba(255,255,255,.18);
}
.ladder-meter i.on{background:var(--lime)}
.ladder-step h3{
  font-size:clamp(17px,1.35vw,20px);
  color:#fff;margin:0 0 9px;letter-spacing:-.01em;
}
.ladder-step p{font-size:15px;line-height:1.55;color:#dceaf0;margin:0}
.ladder-step .ladder-note{
  margin-top:12px;
  padding-left:12px;
  border-left:2px solid var(--lime);
  font-size:13.5px;line-height:1.5;
}

.ladder-foot{
  max-width:820px;
  margin:clamp(34px,4vw,48px) auto 0;
  padding-top:clamp(26px,3vw,34px);
  border-top:1px solid rgba(255,255,255,.18);
  text-align:center;
}
.ladder-foot p{
  color:#dceaf0;
  font-size:clamp(15.5px,1.05vw,17px);
  margin:0 0 12px;
  text-wrap:pretty;
}
/* The ask that leads into the buttons carries more weight than the summary
   line above it, so the section closes on the question rather than the terms */
.ladder-foot .ladder-ask{
  color:#fff;
  font-size:clamp(17px,1.25vw,20px);
  font-weight:600;
  letter-spacing:-.01em;
  margin-bottom:clamp(22px,2.6vw,30px);
}
.ladder-foot .actions{justify-content:center}

@media (max-width:900px){
  .ladder{grid-template-columns:minmax(0,1fr);gap:var(--space-5)}
}

/* ---------- 12. Footer --------------------------------- */
.site-footer{
  background:var(--navy-900);
  color:var(--on-dark-soft);
  padding:clamp(56px,7vw,88px) 0 var(--space-7);
  margin-top:var(--frame);
}
.footer-grid{
  display:grid;
  /* auto-fit so the link columns reflow as the site grows, rather than
     hard-coding a count that breaks whenever one is added or removed */
  grid-template-columns:minmax(240px,1.6fr) repeat(auto-fit,minmax(150px,1fr));
  gap:clamp(28px,4vw,56px);
}
.site-footer .footer-logo{width:186px;margin-bottom:var(--space-4)}
.site-footer p{color:var(--on-dark-soft);font-size:15.5px;max-width:38ch}
/* Social link under the footer tagline. A bordered pill rather than a bare
   icon: at 20px an icon alone is a small target and reads as decoration. */
.social{
  display:inline-flex;align-items:center;gap:9px;
  margin-top:var(--space-5);
  padding:9px 15px 9px 13px;
  border:1px solid rgba(255,255,255,.20);
  border-radius:var(--r-pill);
  color:var(--on-dark-soft);
  font-size:14.5px;font-weight:600;
  transition:color var(--dur-1) var(--ease),
             border-color var(--dur-1) var(--ease),
             background-color var(--dur-1) var(--ease);
}
.social svg{width:16px;height:16px;flex:none}
.social:hover{color:#fff;border-color:var(--cyan);background:rgba(40,186,241,.12)}

.site-footer h2{
  font-family:var(--font-eyebrow);
  font-size:13px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;
  color:var(--lime);margin-bottom:var(--space-4);
}
.site-footer nav a{
  display:block;
  color:var(--on-dark-soft);
  padding:7px 0;
  font-size:15.5px;
  transition:color var(--dur-1) var(--ease);
}
.site-footer nav a:hover{color:#fff}
.footer-base{
  margin-top:clamp(40px,5vw,64px);
  padding-top:var(--space-5);
  border-top:1px solid rgba(255,255,255,.12);
  display:flex;flex-wrap:wrap;gap:var(--space-4);
  justify-content:space-between;
  font-size:14px;
}

/* ---------- 11b. Definitions --------------------------- */
/* Quiet, inline treatment — an aside within body copy, not a headline moment */
.defs{display:grid;gap:clamp(20px,2.4vw,28px);align-content:start}
/* Only needs a top margin when it follows body copy in the same column */
.defs:not(.split > *){margin-top:clamp(28px,3.2vw,40px)}
.def-row{
  display:grid;
  grid-template-columns:auto minmax(0,1fr);
  gap:16px;
  align-items:start;
}
.def-mark{
  width:38px;height:31px;flex:none;
  color:var(--cyan);          /* decorative, aria-hidden — no contrast floor applies */
  margin-top:3px;
}
.def-term{
  display:block;
  font-family:var(--font-display);
  font-size:clamp(24px,1.7vw,27px);   /* never below 24px, so 3:1 applies */
  font-weight:600;letter-spacing:-.015em;
  color:var(--cyan-600);
  margin-bottom:4px;
}
.def-text{
  margin:0;
  font-style:italic;
  font-size:clamp(15.5px,1.15vw,17px);
  line-height:1.5;
  color:var(--muted);
}
.dark .def-mark,.dark .def-term{color:var(--cyan)}
.dark .def-text{color:var(--on-dark-soft)}

/* ---------- 11c. Map ----------------------------------- */
/* OpenStreetMap rather than Google: no API key, and it does not set the
   tracking cookies that would drag a consent banner onto the site. */
.map-frame{
  position:relative;
  aspect-ratio:4/3;
  border-radius:var(--r-lg);
  overflow:hidden;
  border:1px solid var(--line);
  box-shadow:var(--sh-1);
  background:var(--sky);
}
.map-frame iframe{
  display:block;width:100%;height:100%;border:0;
}

/* Contact details list */
.contact-list{display:grid;gap:clamp(22px,2.6vw,30px);margin-top:clamp(24px,3vw,34px)}
.contact-row{display:grid;grid-template-columns:auto minmax(0,1fr);gap:16px;align-items:start}
.contact-icon{
  width:42px;height:42px;flex:none;
  display:grid;place-items:center;
  border-radius:var(--r-sm);
  background:var(--sky);
  border:1px solid #cbe4ef;
  color:var(--cyan-deep);
}
.contact-icon svg{width:21px;height:21px}
.contact-label{
  display:block;
  font-family:var(--font-eyebrow);
  font-size:12px;letter-spacing:.16em;text-transform:uppercase;font-weight:600;
  color:var(--muted);
  margin-bottom:4px;
}
.contact-value{
  display:block;
  font-size:clamp(17px,1.3vw,19px);
  font-weight:600;
  color:var(--ink);
  line-height:1.4;
}
/* A postal address is reference matter, not emphasis — the label above it
   already says what it is, so the bold weight only shouts. */
.contact-value.is-address{font-weight:400;font-size:16px;line-height:1.65;color:var(--ink)}
a.contact-value{color:var(--cyan-deep)}
a.contact-value:hover{color:var(--navy-600);text-decoration:underline}
.contact-note{
  display:block;margin-top:4px;
  font-size:14.5px;color:var(--muted);
}

/* ---------- 11b. Enquiry form -------------------------- */
/* A panel rather than bare fields on the section ground: the form is the one
   thing on the page asking for work from the reader, so it earns an edge. */
/* Form as the main column, with where-to-find-us as a narrower companion card.
   The map and the address belong to the same thought, so they share one card
   rather than sitting as two separate blocks down the page. */
.enquiry-grid{
  display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(20px,2.4vw,32px);
  align-items:stretch;                 /* both cards end on the same line */
}

.contact-aside{
  display:flex;
  flex-direction:column;
  background:#fff;
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-1);
  overflow:hidden;                     /* so the map corners follow the card */
}
/* The address block takes the height it needs; the map absorbs whatever is
   left, which is what keeps this card level with the form beside it. */
.aside-map{
  margin:0;
  flex:1;
  min-height:200px;
  border-bottom:1px solid var(--line);
  background:linear-gradient(150deg,#e6f2f5,#fbfdfd);
}
.aside-map iframe{display:block;width:100%;height:100%;border:0}

/* Placeholder shown until the visitor asks for the Google embed. Full-size so
   the card does not resize when the map arrives. */
.map-load{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:6px;
  width:100%;height:100%;
  padding:20px;
  text-align:center;
  cursor:pointer;
  transition:background-color var(--dur-1) var(--ease);
}
.map-load:hover{background:rgba(40,186,241,.07)}
.map-pin{
  display:grid;place-items:center;
  width:42px;height:42px;
  margin-bottom:2px;
  border-radius:var(--r-sm);
  background:var(--sky);
  border:1px solid #cbe4ef;
  color:var(--cyan-deep);
}
.map-pin svg{width:21px;height:21px}
.map-load-title{font-weight:650;font-size:15.5px;color:var(--cyan-deep)}
.map-load-note{font-size:13px;color:var(--muted);max-width:26ch;line-height:1.4}
.contact-aside .contact-list{
  margin:0;
  padding:clamp(20px,2.2vw,26px);
  gap:clamp(18px,2vw,22px);
}

.enquiry-form{
  display:flex;                        /* so one field can absorb spare height */
  flex-direction:column;
  gap:clamp(15px,1.7vw,20px);
  background:#fff;
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-1);
  padding:clamp(20px,2.4vw,30px);
}
.field{display:grid;gap:7px;min-width:0}
/* Two short fields on one line; collapses with the rest of the layout */
/* align-items:end keeps the two inputs on one line even when one label
   wraps to two lines and the other does not */
.field-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:inherit;align-items:end}

/* Form labels are not section eyebrows. Sharing the eyebrow's uppercase,
   widely-tracked Saira made the form read as signage; IBM Plex Sans in
   sentence case reads as an instrument panel, which is the right register for
   a company that builds them. Loaded on the contact page only. */
.field label{
  font-family:"IBM Plex Sans",var(--font-body);
  font-size:13.5px;
  font-weight:600;
  letter-spacing:.005em;
  color:var(--ink);
}
.field .opt{
  font-weight:500;
  font-size:13px;
  color:var(--muted);
}

.field input,.field select,.field textarea{
  font:inherit;
  font-size:16px;                      /* under 16px iOS zooms the page on focus */
  color:var(--ink);
  background:#fff;
  border:1px solid var(--line-strong);
  border-radius:var(--r-sm);
  padding:11px 13px;
  width:100%;
  transition:border-color .15s ease;
}
/* A native select renders a few px taller than a text input at the same
   padding, which breaks the line-up in a .field-row. Fix the height of
   both instead of chasing per-browser padding. */
.field input,.field select{height:46px}
.field textarea{min-height:130px;resize:vertical;line-height:1.55;height:auto}
/* Whichever card is taller, the message box takes up the difference, so the
   form never ends in a band of empty white above its own border. */
.field-grow{flex:1;grid-template-rows:auto 1fr}
.field-grow textarea{height:100%}
.field input::placeholder{color:#8aa2a9}
.field input:hover,.field select:hover,.field textarea:hover{border-color:var(--cyan-deep)}
/* Focus is left to the global :focus-visible ring so it matches every other
   control on the site. */

.form-foot{
  display:grid;gap:12px;
  justify-items:start;
  margin-top:4px;
}
.form-note{font-size:14px;color:var(--muted);margin:0;max-width:46ch}

/* Result of a background submit, announced to screen readers via aria-live */
.form-status{
  margin:0;
  padding:12px 14px;
  border-radius:var(--r-sm);
  font-size:15px;
  background:var(--sky);
  border:1px solid #cbe4ef;
  color:var(--cyan-deep);
}
.form-status.is-error{
  background:#fdf1ef;
  border-color:#f2cfc8;
  color:#8f2f1c;              /* 6.1:1 on the tint above */
}

/* Honeypot: off-screen rather than display:none, which some bots skip */
.hp{position:absolute!important;left:-9999px;width:1px;height:1px;overflow:hidden}

@media (max-width:900px){
  .enquiry-grid{grid-template-columns:minmax(0,1fr)}
  /* stacked there is no form height to match, so give the map a fixed shape */
  .aside-map{flex:none;aspect-ratio:16/9}
}
@media (max-width:640px){
  .field-row{grid-template-columns:minmax(0,1fr)}
}

/* ---------- 11c. Supporting note pair ------------------ */
/* Two short notes under a lead block, in a deliberately smaller voice. Three
   stacked intro-splits gave every block the same display heading and the same
   half-empty left column, which read as a list rather than a page. */
.note-pair{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(30px,4vw,60px);
  margin-top:clamp(40px,5vw,64px);
  padding-top:clamp(36px,4.5vw,56px);
  border-top:1px solid var(--line);
}
.note-pair h3{
  font-size:clamp(20px,1.7vw,24px);
  line-height:1.22;
  margin:var(--space-3) 0 var(--space-4);
  max-width:22ch;
}
.note-pair p{max-width:46ch}
.note-pair p:last-child{margin-bottom:0}
.dark .note-pair{border-top-color:rgba(255,255,255,.13)}

@media (max-width:820px){
  .note-pair{
    grid-template-columns:minmax(0,1fr);
    gap:clamp(30px,5vw,44px);
  }
}

/* ---------- 11d. Long-form prose ----------------------- */
/* A policy page is read, not scanned: one column at a comfortable measure,
   with headings that separate rather than shout. */
.prose{max-width:72ch}
.prose h2{
  font-size:clamp(20px,1.8vw,25px);
  margin:clamp(36px,4vw,52px) 0 var(--space-4);
}
.prose h2:first-of-type{margin-top:0}
.prose p{margin-bottom:var(--space-4)}
.prose .feature-list{margin:var(--space-5) 0 var(--space-6)}
.policy-date{
  font-family:var(--font-eyebrow);
  font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;font-weight:600;
  color:var(--muted);
  margin-bottom:clamp(28px,3.2vw,40px);
}

/* ---------- 12a. Rule card ----------------------------- */
/* Shows the SHAPE of a user-defined rule, deliberately not a mock of the EASI
   UI — it stays true while the dashboard is still in development. */
.rule-card{
  background:#fff;
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-2);
  padding:clamp(20px,2.4vw,28px);
  display:grid;gap:14px;
}
/* Rules are the compounded conditions; triggers are the resulting actions.
   The card separates them so the vocabulary is visible, not just stated. */
.rule-group{display:grid;gap:12px}
.rule-group + .rule-group{
  padding-top:16px;
  border-top:1px dashed var(--line-strong);
}
.rule-label{
  font-family:var(--font-eyebrow);
  font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;font-weight:600;
  color:var(--muted);
  margin:0;
}
.rule-group.trigger .rule-label{color:var(--lime-ink)}

.rule-row{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.rule-kw{
  font-family:var(--font-eyebrow);
  font-size:12.5px;letter-spacing:.16em;text-transform:uppercase;font-weight:600;
  color:var(--muted);
  min-width:46px;
}
.rule-token{
  display:inline-flex;align-items:center;
  padding:8px 14px;
  border-radius:var(--r-sm);
  background:var(--sky);
  border:1px solid #cbe4ef;
  font-size:15px;font-weight:600;
  color:var(--navy-600);
}
.rule-token.op{
  background:transparent;border-color:transparent;
  color:var(--muted);font-weight:500;
  padding-inline:2px;
}
.rule-token.val{
  background:#fff;border-color:var(--line-strong);
  font-variant-numeric:tabular-nums;
}
.rule-row.then .rule-kw{color:var(--lime-ink)}
.rule-row.then .rule-token{background:#eef7e4;border-color:#a9cf6f;color:#3f6414}
.rule-row.then .rule-token.op{background:transparent;border-color:transparent;color:var(--muted)}
.rule-note{
  margin-top:var(--space-4);
  font-size:14.5px;color:var(--muted);
}

/* ---------- 12b. Spec table ---------------------------- */
.table-wrap{
  overflow-x:auto;                 /* wide table scrolls in its own box, page never does */
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-1);
  /* Scroll shadows. On a phone the table is wider than the screen and there is
     otherwise nothing to say so — a reader sees the SP50 column and never
     learns the Biota MAP column exists. The white panels are attached to the
     content and the shadows to the box, so each shadow appears only while
     there is more table to reach in that direction. */
  background:
    linear-gradient(to right, #fff, rgba(255,255,255,0)) 0 0 / 30px 100% no-repeat local,
    linear-gradient(to left,  #fff, rgba(255,255,255,0)) 100% 0 / 30px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,   rgba(1,32,41,.20), rgba(1,32,41,0)) 0 0 / 16px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(1,32,41,.20), rgba(1,32,41,0)) 100% 0 / 16px 100% no-repeat scroll,
    #fff;
}
.spec-table{width:100%;border-collapse:collapse;min-width:720px;font-size:15.5px}
.spec-table th,.spec-table td{
  padding:16px 20px;
  border-bottom:1px solid var(--line);
  text-align:left;vertical-align:top;
}
.spec-table thead th{
  background:var(--navy-800);color:#fff;
  font-size:16px;font-weight:650;letter-spacing:-.01em;
}
.spec-table thead th:first-child{width:26%}
.spec-table tbody th{
  width:26%;
  color:var(--navy-800);font-weight:650;
  background:#f7fafb;
}
.spec-table td{color:var(--muted)}
.spec-table tbody tr:last-child th,
.spec-table tbody tr:last-child td{border-bottom:0}

/* Marks a value that still needs real data — deliberately conspicuous */
.tbd{
  display:inline-block;
  font-family:var(--font-eyebrow);
  font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;font-weight:600;
  color:#7a4e00;background:#fdf3dc;
  border:1px dashed #d9a94e;
  border-radius:var(--r-pill);
  padding:3px 10px;
}

/* ---------- 12c. Feature list -------------------------- */
.feature-list{display:grid;gap:12px;margin-top:var(--space-5)}
.feature-list li{display:flex;gap:12px;align-items:flex-start;font-size:16px;line-height:1.5}
.feature-list svg{width:19px;height:19px;flex:none;margin-top:3px;color:var(--lime-ink)}
.dark .feature-list svg{color:var(--lime)}
.dark .feature-list li{color:var(--on-dark-soft)}

/* ---------- 12d. Partners & proof ---------------------- */
/* A contained panel rather than a rule and more text — the section needed one
   element with enough weight to anchor it */
.proof-band{
  position:relative;
  margin-top:clamp(40px,5vw,64px);
  padding:clamp(34px,4vw,52px) clamp(24px,3vw,44px);
  background:linear-gradient(150deg,#e6f4fa 0%,#f7fcfe 55%,#ffffff 100%);
  border:1px solid #cbe4ef;
  border-radius:var(--r-lg);
  box-shadow:var(--sh-2);
  overflow:hidden;
}
.proof-band::before{
  content:"";position:absolute;left:0;right:0;top:0;height:4px;
  background:linear-gradient(90deg,var(--cyan) 0%,var(--lime) 100%);
}
.proof-lead{
  text-align:center;
  font-family:var(--font-eyebrow);
  font-size:13px;letter-spacing:.18em;text-transform:uppercase;font-weight:600;
  color:var(--muted);
  margin-bottom:var(--space-5);
}
/* Partner credit row — not currently used on any page, kept for reuse.
   An icon banner rather than brand logos: the icon denotes the KIND of
   organisation, so it needs no logo clearance.
   To swap in a real logo later, replace the .p-icon span with
   <img src="images/partners/name.svg" alt="" class="p-logo"> */
.partner-grid{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(12px,1.4vw,18px);
  margin-bottom:clamp(34px,4vw,50px);
}
.partner-item{
  display:flex;flex-direction:column;align-items:center;
  text-align:center;gap:10px;
  padding:22px 14px;
  background:rgba(255,255,255,.78);
  border:1px solid #d5e9f2;
  border-radius:var(--r-md);
}
.partner-item .p-icon{
  width:44px;height:44px;
  display:grid;place-items:center;
  border-radius:50%;
  background:#fff;
  border:1px solid #cbe4ef;
  color:var(--cyan-ink);
  flex:none;
}
.partner-item .p-icon svg{width:21px;height:21px}
.partner-item .p-logo{max-height:34px;width:auto}
.p-name{
  font-size:15.5px;font-weight:650;line-height:1.3;
  color:var(--navy-600);letter-spacing:-.01em;
  text-wrap:balance;
}
.p-type{
  font-family:var(--font-eyebrow);
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);
}
@media (max-width:900px){
  .partner-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}

.stat-row{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(16px,2vw,24px);
  text-align:center;
}
/* Dividers give the three figures structure instead of floating in a row */
.stat-row > div + div{border-left:1px solid #cbe4ef}
.stat-num{
  display:block;
  font-size:clamp(34px,3.6vw,50px);
  font-weight:700;
  line-height:1;
  letter-spacing:-.03em;
  color:var(--navy-600);
  font-variant-numeric:tabular-nums;
  margin-bottom:10px;
}
.stat-label{
  display:block;
  font-size:15px;
  color:var(--muted);
  line-height:1.4;
}
.proof-note{
  text-align:center;
  margin-top:clamp(24px,3vw,36px);
  font-size:15px;
  color:var(--muted);
}
@media (max-width:700px){
  .stat-row{grid-template-columns:minmax(0,1fr);gap:var(--space-6)}
  .stat-row > div + div{border-left:0;border-top:1px solid #cbe4ef;padding-top:var(--space-6)}
  .partner-names{gap:10px 18px}
  .partner-names li:not(:last-child)::after{margin-left:18px}
}

/* ---------- 13. Scroll reveal -------------------------- */
.reveal{opacity:0;transform:translateY(18px)}
.reveal.is-in{
  opacity:1;transform:none;
  transition:opacity 620ms var(--ease), transform 620ms var(--ease);
}
.reveal.is-in[data-delay="1"]{transition-delay:70ms}
.reveal.is-in[data-delay="2"]{transition-delay:140ms}
.reveal.is-in[data-delay="3"]{transition-delay:210ms}

/* ---------- 14. Responsive ----------------------------- */
@media (max-width:1200px){
  .grid4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .grid5{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (max-width:1100px){
  .links{display:none}
  .nav-toggle{display:flex}
  .site-header{background:rgba(1,32,41,.86);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}
}
@media (max-width:900px){
  :root{--r-xl:18px;--r-lg:14px}
  .grid2,.grid3,.grid4,.split,.flow,.footer-grid{grid-template-columns:minmax(0,1fr)}
  .grid5{grid-template-columns:repeat(2,minmax(0,1fr))}
  .split.reverse > *:first-child{order:0}
  .hero{min-height:auto;align-items:flex-start}
  .hero-copy{padding-block:132px 48px}
  /* Copy spans the full width here, so the scrim has to be uniform
     rather than the desktop left-to-right falloff */
  .hero::before{
    background:
      linear-gradient(180deg, rgba(1,32,41,.92) 0%, rgba(1,32,41,.80) 55%, rgba(1,32,41,.88) 100%);
  }
  .flow .step:not(:last-child)::after{
    right:auto;left:50%;top:auto;bottom:-11px;
    transform:translateX(-50%) rotate(135deg);
  }
  .footer-grid{gap:var(--space-6)}
  .cta.slim .cta-inner{align-items:flex-start}
  .cta.slim .actions{width:100%}
}
@media (max-width:560px){
  body{font-size:16px}
  .actions .btn{width:100%}
  .media{aspect-ratio:3/2}
}

/* ---------- 14b. Short viewports ----------------------- */
/* Every clamp above scales off viewport WIDTH. A 1366x768 or 1440x900 laptop is
   wide but short, so it gets near-maximum spacing and display type with no
   height to spend it in — which reads as the page being zoomed in. Trim the
   vertical rhythm and the display scale on height, leaving tall screens alone. */
@media (min-width:901px) and (max-height:860px){
  .section{padding-block:clamp(44px,5vw,68px)}
  .section.pull-up{padding-top:clamp(26px,2.8vw,38px)}
  .section.pull-down{padding-bottom:clamp(26px,2.8vw,38px)}
  .section.tight-top{padding-top:clamp(14px,1.6vw,22px)}
  .section.tight-bottom{padding-bottom:clamp(14px,1.6vw,22px)}

  .hero{min-height:min(94vh,700px)}
  .hero-copy{padding-block:clamp(124px,13vw,146px) clamp(56px,7vw,84px)}
  .hero-mini{padding:clamp(118px,12.5vw,138px) 0 clamp(38px,4.4vw,52px)}
  .hero-mini.tight{padding:clamp(106px,11.5vw,122px) 0 clamp(30px,3.4vw,42px)}

  h1{font-size:clamp(38px,4.3vw,56px)}
  h2{font-size:clamp(28px,2.9vw,41px)}

  .center,.intro{margin-bottom:clamp(26px,3vw,42px)}
  .section > .shell + .shell{margin-top:clamp(32px,3.6vw,52px)}
}

/* ---------- 15. Motion & print preferences ------------- */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  .hero-media img{animation:none;transform:scale(1.04)}
  .reveal{opacity:1;transform:none}
}
@media print{
  .site-header,.drawer,.nav-toggle{display:none}
  body{background:#fff;color:#000}
  .panel,.hero,.cta{margin:0;border-radius:0}
}
