
/* Self-hosted Poppins. The stylesheet asked for it while nothing shipped
   it, so every visitor was seeing the Arial fallback. Local files mean
   the CSP needs no third-party font or style host at all.
   font-display:swap — text paints in the fallback immediately rather
   than blocking on the download. */
@font-face{font-family:'Poppins';font-style:normal;font-weight:300;font-display:swap;src:url('fonts/poppins-300-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Poppins';font-style:normal;font-weight:300;font-display:swap;src:url('fonts/poppins-300-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Poppins';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/poppins-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Poppins';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/poppins-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Poppins';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/poppins-500-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Poppins';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/poppins-500-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/poppins-600-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/poppins-600-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
/* ==========================================================================
   Lipid Labs — CanAlt structure, Lipid brand
   ==========================================================================
   Every token below is lifted from www.canaltlabs.com/static/css/site.css so
   the two sites read as one house. Nothing here was invented.

   Layout, spacing, type scale, hairlines and component shapes come from
   canaltlabs.com so the two sites read as one house. The COLOURS and the
   TYPEFACE are Lipid's own, taken from its live theme stylesheet:

     --dark       #1C1715   h1, body ink
     --dark-green #505928   buttons, h2, CTA band, nav  (CanAlt's --ink slot)
     --dark-brown #693C1A   eyebrows, topbar rule, links (CanAlt's --red slot)
     --green      #767F4B   quiet accent — dots, scope marks, soft fills
     --brown      #9B7E66   warm wash backgrounds
     --grey       #707070   RETIRED — a cool grey fights this palette

   TYPE
   Poppins — Lipid's own face, self-hosted on the live site at 300/400/500/
   600/700. Set at CanAlt's SCALE rather than Lipid's current one: body 13.5px
   instead of 18px, headings LIGHT (300) instead of 600. Labels 9.5px at .12em.

   SHAPE
   3px radius almost everywhere. Hairline rules at 6% black. Grids are joined
   by borders with no gap. No shadows, no gradients, no decorative motifs.
   ========================================================================== */

:root{
  /* Lipid brand, from the live theme stylesheet */
  --dark:#1C1715; --dark-green:#505928; --green:#767F4B;
  --brown:#9B7E66; --dark-brown:#693C1A;

  /* CanAlt role names, carrying Lipid values */
  --red:#693C1A; --rh:#7d4a22; --rs:rgba(105,60,26,.04); --rb:rgba(105,60,26,.12);
  --nv:#505928; --ns:rgba(80,89,40,.03); --nb:rgba(80,89,40,.08);
  --tl:#693C1A;
  --bl:#767F4B; --bll:#A8B47A; --bw:#F6F3EF;
  --ink:#505928; --ink-hover:#3E4620; --ink-soft:rgba(80,89,40,.07);
  /* Aliases the inline styles in build2.js and app.js name but no rule
     defined, so 30 muted notes rendered in full body ink and the order-step
     headings lost their green. Each is an existing neutral: --ink-2 the body
     grey, --ink-3 the muted grey (5.16:1 on white), --heading the heading
     green. */
  --ink-2:var(--g6); --ink-3:var(--g5); --heading:var(--ink);
  --teal:#505928; --graphite:#595959;
  --qc-green:#767F4B; --qc-orange:#B07C2A; --qc-red:#8C3A22;
  /* Status pills are 10px uppercase TEXT and need 4.5:1, not the 3:1 the
     decorative accents are tuned for. --bl was 4.28:1 and --qc-orange
     3.64:1 on white. These are those two hues, darkened to clear white,
     --bw, --g05 and --g0 with room to spare. */
  --pill-green:#697141; --pill-amber:#8E6422;

  /* neutrals shared with CanAlt so the two sites sit in the same house */
  --g9:#1C1715; --g8:#2a2422; --g7:#4a423c; --g6:#5b544e; --g5:#736C67;
  /* --g4 is 3.03:1 on white: decorative only, never text. See fix-contrast.js */
  --g4:#9a938c; --g3:#bdb7b1; --g2:#dad5cf; --g1:#ecE8e3;
  --g05:#f5f3f0; --g0:#faf9f7; --w:#fff;

  --line:rgba(28,23,21,.07);
  --line-strong:rgba(28,23,21,.12);

  /* type scale — in rem, so it follows the visitor's own browser text size
     and the Text size control (html[data-text-size], below). Raised 2026-10-03
     at the laboratory's request: the floor was 10px and body copy 13.5px;
     nothing typed now renders below 12px at the default size. */
  --t-label:.75rem;      /* 12px   eyebrows, kickers, table headers, form labels */
  --t-micro:.8125rem;    /* 13px   meta, captions, help text */
  --t-small:.84375rem;   /* 13.5px secondary UI, footer links */
  --t-body:.90625rem;    /* 14.5px body copy, table cells */
  --t-lead:1rem;         /* 16px   ledes, hero subhead */
  --t-h3:1.0625rem;      /* 17px */
  --t-h2:clamp(1.375rem,2.2vw,1.75rem);
  --t-h1:clamp(1.75rem,3.4vw,2.625rem);

  /* vertical rhythm */
  --space-section:76px;
  --space-tight:56px;

  --gutter:32px;
  --gutter-lg:64px;
  --maxw:1200px;
  --seg:1080px;
  --r:3px;

  /* Poppins is Lipid's face — self-hosted on the live site at 300–700.
     Point this at those .woff files in production; loaded from Google here
     so the file stays portable. */
  --font:'Poppins','Helvetica Neue',Helvetica,Arial,sans-serif;
}
@media (max-width:760px){ :root{ --gutter:20px } }

/* ---------- base ---------- */
*,*::before,*::after{box-sizing:border-box}
html{
  /* 100% is the visitor's own browser setting, not a fixed 16px. */
  font-size:100%;
  scroll-behavior:smooth;
  /* The header is sticky and the cookie bar is fixed. Without this, tabbing
     or following an in-page link lands the target underneath one of them —
     WCAG 2.2 SC 2.4.11 Focus Not Obscured. */
  scroll-padding-top:88px;
  scroll-padding-bottom:24px;
}
/* The Text size control (top bar and footer; wired in assets/app.js, which
   sets the attribute and remembers the choice in the visitor's own browser).
   Everything typed is in rem, so one step on the root scales the whole page. */
html[data-text-size="1"]{font-size:112.5%}
html[data-text-size="2"]{font-size:125%}
body{
  margin:0;
  background:var(--w);
  color:var(--g8);
  font-family:var(--font);
  font-size:var(--t-body);
  line-height:1.6;
  letter-spacing:.01em;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
h1,h2,h3,h4,h5{margin:0;font-weight:300;color:var(--ink);letter-spacing:-.022em;line-height:1.14}
h3,h4,h5{font-weight:500;letter-spacing:-.005em;line-height:1.3}
p{margin:0 0 14px;max-width:70ch}
img{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
main a:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link){
  color:var(--red);border-bottom:1px solid rgba(154,51,36,.28);transition:border-color .15s;
}
main a:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link):hover{border-bottom-color:var(--red)}
:focus-visible{outline:2px solid var(--ink);outline-offset:3px;border-radius:2px}
.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter)}
.wrap--narrow{max-width:760px}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip{position:absolute;left:-9999px}
.skip:focus{left:16px;top:12px;z-index:200;background:var(--w);padding:10px 16px;border:1px solid var(--ink);border-radius:var(--r)}

/* The one label style, used for every eyebrow, kicker and step number. */
.eyebrow{
  display:inline-flex;align-items:center;gap:6px;
  font-size:var(--t-label);font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--tl);margin:0 0 12px;
}

/* ---------- topbar ---------- */
.topbar{
  background:var(--nv);border-top:2px solid var(--red);min-height:36px;
  padding:0 var(--gutter);display:flex;align-items:center;justify-content:space-between;
  color:rgba(255,255,255,.6);font-size:var(--t-micro);letter-spacing:.02em;
}
.topbar a{color:rgba(255,255,255,.85)}
.topbar a:hover{color:var(--w)}
/* The accreditation line is a link to accreditation.html. It takes the
   topbar link colour (.85 white on --nv, about 6:1, where the .6 of the
   bar's plain text was under 4.5:1), is underlined on hover so it reads as
   a link, and carries the same white ring as the doors on focus. */
.topbar .tb-acc:hover{text-decoration:underline;text-underline-offset:2px}
.topbar a:focus-visible{outline:2px solid #fff;outline-offset:2px}
/* The left cluster never wraps or shrinks: the search box is the part of the
   bar that gives way (it shrinks from 230px, below), so a phone number is not
   broken at its hyphens when the text is larger. */
.topbar .tb-left{display:flex;gap:20px;align-items:center;flex:none;white-space:nowrap}
/* The two ways in, in the topbar.

   Pills rather than plain links: this is the one thing in the topbar a
   returning user is hunting for, and underlined text at 11px beside a phone
   number is not findable. The client door is filled and the staff one is
   outlined — same size, different weight, because the audiences are not the
   same size and the marketing site is not for staff. */
.tb-entry{display:flex;align-items:center;gap:8px;flex:none}
/* The right-hand cluster: the Text size control, then the two doors. */
.tb-right{display:flex;align-items:center;gap:14px;flex:none}
/* Text size: three steps, shown as three sizes of the letter A. The letters
   are deliberately in px — they picture the sizes, so they must not grow with
   the setting they change. aria-pressed carries the state; the label names it.
   In the top bar on wide screens and in the footer at every width, so it is
   reachable where the bar is too narrow to carry it. */
.text-size{display:inline-flex;align-items:center;gap:2px;white-space:nowrap}
.text-size-label{margin-right:6px}
.text-size button{
  font-family:var(--font);font-weight:500;line-height:1;cursor:pointer;
  min-width:26px;height:24px;padding:0 6px;border-radius:var(--r);
  border:1px solid transparent;background:transparent;color:inherit;
}
.text-size button[data-text-size="0"]{font-size:12px}
.text-size button[data-text-size="1"]{font-size:15px}
.text-size button[data-text-size="2"]{font-size:18px}
.topbar .text-size{color:rgba(255,255,255,.85)}
.topbar .text-size button:hover{background:rgba(255,255,255,.12)}
.topbar .text-size button[aria-pressed="true"]{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.4);color:#fff}
.topbar .text-size button:focus-visible{outline:2px solid #fff;outline-offset:2px}
.site-footer .text-size{color:var(--g6)}
.site-footer .text-size button{border-color:var(--line-strong)}
.site-footer .text-size button:hover{border-color:var(--ink)}
.site-footer .text-size button[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--w)}
/* Below 1040px the bar has no room beside the search and the doors; the
   footer copy of the control stays. */
@media (max-width:1040px){ .topbar .text-size{display:none} }
.tb-door{
  display:inline-flex;align-items:center;gap:6px;min-height:24px;padding:0 11px;
  border-radius:var(--r);border:1px solid rgba(255,255,255,.22);
  background:rgba(255,255,255,.12);color:#fff;
  font-size:var(--t-micro);letter-spacing:.02em;white-space:nowrap;
  transition:background .15s ease,border-color .15s ease;
}
.tb-door:hover{background:rgba(255,255,255,.2);border-color:rgba(255,255,255,.4);color:#fff}
.tb-door:focus-visible{outline:2px solid #fff;outline-offset:2px}
.tb-door-staff{background:transparent;color:rgba(255,255,255,.85)}
.tb-door-staff:hover{background:rgba(255,255,255,.1)}
.tb-door svg{flex:none;opacity:.85}

/* Below 900px the search box at its full 230px and the two pills cannot
   share 100vw, so between 861 and 900px it gives up its minimum width and
   takes what is left. At 860px and below it folds: the hamburger menu takes
   over there and carries its own test search (.nav-search), so there is no
   width at which the site has no search. The fold used to be at 900px, which
   left 861-900px with neither. */
@media (max-width:900px){
  .tb-search{min-width:0;flex:1 1 auto;margin:0 16px}
}
@media (max-width:860px){
  .topbar .tb-search{display:none}
}
@media (max-width:520px){
  /* The icon carries the meaning at this width; the staff door keeps its
     words because "Staff" alone beside a person icon reads as the client one. */
  .tb-door svg{display:none}
  .tb-entry{gap:6px}
  .tb-door{padding:0 9px}
  /* At the larger text sizes the phone number and the two doors do not fit
     one row on a phone, so the bar takes two: number above, doors below. */
  html[data-text-size] .topbar{flex-wrap:wrap;justify-content:flex-start;gap:4px 14px;padding-block:6px}
}

.tb-search{display:flex;align-items:center;gap:7px;background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.14);border-radius:var(--r);padding:0 10px;min-height:24px;min-width:0;flex:0 1 230px;margin:0 16px}
/* A 0.16 alpha shift is not a focus indicator — against the green topbar
   it is nearly invisible. Use a real ring that meets 3:1 against both the
   field and the bar behind it. */
.tb-search:focus-within{
  background:rgba(255,255,255,.16);
  border-color:#fff;
  outline:2px solid #fff;
  outline-offset:2px;
}
.tb-search svg{flex:none}
.tb-search input{background:none;border:0;color:#fff;font-family:var(--font);font-size:var(--t-micro);width:100%;padding:0}
/* .85, not .45: at .45 the placeholder was 2.5:1 on its field. */
.tb-search input::placeholder{color:rgba(255,255,255,.85)}
.tb-search input:focus{outline:none}
@media (max-width:760px){ .topbar{padding:0 20px;font-size:var(--t-micro)} .topbar .hide-sm{display:none} .tb-search{min-width:0;flex:1;margin-left:14px} }
/* 320px — the reflow width, and a 1280px window at 400% zoom. The phone
   number and the two doors do not fit one row there at any text size, so the
   bar takes two as it does on a phone at the larger sizes. The header row's
   own tightening is in the responsive section at the end ("320px, the
   header row"): it has to come after the header's base rules to apply. */
@media (max-width:359px){
  .topbar{flex-wrap:wrap;justify-content:flex-start;gap:4px 14px;padding-block:6px}
}

/* ---------- nav ---------- */
/* the topbar is now the header's first row, so the header itself must
   stop being a flex row and let its two rows stack */
.site-header > .topbar{margin:0}
.site-header{display:block}
.site-header > .wrap{
  position:sticky;top:0;z-index:100;
  background:rgba(255,255,255,.96);
  backdrop-filter:saturate(180%) blur(14px);
  -webkit-backdrop-filter:saturate(180%) blur(14px);
  border-bottom:1px solid var(--line);
}
.site-header .wrap{display:flex;align-items:center;gap:24px;height:64px;max-width:var(--maxw)}
.brand{display:flex;align-items:center;flex:none}
.brand img{width:auto;height:30px}
.site-nav{display:flex;gap:26px;margin-left:auto;align-items:center}
.site-nav a{font-size:var(--t-body);font-weight:400;color:var(--g7);transition:color .15s;letter-spacing:0;padding:6px 0;position:relative;white-space:nowrap}
/* The one-row header needs about 922px at the 26px gap, so between the
   860px menu breakpoint and ~960px "Omega-3 & fish oil" and "Our Lab" broke
   onto two lines. A tighter gap up to 1100px keeps every label on one line
   (checked at 861px: 15px to spare); the menu rules below win at 860px. */
@media (max-width:1100px){ .site-nav{gap:16px} }
/* The type floor was raised on 2026-10-03 (body 13.5 -> 14.5px), and the row
   no longer fits just above the menu breakpoint. Between 861 and 960px the
   links take the next size down (13.5px, what they were) and a 12px gap. */
@media (min-width:861px) and (max-width:960px){
  .site-nav{gap:12px}
  .site-nav a{font-size:var(--t-small)}
  .site-header .wrap{gap:16px}
}
/* With the Text size control raised, one row needs up to ~1120px. Media
   queries cannot see the chosen size, so between the menu breakpoint and
   1140px the links move to a row of their own under the brand and the order
   button, at full size, rather than being squeezed or pushed off the page. */
@media (min-width:861px) and (max-width:1140px){
  html[data-text-size] .site-header .wrap{flex-wrap:wrap;height:auto;padding-block:10px 4px;row-gap:2px}
  html[data-text-size] .site-nav{order:3;flex:0 0 100%;margin-left:0;gap:20px}
  html[data-text-size] .site-nav a{font-size:var(--t-body)}
  html[data-text-size] .header-actions{margin-left:auto}
  /* The two-row header is taller than the 88px the page scrolls targets
     clear of, so an anchored heading would land under it. */
  html[data-text-size]{scroll-padding-top:112px}
}
/* The Register button (2026-10-08) sits beside the order button and costs
   the row about 105px. Measured: at the default size the one-row header then
   overflows below ~990px, and at the largest Text size between 1141px and
   ~1250px. In those ranges the links take the row of their own that the
   raised Text sizes already use between 861 and 1140px, so neither button is
   squeezed or pushed off the page. */
@media (min-width:861px) and (max-width:1040px){
  .site-header .wrap{flex-wrap:wrap;height:auto;padding-block:10px 4px;row-gap:2px}
  .site-nav{order:3;flex:0 0 100%;margin-left:0;gap:20px}
  .site-nav a{font-size:var(--t-body)}
  .header-actions{margin-left:auto}
  html{scroll-padding-top:112px}
}
@media (min-width:1141px) and (max-width:1280px){
  html[data-text-size="2"] .site-header .wrap{flex-wrap:wrap;height:auto;padding-block:10px 4px;row-gap:2px}
  html[data-text-size="2"] .site-nav{order:3;flex:0 0 100%;margin-left:0;gap:20px}
  html[data-text-size="2"] .header-actions{margin-left:auto}
  html[data-text-size="2"]{scroll-padding-top:112px}
}
.site-nav a:hover{color:var(--ink)}
.site-nav a[aria-current="page"]{color:var(--ink);font-weight:500}
.site-nav a[aria-current="page"]::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--red)}
/* The mobile menu's test search (build.js page()). Hidden with the desktop
   nav; shown only inside the open mobile menu, below. */
.nav-search{display:none}
.header-actions{display:flex;align-items:center;gap:16px;flex:none}
.nav-toggle{display:none;background:none;border:1px solid var(--line-strong);border-radius:var(--r);padding:7px 10px;cursor:pointer;color:var(--g7);font-size:var(--t-lead)}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  font-family:var(--font);font-size:var(--t-body);font-weight:500;letter-spacing:0;
  padding:11px 22px;border-radius:var(--r);border:1px solid transparent;
  cursor:pointer;transition:background .15s,color .15s,border-color .15s;
}
.btn-primary{background:var(--ink);color:var(--w);border-color:var(--ink)}
.btn-primary:hover{background:var(--ink-hover);border-color:var(--ink-hover)}
.btn-secondary{background:transparent;color:var(--ink);border-color:var(--line-strong)}
.btn-secondary:hover{border-color:var(--ink);background:var(--ink-soft)}
.btn-lg{font-size:var(--t-body);padding:13px 26px}
.btn-sm{font-size:var(--t-small);padding:8px 16px}
/* pointer-events:none made an aria-disabled button unclickable AND
   unhoverable, so there was no way to discover why it was unavailable.
   It stays dimmed and keeps its cursor; the JS guard does the refusing. */
.btn[disabled]{opacity:.35;pointer-events:none}
.btn[aria-disabled="true"]{opacity:.5;cursor:not-allowed}
.btn-row{display:flex;flex-wrap:wrap;gap:10px}
.arrow{transition:transform .15s ease}
.btn:hover .arrow,a.card:hover .arrow,a.door:hover .arrow{transform:translateX(2px)}

/* ---------- hero ---------- */
.hero{background:var(--w);border-bottom:1px solid var(--line);position:relative;overflow:hidden}
.hero .wrap{padding-block:72px 80px;max-width:var(--maxw)}
.hero-grid{display:grid;grid-template-columns:1fr .95fr;gap:56px;align-items:center}
.hero h1{font-size:var(--t-h1);font-weight:300;color:var(--dark);letter-spacing:-.032em;line-height:1.1;margin-bottom:16px;max-width:16ch}
.hero-sub{font-size:var(--t-lead);line-height:1.62;color:var(--g6);margin-bottom:22px;max-width:46ch;font-weight:400}
.hero-meta{display:flex;flex-wrap:wrap;gap:8px 20px;font-size:var(--t-micro);letter-spacing:.02em;color:var(--g5);margin-bottom:26px}
.hero-meta span{display:flex;align-items:center;gap:7px}
.hero-meta span::before{content:"";width:4px;height:4px;border-radius:50%;background:var(--red);flex:none}
/* The hero figure is a crossfade carousel. It is a 4/3 box (taller than the
   old 3/2, so it fills more of the text column's height); every slide is
   absolutely stacked and fades on .is-active, so a rotation causes no layout
   shift. With JS off, only slide 1 (.is-active) is visible. */
.hero-figure{position:relative;aspect-ratio:4/3;overflow:hidden;background:transparent;margin:0}
.hero-figure>picture{display:block;width:100%;height:100%}.hero-figure>picture>img{display:block;width:100%;height:100%;object-fit:contain}
.banner-slide{position:absolute;inset:0;opacity:0;transition:opacity .7s ease}
.banner-slide.is-active{opacity:1}
.banner-slide picture,.banner-slide img{display:block;width:100%;height:100%;object-fit:cover}
@media (prefers-reduced-motion: reduce){.banner-slide{transition:none}}
/* Dot controls, built by app.js (absent with JS off, so no inert buttons).
   White dots with a dark ring read on both the pale bottle shot and the
   photographs. */
.hero-dots{position:absolute;left:0;right:0;bottom:12px;display:flex;justify-content:center;gap:9px;z-index:2}
.hero-dot{width:9px;height:9px;padding:0;border:0;border-radius:50%;cursor:pointer;background:rgba(255,255,255,.55);box-shadow:0 0 0 1px rgba(28,23,21,.3);transition:background .15s,transform .15s}
.hero-dot:hover{background:#fff}
.hero-dot.is-active{background:#fff;transform:scale(1.3)}
.hero-dot:focus-visible{outline:2px solid #fff;outline-offset:2px}

/* The 2026-09 rotating-banner CSS (.banner-track, .banner-slide[data-active],
   .banner-controls/-dots/-panel) was removed with that carousel and lingered
   here as dead rules. It defined .banner-slide{visibility:hidden} and keyed the
   active slide on [data-active], both of which fought the new carousel above
   (which keys on .is-active) and hid every slide. No page used any of those
   classes; the live carousel is the rules above plus app.js. */
@media (max-width:900px){ .hero-grid{grid-template-columns:1fr;gap:32px} .hero .wrap{padding-block:52px 56px} }

/* ---------- figures band ---------- */
.figures{background:var(--g05);border-bottom:1px solid var(--line)}
.figures .wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:0;max-width:var(--maxw)}
.figures div{padding:28px 28px 28px 0;border-left:1px solid var(--line);padding-left:28px}
.figures div:first-child{border-left:0;padding-left:0}
.figures b{display:block;font-size:1.75rem;font-weight:300;line-height:1;letter-spacing:-.02em;color:var(--ink);margin-bottom:8px}
.figures span{display:block;font-size:var(--t-small);color:var(--g5);line-height:1.5}

/* ---------- accreditation marks ----------
   The four marks carry very different amounts of margin baked into the
   source files. Measured off-canvas, ink bounds vs file bounds:

     mark   file       ink box    file is margin   ink density   shape
     ISO    200x200    200x200        0.0%            78.6%      filled square
     SCC    200x200    167x168       29.9%            28.3%      outline square
     AOCS   450x450    337x337       43.9%            61.6%      circle
     GOED   198x270    191x247       11.8%            58.6%      portrait

   Fitting all four to one box scaled the MARGINS, not the marks. In the old
   36px content box ISO rendered 36px of ink and AOCS rendered 27px — a 25%
   mismatch, which is what read as "the logos are different sizes". Stacking
   a 1px tile around each made it worse: ISO's artwork is already a filled
   square and SCC's is already an outlined square, so both became boxes
   drawn inside boxes.

   --s is the share of the box each FILE may occupy, back-calculated so the
   INK lands on a common optical size of roughly 40px, then nudged for shape
   and weight: ISO pulled back because a filled saturated square is the
   heaviest thing here, AOCS pushed up because a circle reads about 5%
   smaller than a square of the same width, SCC allowed to run largest
   because a 28%-density outline carries almost no visual weight.

   Resulting ink, at a 60px box:  ISO 37.8  ·  SCC 40.6  ·  AOCS 42.2
   (circle, = 1399px² vs ISO's 1429px²)  ·  GOED 32.7x42.3.

   The mark files are untouched — uniform scale only, which is what the SCC,
   AOCS and GOED mark licences require. Never redraw these. */
.m-iso{--s:63%}
.m-scc{--s:81%}
.m-aocs{--s:94%}
.m-goed{--s:77%}
.acc-mark{flex:none;display:grid;place-items:center;width:60px;height:60px}
.acc-mark img{max-width:var(--s);max-height:var(--s);width:auto;height:auto}

.accreditations{background:var(--w);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.accreditations .wrap{max-width:var(--maxw)}
.acc-grid{display:grid;grid-template-columns:repeat(4,1fr);border-left:1px solid var(--line)}
.acc-grid a{
  display:flex;align-items:center;gap:13px;min-width:0;
  padding:18px 20px;border:0;border-right:1px solid var(--line);
  color:var(--g6);transition:background .15s;
}
.acc-grid a:hover{background:var(--g05)}
.acc-txt{min-width:0}
.acc-txt b{display:block;font-size:var(--t-small);font-weight:500;color:var(--g8);line-height:1.25;letter-spacing:-.005em}
.acc-txt span{display:block;font-size:var(--t-micro);color:var(--g5);line-height:1.35;margin-top:2px}
.acc-grid a:hover .acc-txt b{color:var(--red)}
@media(max-width:900px){
  .acc-grid{grid-template-columns:repeat(2,1fr)}
  .acc-grid a:nth-child(-n+2){border-bottom:1px solid var(--line)}
}
@media(max-width:520px){
  .acc-grid{grid-template-columns:1fr}
  .acc-grid a{border-bottom:1px solid var(--line)}
  .acc-grid a:last-child{border-bottom:0}
  .acc-mark{width:52px;height:52px}
}

/* .badge-row is laid out further down, as equal cards (2026-10-06). */
.badge-row .acc-mark{width:88px;height:88px}

/* ---------- credential badges ----------
   The LinkedIn originals are gold with drop shadows; here the same three
   claims are fine line marks in the brand green, on the warm ground, so
   they read as part of this site rather than as pasted-in trophies. */
.credentials{background:var(--bw);border-bottom:1px solid var(--line)}
.credentials .wrap{max-width:var(--maxw);padding-block:52px}
/* Per-tile credential icons. The laboratory-supplied three-badge lockup was
   sliced into its three marks (brand/cred-icon-*.png) so each icon sits above
   its own tile's heading and aligns with it, rather than sitting in one row
   over three disconnected tiles. .cred-art is a fixed-height row so the
   headings line up across the three tiles whatever each icon's aspect ratio;
   the icons are decorative (alt="") because the heading beneath states the
   claim in words. */
.cred-art{height:72px;display:grid;place-items:center;margin-bottom:16px}
.cred-icon{display:block;width:auto;height:auto;max-height:62px;max-width:132px}
.cred-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0}
.cred{padding:6px 34px;border-left:1px solid var(--line);text-align:center}
.cred:first-child{border-left:0}
.credentials h2{font-size:var(--t-h3);font-weight:500;color:var(--g9);line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
.credentials p{font-size:var(--t-small);color:var(--g5);line-height:1.6;margin:0;max-width:34ch;margin-inline:auto}
/* The same tiles inside a page's own section (build.js credSectionTiles —
   Our lab's "Why specialisation matters"): h3 under the section's h2, set
   like the home band's h2, a rule above to separate them from the section's
   text, and the column count from the tiles actually present (two once the
   award term lapses). */
.cred-grid--section{margin-top:40px;padding-top:36px;border-top:1px solid var(--line)}
.cred-grid--section h3{font-size:var(--t-h3);font-weight:500;color:var(--g9);line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
.cred-grid--section p{font-size:var(--t-small);color:var(--g5);line-height:1.6;margin:0;max-width:34ch;margin-inline:auto}
.cred-grid--2{grid-template-columns:repeat(2,1fr)}
.cred-marks{margin-top:48px;padding-top:34px;border-top:1px solid var(--line)}
.cred-marks .eyebrow{text-align:center;margin-bottom:22px}
/* The AOCS participation line under the marks (2026-10-08): centred like
   the eyebrow above the tiles, quiet, one measure wide. */
.cred-marks .cred-note{margin:22px auto 0;max-width:68ch;text-align:center;font-size:var(--t-small);line-height:1.55;color:var(--g6)}
/* The marks row in its own warm band under the show band: it no longer
   follows the tiles, so it drops the divider and spacing that set it off
   from them. */
.credentials--marks .cred-marks{margin-top:0;padding-top:0;border-top:0}
/* On the home band the three marks are white cards, not hairline-divided
   cells: every mark file (ISO png, SCC jpg, GOED png) carries a white/opaque
   background, so a white card blends each one cleanly and gives the marks
   physical presence on the warm ground instead of floating on it. auto-fit
   is the fallback for three marks; with four (the live row) or five (the
   AOCS mark, while that credential is held) build.js adds acc-grid--4 or
   acc-grid--5 and the rules below lay the row out deliberately. Scoped to
   .cred-marks so accreditation.html's divided .acc-grid is untouched. */
.cred-marks .acc-grid{
  grid-template-columns:repeat(auto-fit,minmax(228px,1fr));
  gap:18px;border-left:0;
}
.cred-marks .acc-grid a{
  gap:20px;padding:24px 26px;border:1px solid var(--line-strong);border-radius:12px;
  background:var(--w);box-shadow:0 1px 2px rgba(28,23,21,.05);
  transition:box-shadow .18s,border-color .18s,transform .18s;
}
.cred-marks .acc-grid a:hover{
  background:var(--w);border-color:var(--green);
  box-shadow:0 8px 20px rgba(28,23,21,.09);transform:translateY(-2px);
}
/* Four marks — the live row: ISO, SCC, GOED and the DHA/EPA Omega-3
   Institute — go four across only where every card keeps room for its
   caption beside its mark, and two by two below that: never three and one.
   build.js adds acc-grid--4 when the row has exactly four. */
.cred-marks .acc-grid--4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:1120px){.cred-marks .acc-grid--4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){.cred-marks .acc-grid--4{grid-template-columns:1fr}}
/* Five marks (AOCS held): five across, then three and three with the wide
   Institute card spanning two, then two and two the same way — never a lone
   card on its own row. */
.cred-marks .acc-grid--5{grid-template-columns:repeat(5,minmax(0,1fr))}
@media (max-width:1280px){
  .cred-marks .acc-grid--5{grid-template-columns:repeat(3,minmax(0,1fr))}
  .cred-marks .acc-grid--5 .acc-wide{grid-column:span 2}
}
@media (max-width:860px){.cred-marks .acc-grid--5{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){
  .cred-marks .acc-grid--5{grid-template-columns:1fr}
  .cred-marks .acc-grid--5 .acc-wide{grid-column:auto}
}
.cred-marks .acc-mark{width:84px;height:84px}
.cred-marks .acc-txt b{font-size:var(--t-body)}
.cred-marks .acc-grid a:hover .acc-txt b{color:var(--ink)}
/* The DHA/EPA Omega-3 Institute mark is a wide wordmark (292x70), not a
   badge, so its card stacks the logo over the caption and the box takes the
   logo's own aspect. Shown at about half its pixel width, so it stays sharp
   on a 2x screen; uniform scale only, like every other mark here. These
   rules sit after the .cred-marks ones on purpose: equal specificity, so
   order decides. */
.m-dhaepa{--s:100%}
.acc-mark.m-dhaepa{width:146px;height:35px}
.cred-marks .acc-mark.m-dhaepa{width:160px;height:38px}
.acc-grid a.acc-wide{flex-direction:column;align-items:flex-start;justify-content:center;gap:12px}
/* The Institute tile on our-lab.html's badge row says what it is in words
   under the wordmark, as the home tile does, so a sighted reader is not
   left to take a fourth logo under "Accreditation" as a fourth accreditation. */
/* Our lab's marks row, BALANCED (2026-10-06): equal white cards in a grid,
   each mark fitted inside the same 96px-high box (object-fit keeps every
   mark's own proportions — a square seal, a tall badge and a wide wordmark
   come out the same visual weight), the caption under it. Four across, two
   by two below 900px. */
.badge-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;margin-bottom:32px}
.badge-row .tile{
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:14px;
  padding:22px 18px 20px;background:var(--w);border:1px solid var(--line-strong);border-radius:var(--r);
  box-shadow:0 1px 3px rgba(28,23,21,.06);text-align:center;text-decoration:none;
}
.badge-row .tile img{display:block;width:100%;max-width:170px;height:96px;object-fit:contain}
.badge-row .tile--wide img{max-width:200px}
.badge-row a.tile:hover{border-color:var(--ink);box-shadow:0 6px 18px rgba(28,23,21,.10)}
.badge-row .tile-caption{font-size:var(--t-small);color:var(--g6);line-height:1.4}
.badge-row .tile-caption b{display:block;font-weight:500;color:var(--g8)}
/* Five across while the AOCS mark is held (aocs-config), so it never
   falls into four and one. */
.badge-row:has(> .tile:nth-child(5)){grid-template-columns:repeat(5,minmax(0,1fr))}
@media (max-width:900px){.badge-row,.badge-row:has(> .tile:nth-child(5)){grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:420px){.badge-row .tile img{height:80px}}

@media (max-width:860px){
  .cred-marks{margin-top:32px;padding-top:24px}
  .cred-grid{grid-template-columns:1fr;gap:0}
  .cred{border-left:0;border-top:1px solid var(--line);padding:30px 0}
  .cred:first-child{border-top:0;padding-top:0}
  .credentials .wrap{padding-block:40px}
}

/* Home "What we test": one hairline tile per menu family (build.js
   homeFamilyTile). auto-fill at 230px gives four columns at the section
   width, so the eight families fill two whole rows, and one column on a
   phone. The tile's own links sit at the foot; the family link does not
   stretch across the tile. */
/* Eight families: 4, 2 or 1 columns so no row is left with an empty cell. */
/* Six "what we test" cards: three across, two rows. */
.grid--fams{grid-template-columns:repeat(3,minmax(0,1fr))}
@media (max-width:1000px){.grid--fams{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:520px){.grid--fams{grid-template-columns:minmax(0,1fr)}}
.fam-tile .go{align-self:flex-start;margin-top:auto}
.fam-tiles-all{margin-top:28px}
/* Home "Who we work with": one compact row of sector labels. */
.who-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px 20px}
.who-row .eyebrow{margin:0}
.who-list{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0}

/* Where a form says what actually happened. Persistent node, so the live
   region keeps working; hidden while empty. */
.form-status{font-size:var(--t-small);color:var(--g6);line-height:1.6;margin:12px 0 0}
.form-status:empty{display:none}

/* ---------- sections ---------- */
.section{padding-block:var(--space-section);margin:0}
.section > .wrap{max-width:var(--seg)}
.section--alt{background:var(--g05);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.section--warm{background:var(--bw);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
/* The "Recognised by GOED" band (build2.js awardBand): the words on the left,
   the GOED SAP Recipient banners on the right. The banners are on a
   transparent ground, so they float on the warm band with no frame. Under
   760px they drop below the words, centred. */
.recognition{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,420px);gap:52px;align-items:center}
.recognition .section-head{margin-bottom:0}
.recognition-text .btn-row{margin-top:24px}
.recognition-art{margin:0}
.recognition-art img{display:block;width:100%;height:auto}
@media (max-width:760px){
  .recognition{grid-template-columns:1fr;gap:28px}
  .recognition-art{max-width:460px;margin-inline:auto}
}
.custom-band{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,504px);gap:50px;align-items:center}
.custom-band .section-head{margin-bottom:0}
.custom-band-text .btn-row{margin-top:24px}
.custom-band-art{margin:0}
.custom-band-art img{display:block;width:100%;height:auto}
@media (max-width:760px){
  .custom-band{grid-template-columns:1fr;gap:28px}
  .custom-band-art{max-width:460px;margin-inline:auto}
}
.section--tight{padding-block:var(--space-tight)}
.section-head{max-width:680px;margin-bottom:34px}
.section-head h2{font-size:var(--t-h2);font-weight:300;color:var(--ink);letter-spacing:-.026em;line-height:1.18;margin-bottom:12px}
.section-head p{color:var(--g6);margin:0;font-size:var(--t-lead);line-height:1.6}
.sub-head{font-size:var(--t-h3);font-weight:500;color:var(--ink);margin:44px 0 16px;padding-bottom:10px;border-bottom:1px solid var(--line)}
.sub-head:first-child{margin-top:0}
.page-head{background:var(--w);border-bottom:1px solid var(--line);padding:56px 0 48px}
.page-head .wrap{max-width:var(--maxw)}
.crumb{display:flex;align-items:center;gap:8px;font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase;color:var(--g5);margin-bottom:14px;flex-wrap:wrap}
.crumb a{color:var(--g5);border:0}
.crumb a:hover{color:var(--red)}
.page-head h1{font-size:var(--t-h1);font-weight:300;color:var(--dark);letter-spacing:-.032em;line-height:1.12;margin-bottom:14px;max-width:20ch}
.page-head .lede{font-size:var(--t-lead);color:var(--g6);max-width:62ch;margin:0;line-height:1.62}
/* The optional hero visual (a page passes o.visual to build.js's page()): copy
   on the left, a ~408px picture column on the right, centred against it. Only a
   page that opts in carries .page-head--visual, so every other page-head is
   untouched. The 408px matches VISUAL_SIZES in build.js so the browser picks
   the right derivative. */
/* (A tighter variant — copy capped at 62ch, visual packed beside it — was
   tried on 2026-10-06 and reverted the same day at the laboratory's request:
   "return to original spacing".) */
.page-head--visual .page-head-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,347px);gap:56px;align-items:center}
.page-head--visual .page-head-copy .lede{margin-top:0}
/* Tests page only (the one page whose first section holds the flagship
   package): the hero and the Panels section sit 15% closer — both sides of the
   gap (48px + --space-section) take .85 (owner, 2026-10-08). */
.page-head--visual:has(+ .section .flagship){padding-bottom:calc(48px * .85)}
.page-head:has(+ .section .flagship) + .section{padding-top:calc(var(--space-section) * .85)}
/* FULL-WIDTH BANNER HEADER (page({ banner }), the Tests page since
   2026-10-08). The photograph is composed for it — drop on the right, room on
   the left — so it spans the header behind the copy, cropped from the right
   so the drop is always in frame, and the copy keeps to the left half. The
   ground colour under the picture matches the photo's own off-white, so a
   slow image never flashes a white box. Below 900px the picture drops under
   the copy (flex order) at 4:3, still anchored right: the words never sit on
   the photograph where there is no room beside it. */
.page-head--banner{position:relative;overflow:hidden;background:#fff;display:flex;align-items:center;min-height:clamp(340px,34vw,480px);padding:56px 0 calc(48px * .85)}
.page-head--banner .page-head-bg{position:absolute;inset:0;margin:0}
/* The photo's ground read grey against the site's white (laboratory,
   2026-10-08: "needs to be a white back ground ... or fade more to white"),
   so the banner is the white-balanced copy (scripts/whiten-background.mjs)
   and its ground IS white. A light white wash stays over the left side only,
   so the copy never sits on the faint outer ripples on narrower screens;
   it is gone well before the drop (~70% across at 1280-1600px). */
.page-head--banner .page-head-bg::after{content:"";position:absolute;inset:0;pointer-events:none;background:linear-gradient(to right,#fff 0%,#fff 30%,rgba(255,255,255,0) 58%)}
/* ZOOMED OUT (laboratory, 2026-10-08: "i dont want to take such a zoomed in
   view, zoom out maybe 35%"). Filling the header's width blew the drop up on
   wide screens, so the photo is drawn at 58.5% of the header width (65%, then 10%
   smaller: laboratory 2026-10-08 "zoom out the oil drop picture 10%"), anchored
   bottom-right: the ripples rest on the header's bottom edge and anything
   that does not fit is lost off the TOP (the falling stream), never the
   pool. Its ground is white (the white-balanced copy), so where the photo
   ends the page simply continues — there is no edge to see. */
.page-head--banner .page-head-bg picture{position:absolute;right:0;bottom:0;width:58.5%;display:block}
.page-head--banner .page-head-bg img{display:block;width:100%;height:auto}
.page-head--banner > .wrap{position:relative;width:100%}
.page-head--banner .page-head-copy{max-width:min(600px,52%)}
@media (max-width:900px){
  .page-head--banner{flex-direction:column;align-items:stretch;min-height:0;padding:40px 0 0}
  .page-head--banner .page-head-bg{position:relative;order:2;margin-top:28px}
  .page-head--banner .page-head-bg::after{background:linear-gradient(to bottom,#fff 0%,rgba(255,255,255,0) 35%),linear-gradient(to right,rgba(255,255,255,.7) 0%,rgba(255,255,255,0) 45%)}
  .page-head--banner .page-head-bg picture{position:static;width:100%}
  .page-head--banner .page-head-bg img{height:auto;aspect-ratio:4/3;object-fit:cover;object-position:right center}
  .page-head--banner .page-head-copy{max-width:none}
}
.page-head-visual{margin:0}
.page-head-visual picture{display:block}
/* No frame: the source is a transparent cut-out, so it floats on the white
   page-head rather than sitting in a bordered box. */
.page-head-visual img{display:block;width:100%;height:auto}
.award-hero-banners{text-align:center}
.award-hero-banners img{display:block;width:100%;height:auto}
.award-hero-link{display:inline-block;margin-top:12px;font-size:.875rem;color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.award-hero-link:hover{color:var(--ink-hover)}
.page-head--visual:has(.award-hero-banners) .page-head-grid{grid-template-columns:minmax(0,1fr) minmax(0,462px)}
/* Below the grid breakpoint the picture drops under the copy and is capped so a
   tall portrait source does not run the hero to full height on a phone. */
@media (max-width:860px){
  .page-head--visual .page-head-grid{grid-template-columns:1fr;gap:28px}
  .page-head--visual .page-head-visual{max-width:300px}
}
/* The GOED Monograph mark in the package page's header (goed-monograph.html),
   at the size the spec band below the header used to draw it, right-aligned in
   the visual column. It keeps .monograph-badge's soft frame — the file is a
   laurel on a white square. Smaller once it drops under the copy. */
.page-head-visual .monograph-badge{width:300px;max-width:100%;margin-left:auto}
@media (max-width:860px){
  .page-head-visual .monograph-badge{width:220px;margin-left:0}
}
/* Not uppercased: the line carries reference methods, and uppercasing printed
   "Modified AOCS Ce 1i-07" as "MODIFIED AOCS CE 1I-07" — the case in an AOCS
   designation is part of it. */
.method-line{display:inline-block;margin-top:16px;font-size:var(--t-micro);letter-spacing:.02em;font-weight:500;color:var(--tl);background:var(--rs);border:1px solid var(--rb);padding:6px 13px;border-radius:var(--r)}

/* ---------- hairline grids ---------- */
.grid{display:grid;gap:0;border-top:1px solid var(--line);border-left:1px solid var(--line)}
/* min(…,100%): on a 320px screen the grid is 279px inside its hairline, and
   a bare 300px minimum made the one column wider than the grid, so every card
   ran 21px into the gutter with its right hairline past the screen edge
   (accreditation.html, resources.html). Wider screens get the same 300px and
   260px floors as before. */
.grid--2{grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr))}
.grid--3{grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr))}
.grid--4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:1000px){.grid--4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){.grid--4{grid-template-columns:minmax(0,1fr)}}
.grid--loose{gap:16px;border:0}
.card,.door{
  background:var(--w);padding:30px 28px;display:flex;flex-direction:column;
  border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  transition:background .15s;
}
.grid--loose .card,.grid--loose .door{border:1px solid var(--line);border-radius:var(--r)}
a.card:hover,a.door:hover{background:var(--g0)}
.card--feature,.door--feature{background:var(--bw)}
a.card--feature:hover,a.door--feature:hover{background:#EFEAE3}
.card .kicker,.door .kicker{font-size:var(--t-label);font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--tl);margin-bottom:12px}
.card h3,.door h3{font-size:var(--t-h3);font-weight:500;line-height:1.3;margin-bottom:9px;color:var(--ink);letter-spacing:-.005em}
.card p,.door p{font-size:var(--t-body);color:var(--g6);margin:0;flex:1;line-height:1.6}
.card .go,.door .go{margin-top:18px;font-size:var(--t-small);font-weight:500;color:var(--ink);display:inline-flex;align-items:center;gap:6px}
/* A certificate shown in a card on the accreditation page: the scan framed
   like the monograph badge and linked to the document it depicts (the link
   is .tile-link so the running-text underline rule leaves it alone); the
   caption, where there is one, in the card's small type. */
.cert-figure{margin:14px 0 16px}
.cert-figure a{display:block}
.cert-figure img{display:block;width:100%;height:auto;border:1px solid var(--line-strong);border-radius:6px;box-shadow:0 4px 14px rgba(28,23,21,.08);background:var(--w)}
.cert-figure a:hover img{border-color:var(--ink)}
.cert-figure figcaption{font-size:var(--t-small);color:var(--g5);line-height:1.5;margin-top:10px}
.section--alt .card,.section--alt .door{background:var(--w)}

/* ---------- panels (quote-only) ---------- */
.panel{
  background:var(--w);display:flex;flex-direction:column;position:relative;
  border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  transition:background .15s;
}
.panel:hover{background:var(--g0)}
.panel .flag{
  position:absolute;top:0;left:0;right:0;background:var(--red);color:var(--w);
  font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;font-weight:700;
  padding:5px;text-align:center;margin:0;
}
.panel-body{padding:30px 28px;display:flex;flex-direction:column;flex:1}
.panel--flagged .panel-body{padding-top:42px}
.panel h3{font-size:var(--t-h3);font-weight:500;line-height:1.3;margin-bottom:8px;color:var(--ink)}
.panel .why{font-size:var(--t-body);color:var(--g6);margin:0 0 18px;line-height:1.6;flex:1}
.panel ul{list-style:none;margin:0 0 20px;padding:0;display:flex;flex-wrap:wrap;gap:5px}
/* A panel with a long test list (the TLC lipid-class panel's eight FAP chips)
   lays them in two columns so its card is no taller than its neighbours. The
   chips keep their natural pill width (justify-items:start), just arranged in a
   grid rather than a single stacked column. */
.panel ul.tests-2col{display:grid;grid-template-columns:1fr 1fr;justify-items:start;gap:6px 10px}
.panel li{font-size:var(--t-label);letter-spacing:.04em;color:var(--g6);border:1px solid var(--line-strong);padding:3px 8px;border-radius:999px}
.panel .foot{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;border-top:1px solid var(--line);padding-top:14px;margin-top:auto}
/* The turnaround is the laboratory's own label for the panel's slowest family,
   and some of those labels open with "Within". At the old, larger size the
   longest one left no room for "Quoted" beside it at the full card width, so
   two cards in a row of three wrapped their foot and four did not. One step
   smaller keeps every foot on one line there; on a narrower card the foot
   still wraps (flex-wrap), as it always could. */
.panel .turnaround{font-size:1.0625rem;font-weight:300;color:var(--ink);letter-spacing:-.02em;line-height:1}
.panel .turnaround small{display:block;font-size:var(--t-label);font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--g5);margin-top:5px}
.panel .quoted{font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;color:var(--tl);font-weight:700;text-align:right}
/* A disclosure or link inside a card sits above any overlay so it is clickable. */
.panel .flagship-scope,.panel .flagship-go,.panel details,.panel .panel-body a{position:relative;z-index:2}
/* The heavy-metals note, visible beside its mark in the picker. */
.pick-note{display:block;width:100%;font-size:var(--t-small);color:var(--g6);line-height:1.45;margin-top:5px}
/* The testing-menu panel deck: the flagship sits in its own box above, and
   these three read as separated, clearly outlined boxes rather than a seamless
   hairline table. Scoped to .panel-deck so the shared .grid/.panel table style
   on other pages is untouched. The gap below the flagship is the separation the
   deck needs; each card takes the stronger line and a soft lift on hover. */
.panel-deck{border:0;gap:16px;margin-top:28px}
.panel-deck .panel{border:1px solid var(--g5);border-radius:var(--r);overflow:hidden;box-shadow:0 1px 3px rgba(28,23,21,.06)}
.panel-deck .panel:hover{border-color:var(--ink);box-shadow:0 6px 18px rgba(28,23,21,.10)}

/* ---------- steps ---------- */
.steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:0;border-top:1px solid var(--line)}
.steps > div{padding:26px 26px 26px 0}
.steps > div + div{padding-left:26px;border-left:1px solid var(--line)}
.steps .n{font-size:var(--t-label);font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--tl);display:block;margin-bottom:12px}
.steps h3{font-size:var(--t-lead);font-weight:500;margin-bottom:8px;color:var(--ink)}
.steps p{font-size:var(--t-body);color:var(--g6);margin:0;line-height:1.6}

/* ---------- tables ---------- */
/* position:relative is what keeps the wrap's own scrolling its own: the
   visually-hidden spans inside the tables are position:absolute, and with no
   positioned ancestor they escaped the wrap and widened the whole page —
   tests.html scrolled sideways from 761 to 939px, further at larger text. */
.table-wrap{position:relative;border:1px solid var(--line);border-radius:var(--r);background:var(--w);overflow-x:auto;overflow-y:hidden}
table{border-collapse:collapse;width:100%;font-size:var(--t-body)}
caption{text-align:left}
thead th{
  text-align:left;padding:11px 16px;font-size:var(--t-label);font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:var(--g5);background:var(--g05);
  border-bottom:1px solid var(--line);white-space:nowrap;
}
td{padding:13px 16px;font-size:var(--t-body);color:var(--g8);border-bottom:1px solid var(--line);vertical-align:middle}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:var(--g05)}
.test-name{display:block;font-size:var(--t-body);font-weight:500;color:var(--ink);border:0}
.test-name:hover{color:var(--red)}
.test-family{display:block;font-size:var(--t-micro);color:var(--g5);margin-top:2px}
td.num{white-space:nowrap;color:var(--g7)}
.scope{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:rgba(118,127,75,.14);color:var(--dark-green);font-size:var(--t-micro);font-weight:700;border:1px solid rgba(118,127,75,.45)}
.scope.out{background:transparent;border-color:var(--g2);color:var(--g5)}
.spec-table td:first-child{width:40%;color:var(--g6);font-weight:400}
.empty{padding:48px 24px;text-align:center;color:var(--g5)}

/* ---------- controls ---------- */
.controls{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:14px}
.search{flex:1;min-width:240px;position:relative}
.search input{width:100%;font-family:var(--font);font-size:var(--t-body);padding:11px 38px 11px 38px;border:1px solid var(--line-strong);border-radius:var(--r);background:var(--w);color:var(--g8)}
.search input:focus{outline:none;border-color:var(--ink);box-shadow:0 0 0 3px var(--ink-soft)}
.search .mag{position:absolute;left:13px;top:50%;transform:translateY(-50%);width:15px;height:15px;color:var(--g4);pointer-events:none}
.search .clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:22px;height:22px;border:0;border-radius:50%;background:var(--g1);color:var(--g6);cursor:pointer;font-size:var(--t-lead);line-height:1;display:grid;place-items:center;padding:0;min-width:24px;min-height:24px;display:grid;place-items:center}
.search .clear:hover{background:var(--g2)}
.chips{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-bottom:22px}
.chip-label{font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;color:var(--g5);font-weight:700;margin-right:4px}
.chip{
  font-family:var(--font);font-size:var(--t-micro);font-weight:500;letter-spacing:.02em;
  padding:7px 13px;border-radius:999px;border:1px solid var(--line-strong);
  background:var(--w);color:var(--g6);cursor:pointer;transition:all .15s;
}
.chip:hover{border-color:var(--ink);color:var(--ink)}
.chip[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--w)}

/* ---------- notes ---------- */
.note{display:flex;gap:11px;align-items:flex-start;border-radius:var(--r);padding:13px 16px;font-size:var(--t-small);line-height:1.6;color:var(--g7);margin:18px 0 0;border:1px solid var(--line)}
.note b{color:var(--g8);font-weight:500}
.note .i{font-weight:700;flex:none}
.note--info{background:var(--g05)}
.note--info .i{color:var(--g5)}
.note--good{background:var(--bw);border-color:rgba(92,157,187,.28)}
.note--good .i{color:var(--pill-green)}
.note--warn{background:var(--rs);border-color:var(--rb)}
.note--warn .i{color:var(--red)}

/* ---------- forms ---------- */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.field{display:flex;flex-direction:column;margin-bottom:20px}
.form-grid>.field{margin-bottom:0}
.field--full{grid-column:1/-1}
.field label{font-size:var(--t-label);font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--g5);margin-bottom:7px}
.field .req{color:var(--red)}
.field input,.field select,.field textarea{
  font-family:var(--font);font-size:var(--t-body);padding:11px 13px;
  border:1px solid var(--line-strong);border-radius:var(--r);
  background:var(--w);color:var(--g8);width:100%;
}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--ink);box-shadow:0 0 0 3px var(--ink-soft)}
.field .help{font-size:var(--t-micro);color:var(--g5);margin-top:6px;line-height:1.5}
.field .err{font-size:var(--t-micro);color:var(--red);margin-top:6px;font-weight:500}
.field .err:empty{display:none}
.field input.bad,.field select.bad{border-color:var(--red);background:var(--rs)}
.check{display:flex;gap:9px;align-items:flex-start;font-weight:400;font-size:var(--t-body);color:var(--g6);cursor:pointer;line-height:1.55;text-transform:none;letter-spacing:0}
.check input{width:auto;margin-top:2px;accent-color:var(--ink);flex:none}
.checks{display:flex;flex-direction:column;gap:14px}
.checks .hint{display:block;font-size:var(--t-micro);color:var(--g5);margin-top:1px}
.opt{font-size:var(--t-micro);color:var(--g5);font-weight:400;letter-spacing:0;text-transform:none;margin-left:4px}

/* ---------- order builder ---------- */
.progress{margin-bottom:30px}
.progress-bar{height:2px;background:var(--g1);overflow:hidden;margin-bottom:13px}
.progress-bar i{display:block;height:100%;background:var(--red);transition:width .3s ease}
.progress-steps{display:flex;gap:8px;flex-wrap:wrap;align-items:center;font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase;color:var(--g5);font-weight:500}
.progress-steps span.on{color:var(--red);font-weight:700}
.progress-steps span.done{color:var(--g6)}
.progress-steps span.done::after{content:" \2713";color:var(--qc-green)}
.progress-steps .sep{color:var(--g4)}
.progress-time{margin-left:auto;color:var(--g5);text-transform:none;letter-spacing:.02em;font-weight:400}
.order-cols{display:grid;grid-template-columns:1fr 300px;gap:32px;align-items:start}
.summary{background:var(--g05);border:1px solid var(--line);border-radius:var(--r);padding:22px 20px;position:sticky;top:92px}
.summary h2{font-size:var(--t-label);font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--g5);margin-bottom:14px;padding-bottom:11px;border-bottom:1px solid var(--line)}
.srow{display:flex;justify-content:space-between;gap:14px;font-size:var(--t-small);padding:6px 0;color:var(--g6)}
.srow b{color:var(--ink);font-weight:500;text-align:right}
/* A row whose value is one unbroken token (the contact page's email address)
   lets the value drop to a line of its own, still on the right, when label
   and value do not fit side by side: at 320px and the two larger Text sizes
   they do not, and the address widened the whole contact column past the
   screen. Other rows keep their value beside the label and wrap inside it. */
.srow--wrap{flex-wrap:wrap;row-gap:2px}
.srow--wrap b{margin-left:auto}
.srow--total{border-top:1px solid var(--line);margin-top:9px;padding-top:12px;font-size:var(--t-body)}
/* Step-1 summary line: a reserved-height line until something is chosen, then
   the choice folded to one line — name, scope, turnaround — with Change to open
   the deck again. Updated in place so it never shifts what is below it. */
.choice-bar{min-height:46px;display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin:0 0 24px;padding:12px 16px;border-radius:var(--r);background:var(--ink-soft);border:1px solid var(--line-strong);font-size:var(--t-body);color:var(--g7)}
.choice-bar:focus{outline:2px solid var(--ink);outline-offset:2px}
.choice-bar .i{color:var(--ink);font-weight:700}
.choice-bar .btn{margin-left:auto}
.choice-text{min-width:0}
.choice-text b{font-weight:500;color:var(--ink)}
.choice-meta{display:block;font-size:var(--t-small);color:var(--g6);margin-top:1px}
.err{font-size:var(--t-small);color:var(--red);font-weight:500;margin:10px 0 0;flex-basis:100%}
.err:empty{display:none}
/* The mobile action bar (build2.js #m-sub / #m-next), sticky at the foot while
   ordering on a narrow screen. scroll-padding keeps a focused field clear of
   it (WCAG 2.4.11 Focus Not Obscured). The summary line's button is Change,
   not Continue, so it stays: the bar carries Continue. */
.mbar{display:none}
#m-sub{font-size:var(--t-small);color:var(--g6)}
@media (max-width:980px){
  body.ordering .mbar{display:flex;position:sticky;bottom:0;z-index:5;gap:12px;justify-content:space-between;align-items:center;margin:16px calc(-1*var(--gutter)) 0;padding:10px var(--gutter);background:var(--w);border-top:1px solid var(--line-strong)}
  html.ordering{scroll-padding-bottom:88px}
}
/* Bulk sample upload (build2.js #bulk-add): the CSV template download and the
   file picker — a quiet secondary affordance under "+ Add another sample" for
   clients sending many samples at once. The file input is visually hidden but
   kept focusable (opacity, not display:none), so the label reads as a button
   and a keyboard user still reaches it; :focus-within carries the ring. */
.bulk-add{margin:16px 0 0;padding:14px 16px;border:1px dashed var(--line-strong);border-radius:var(--r);background:var(--g05)}
.bulk-add>summary{cursor:pointer;font-size:var(--t-small);font-weight:600;color:var(--heading)}
.bulk-add-lead{margin:10px 0 12px;font-size:var(--t-small);color:var(--g7);font-weight:300;line-height:1.5}
.bulk-add-actions{gap:10px;flex-wrap:wrap;margin:0}
.file-btn{position:relative;overflow:hidden;cursor:pointer}
.file-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;font-size:0}
.file-btn:focus-within{outline:2px solid var(--ink);outline-offset:2px}
.bulk-status{margin:12px 0 0;font-size:var(--t-small);font-weight:500}
.bulk-status:empty{display:none}
.bulk-status.is-good{color:var(--dark-green)}
.bulk-status.is-warn{color:var(--red)}
/* Step 1 runs the full width of the page: the samples sheet needs the room,
   and the summary line above it carries what the rail would. The rail comes
   back for the details and review steps (order.js goStep, body.order-wide).
   Scoped to #order — other pages use .order-cols too. minmax(0,…), not a
   bare 1fr: a 1fr track's minimum is the content's, so the 880px sheet
   widened the track and the whole page scrolled sideways between about 640
   and 915px, instead of the sheet scrolling in its own box. */
body.order-wide #order .order-cols{grid-template-columns:minmax(0,1fr)}
body.order-wide #order .order-cols > :first-child{min-width:0}
body.order-wide #order .order-cols > :last-child{display:none}

/* Step 1's samples sheet (order.js paintSamples): one row per sample, like a
   spreadsheet — reference, description, matrix, quantity, tests, status —
   each column headed by a fill-down. It scrolls sideways inside its own box
   when the page is narrower than the sheet; below 640px each sample becomes a
   card and the fill-downs move to a bar above the cards, since the header row
   is hidden there. */
#chooser{margin:0 0 6px}
.sheet-head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:14px 24px;margin:0 0 14px}
.sheet-intro{min-width:0;flex:1 1 320px}
.sheet-title{font-size:1.125rem;font-weight:500;color:var(--heading);margin:0 0 4px}
.sheet-sub{font-size:var(--t-small);color:var(--g6);font-weight:300;line-height:1.55;margin:0;max-width:66ch}
/* May shrink, and its label wrap, so the group fits a 320px screen at the
   largest Text size rather than pushing the page sideways. */
.count{display:inline-flex;align-items:stretch;flex:0 1 auto;max-width:100%;border:1px solid var(--line-strong);border-radius:var(--r);overflow:hidden;background:var(--w)}
.count-label{display:flex;align-items:center;min-width:0;padding:4px 12px;font-size:var(--t-small);color:var(--g6);line-height:1.3}
.count button,.count input{flex:none}
.count button{width:40px;border:0;border-left:1px solid var(--line);background:var(--g05);color:var(--ink);font:inherit;font-size:1.125rem;line-height:1;cursor:pointer}
.count button:hover{background:var(--ink-soft)}
.count button:focus-visible,.count input:focus-visible{outline:2px solid var(--ink);outline-offset:-2px}
.count input{width:58px;height:40px;border:0;border-left:1px solid var(--line);background:var(--w);color:var(--ink);font:inherit;font-size:var(--t-body);font-weight:500;text-align:center;font-variant-numeric:tabular-nums;-moz-appearance:textfield;appearance:textfield}
.count input::-webkit-outer-spin-button,.count input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.sheet-note{margin:0 0 14px}
/* position:relative keeps the hidden header text ("Remove", .vh) inside the
   scroll box rather than widening the page (the .table-wrap fix again).
   container-type lets the Tests editor size itself to the visible box. */
.sheet-scroll{position:relative;overflow-x:auto;container-type:inline-size;border:1px solid var(--g5);border-radius:var(--r);background:var(--w)}
.sheet{width:100%;min-width:880px;border-collapse:collapse;font-size:var(--t-small)}
.sheet thead th{background:var(--g05);text-align:left;font-size:var(--t-label);font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--g6);padding:9px 10px;border-bottom:1px solid var(--line-strong);white-space:nowrap}
.th-in{display:flex;align-items:center;justify-content:space-between;gap:8px}
.fill{display:inline-grid;place-items:center;flex:none;width:24px;height:24px;border:1px solid var(--line-strong);border-radius:6px;background:var(--w);color:var(--dark-green);font:inherit;font-size:.8125rem;letter-spacing:0;text-transform:none;cursor:pointer}
.fill:hover{background:var(--dark-green);border-color:var(--dark-green);color:#fff}
.fill:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.sheet td,.sheet th[scope=row]{padding:5px 6px;border-bottom:1px solid var(--line);vertical-align:middle}
.sheet tbody tr:last-child > *{border-bottom:0}
.sheet .c-n{width:42px;text-align:center;color:var(--g5);font-weight:500;font-variant-numeric:tabular-nums}
.sheet .c-q{width:100px}
.sheet .c-t{width:220px}
.sheet .c-st{width:150px}
.sheet .c-x{width:42px;text-align:center}
/* The cell inputs only — scoped to the sample rows, so the Tests editor's
   checkboxes and search box (also inside the table) keep their own styles. */
.sheet-row input,.sheet-row select{width:100%;padding:7px 8px;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--ink);font:inherit;font-size:var(--t-small)}
.sheet-row input:hover,.sheet-row select:hover{border-color:var(--line)}
.sheet-row input:focus,.sheet-row select:focus{outline:none;border-color:var(--ink);background:var(--g0);box-shadow:0 0 0 1px var(--ink)}
.sheet-row .c-q input{text-align:right;font-variant-numeric:tabular-nums}
.sheet-row select{cursor:pointer}
.sheet-row.sample--flagged > *{background:var(--rs)}
.sheet-row.is-editing > *{background:var(--ink-soft)}
.tcell{display:flex;align-items:center;gap:7px;width:100%;max-width:230px;padding:6px 9px;border:1px solid var(--line-strong);border-radius:6px;background:var(--g0);color:var(--ink);font:inherit;font-size:var(--t-small);text-align:left;cursor:pointer}
.tcell:hover,.tcell[aria-expanded="true"]{border-color:var(--ink);background:var(--w)}
.tcell:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.tcnt{flex:none;min-width:22px;padding:1px 6px;border-radius:999px;background:var(--dark-green);color:#fff;font-size:var(--t-label);font-weight:600;text-align:center}
.tcnt--0{background:var(--g5)}
.tlead{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--g7)}
.tmore{flex:none;color:var(--g6);font-weight:500}
/* A package order's Tests cell names the package, wrapped rather than cut,
   and opens the editor like any other (where the package is unticked). */
.tcell--pkg{max-width:none;background:var(--ink-soft);font-weight:500;line-height:1.35}
.tcell--pkg .tlead{white-space:normal;color:var(--ink)}
.st{display:inline-block;padding:3px 8px;border-radius:999px;font-size:var(--t-label);font-weight:600;line-height:1.3;white-space:nowrap}
.st--good{color:var(--dark-green);background:rgba(118,127,75,.13)}
.st--warn{color:var(--red);background:var(--rb)}
.st--todo,.st--info{color:var(--g6);background:var(--g05)}
.rm{width:30px;height:30px;border:0;border-radius:6px;background:none;color:var(--g5);font:inherit;font-size:1.125rem;line-height:1;cursor:pointer}
.rm:hover{background:var(--rs);color:var(--red)}
.rm:focus-visible{outline:2px solid var(--ink);outline-offset:1px}
/* A sample's Tests editor, opened as a row under it (never a floating box,
   which the sheet's sideways scroll would clip). Its row is as wide as the
   880px sheet, so the editor holds to the visible part of the box (sticky,
   no wider than the box) and its buttons and right-hand tests stay on
   screen when the sheet is scrolled or the page is narrower than it. */
.editor-row > td{padding:0;background:var(--g0)}
.tests-editor{position:sticky;left:0;max-width:100cqw;padding:14px 16px 16px;border-top:2px solid var(--ink)}
.te-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin:0 0 10px}
.te-head b{font-weight:500;color:var(--ink)}
.te-count{font-size:var(--t-small);color:var(--g6)}
.te-acts{display:flex;flex-wrap:wrap;gap:8px;margin-left:auto}
.editor-list{max-height:380px;overflow-y:auto;padding-right:4px}
.sheet-foot{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:12px 0 0}
.fill-bar{display:none}
.mark-legend{margin:14px 0 0;font-size:var(--t-small)}
.mark-legend summary{padding:4px 0;color:var(--g6);font-weight:500;cursor:pointer}
.mark-legend .mark-key{margin:10px 0 0}
@media (max-width:640px){
  .sheet-scroll{overflow:visible;border:0;background:none}
  .sheet,.sheet tbody,.sheet tr,.sheet td,.sheet th[scope=row]{display:block;width:auto;min-width:0}
  .sheet thead{display:none}
  /* "table tr" outranks a bare class, so the card rules name the row in full. */
  .sheet tr.sheet-row{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:0 0 12px;padding:12px;border:1px solid var(--g5);border-radius:var(--r);background:var(--w)}
  .sheet tr.sheet-row > *{padding:0;border:0;background:none}
  .sheet tr.sheet-row.sample--flagged{border-color:var(--red);background:var(--rs)}
  .sheet tr.sheet-row.is-editing{border-color:var(--ink)}
  .sheet .c-n{grid-column:1 / -1;width:auto;text-align:left;color:var(--ink);font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase}
  .sheet .c-n::before{content:"Sample "}
  .sheet td[data-label]::before{content:attr(data-label);display:block;margin:0 0 2px;font-size:var(--t-label);color:var(--g6)}
  /* Reference and description each take a line; matrix and quantity share
     one; tests and status each take a line. */
  .sheet td[data-label="Reference"],.sheet td[data-label="Description"],.sheet .c-t,.sheet .c-st{grid-column:1 / -1;width:auto}
  /* Same weight as the desktop .sheet .c-q{width:100px}, so it wins here. */
  .sheet .c-q{width:auto}
  .sheet .c-x{position:absolute;top:6px;right:6px;width:auto}
  .sheet-row input,.sheet-row select{border-color:var(--line-strong);background:var(--w)}
  .tcell{max-width:none}
  .editor-row{margin:-4px 0 12px}
  .editor-row > td{display:block;border:1px solid var(--ink);border-radius:var(--r)}
  .tests-editor{border-top:0}
  .te-acts{width:100%;margin-left:0}
  .te-tab{flex:1 1 0;padding-inline:8px}
  .fill-bar{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 12px;font-size:var(--t-small);color:var(--g6)}
  .fill-bar .fill{width:auto;height:auto;padding:5px 10px}
}
.test-picker{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:7px;margin-top:9px}
.pick{display:flex;gap:9px;align-items:flex-start;padding:10px 12px;border:1px solid var(--line);border-radius:var(--r);cursor:pointer;background:var(--w);transition:all .15s}
.pick:hover{border-color:var(--line-strong)}
.pick input{margin:2px 0 0;accent-color:var(--ink);flex:none}
.pick.on{border-color:var(--ink);background:var(--ink-soft)}
.pick .nm{font-size:var(--t-small);font-weight:500;color:var(--ink);display:block;line-height:1.35}
.pick .mt{font-size:var(--t-label);color:var(--g5);display:block;margin-top:2px}
/* A test's status mark inside the order builder (order.js markTag): the
   tests page's chip, a size down so it sits in a picker row or a list. */
.order-mark{padding:1px 7px;margin-top:4px;vertical-align:baseline}
.pick .order-mark{display:inline-block}
.group-label{font-size:var(--t-label);font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--g5);margin:20px 0 0;display:block}
/* A sample's Tests editor has two tabs (order.js editorRow): Packages, the
   flagship package and the six panels that used to be step 1's card deck
   (removed 2026-10-06), and Individual tests, the full menu. The tabs are an
   underlined pair, the open one in ink. */
.te-tabs{display:flex;gap:4px;margin:0 0 12px;border-bottom:1px solid var(--line-strong)}
.te-tab{padding:9px 14px;margin:0 0 -1px;border:0;border-bottom:2px solid transparent;background:none;color:var(--g6);font:inherit;font-size:var(--t-small);font-weight:500;cursor:pointer}
.te-tab:hover{color:var(--ink)}
.te-tab[aria-selected="true"]{color:var(--ink);border-bottom-color:var(--ink)}
.te-tab:focus-visible{outline:2px solid var(--ink);outline-offset:-2px}
.te-note{font-size:var(--t-small);color:var(--g6);margin:0 0 10px;line-height:1.5}
/* The Packages tab: one tick box per package, summarised on a line (scope,
   turnaround, Quoted) with its tests named under it, the way .pick rows
   read. The flagship leads, marked as covering every sample; while it is
   ticked the panels are dimmed and unavailable. */
.pkg-list{display:grid;gap:7px}
.pkg{display:flex;gap:10px;align-items:flex-start;padding:11px 13px;border:1px solid var(--line);border-radius:var(--r);background:var(--w);cursor:pointer;transition:border-color .15s,background .15s}
.pkg:hover{border-color:var(--line-strong)}
.pkg input{margin:3px 0 0;accent-color:var(--ink);flex:none}
.pkg.on{border-color:var(--ink);background:var(--ink-soft)}
.pkg--fixed{border-color:var(--line-strong)}
.pkg.is-off{opacity:.55;cursor:not-allowed}
.pkg-body{min-width:0}
.pkg-name{display:block;font-size:var(--t-small);font-weight:500;color:var(--ink);line-height:1.35}
.pkg-flag{display:inline-block;margin-left:6px;padding:1px 7px;border-radius:999px;background:var(--g05);color:var(--g6);font-size:var(--t-label);font-weight:600;letter-spacing:.04em;vertical-align:1px}
.pkg--fixed .pkg-flag{background:var(--ink);color:var(--w)}
.pkg-meta{display:block;font-size:var(--t-label);color:var(--g6);margin-top:3px}
/* --g6, not --g5: at 12px on the ticked row's tint --g5 fell to 4.43:1,
   below WCAG 1.4.3's 4.5:1. --g6 is 6.4:1 on the tint and 7:1 on white. */
.pkg-tests{display:block;font-size:var(--t-label);color:var(--g6);margin-top:3px;line-height:1.45}
/* Individual tests: a search box over the full menu, which is grouped
   under the home-page category headings so a long list stays navigable. */
.picker-search{margin:4px 0 10px}
.picker-search input{width:100%;padding:10px 12px;border:1px solid var(--line-strong);border-radius:var(--r);font:inherit;font-size:var(--t-body);background:var(--w);color:var(--ink)}
.picker-search input:focus-visible{outline:2px solid var(--ink);outline-offset:1px}
.pick-group .group-label{margin:16px 0 8px}
.pick-group:first-child .group-label{margin-top:4px}
.pick-empty{font-size:var(--t-small);color:var(--g6);padding:10px 2px;margin:0}
.confirm{text-align:center;padding:56px 30px;background:var(--w);border:1px solid var(--line);border-radius:var(--r)}
.confirm .tick{width:48px;height:48px;border-radius:50%;background:rgba(118,127,75,.14);border:1px solid rgba(118,127,75,.45);color:var(--dark-green);display:grid;place-items:center;margin:0 auto 20px;font-size:1.375rem}
.confirm h2{font-size:1.5rem;font-weight:300;color:var(--ink);margin-bottom:10px}
.confirm .ref{font-size:1.75rem;font-weight:300;color:var(--red);letter-spacing:-.01em;margin:16px 0 10px;display:block}
.next-steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:0;margin-top:32px;text-align:left;border-top:1px solid var(--line);border-left:1px solid var(--line)}
.next-steps div{border-right:1px solid var(--line);border-bottom:1px solid var(--line);padding:16px 18px}
.next-steps b{font-size:var(--t-small);font-weight:500;display:block;margin-bottom:5px;color:var(--ink)}
.next-steps span{font-size:var(--t-small);color:var(--g6);line-height:1.55}
.pill{display:inline-block;font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;font-weight:700;padding:5px 11px;border-radius:999px;border:1px solid currentColor}
.pill--submitted{color:var(--pill-green)}
.pill--received{color:var(--teal)}
.pill--progress{color:var(--pill-amber)}
.pill--done{color:var(--dark-green)}
.pill--hold{color:var(--red)}

/* ---------- tracking ---------- */
.track{background:var(--w);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.track-head{padding:22px;border-bottom:1px solid var(--line);background:var(--g05);display:flex;flex-wrap:wrap;gap:10px 24px;align-items:center;justify-content:space-between}
.track-head .ref{font-size:1.25rem;font-weight:300;color:var(--ink);letter-spacing:-.01em}
.track-head .meta{font-size:var(--t-small);color:var(--g5)}
.timeline{list-style:none;margin:0;padding:22px}
.timeline li{display:grid;grid-template-columns:22px 1fr;gap:0 16px;padding-bottom:22px;position:relative}
.timeline li:last-child{padding-bottom:0}
.timeline li::before{content:"";position:absolute;left:10px;top:22px;bottom:0;width:1px;background:var(--g2)}
.timeline li:last-child::before{display:none}
.timeline .dot{width:22px;height:22px;border-radius:50%;border:1px solid var(--g2);background:var(--w);display:grid;place-items:center;font-size:var(--t-label);font-weight:700;color:var(--g5);z-index:1}
.timeline li.done .dot{border-color:var(--ink);background:var(--ink);color:var(--w)}
.timeline li.now .dot{border-color:var(--red);color:var(--red);box-shadow:0 0 0 3px var(--rs)}
.timeline h3{font-size:var(--t-lead);font-weight:500;margin:1px 0 4px;color:var(--ink)}
.timeline li:not(.done):not(.now) h3{color:var(--g5);font-weight:400}
.timeline p{margin:0;font-size:var(--t-small);color:var(--g6);line-height:1.6;max-width:60ch}
.timeline .when{font-size:var(--t-label);color:var(--g5);display:block;margin-top:4px;letter-spacing:.04em}

/* ---------- editorial ---------- */
.prose{max-width:68ch}
.prose h2{font-size:1.375rem;font-weight:300;color:var(--ink);margin:38px 0 14px;letter-spacing:-.01em}
.prose h3{font-size:var(--t-h3);font-weight:500;margin:28px 0 10px;color:var(--ink)}
.prose p{font-size:var(--t-lead);line-height:1.72;color:var(--g7)}
.prose ul,.prose ol{padding-left:20px;margin-bottom:18px}
.prose li{margin-bottom:9px;color:var(--g7);line-height:1.68;font-size:var(--t-lead)}
.prose li b{color:var(--g8);font-weight:500}
.pullquote{border-left:2px solid var(--red);padding:4px 0 4px 20px;margin:26px 0;font-size:var(--t-h3);line-height:1.55;color:var(--ink);font-weight:300}
.byline{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:20px;padding-top:18px;border-top:1px solid var(--line)}
.byline .avatar{width:38px;height:38px;border-radius:50%;background:var(--ink-soft);border:1px solid var(--line-strong);color:var(--ink);display:grid;place-items:center;font-weight:500;font-size:var(--t-body);flex:none}
.byline b{font-size:var(--t-body);font-weight:500;color:var(--ink);display:block}
.byline .meta{font-size:var(--t-label);color:var(--g5);letter-spacing:.04em}
.quote{max-width:62ch;margin:0}
.quote blockquote{margin:0 0 22px;font-size:clamp(19px,2.1vw,24px);font-weight:300;line-height:1.5;color:var(--ink);letter-spacing:-.01em}
.quote figcaption{display:flex;align-items:center;gap:13px}
.quote .avatar{width:40px;height:40px;border-radius:50%;background:var(--ink);color:var(--w);display:grid;place-items:center;font-weight:500;font-size:var(--t-body);flex:none}
.quote cite{display:block;font-size:var(--t-body);font-weight:500;font-style:normal;color:var(--ink)}
.quote .role{display:block;font-size:var(--t-small);color:var(--g5)}
.person{background:var(--w);border:1px solid var(--line);border-radius:var(--r);padding:26px 24px}
.person .avatar{width:52px;height:52px;border-radius:50%;background:var(--ink-soft);border:1px solid var(--line-strong);color:var(--ink);display:grid;place-items:center;font-size:var(--t-h3);font-weight:500;margin-bottom:14px}
.person h3{font-size:var(--t-h3);font-weight:500;margin-bottom:3px;color:var(--ink)}
.person .role{font-size:var(--t-micro);color:var(--tl);font-weight:500;margin-bottom:11px;display:block;letter-spacing:.02em}
.person p{font-size:var(--t-body);color:var(--g6);margin:0;line-height:1.65}
.person details{margin-top:12px}
.person summary{font-size:var(--t-small);color:var(--ink);cursor:pointer;font-weight:500;list-style:none}
.person summary::-webkit-details-marker{display:none}
.person summary::before{content:"+ "}
.person details[open] summary::before{content:"\2212 "}
.person details p{margin-top:11px;font-size:var(--t-body)}
/* A portrait in place of the initials disc (2026-10-01): the same circle,
   larger now that it carries a face, the photograph filling it. */
.person .avatar--photo{width:88px;height:88px;padding:0;overflow:hidden;background:var(--g05);border:1px solid var(--line-strong)}
.avatar--photo img{display:block;width:100%;height:100%;object-fit:cover;border-radius:50%}
/* Our-lab founder section: the team card's avatar, name and role, laid out
   as one wide card — avatar, the biography at a reading measure, and a
   column of figures from that biography so the card is filled edge to edge.
   Under 900px the figures run as a row beneath the text; under 640px
   everything stacks. */
.founder{display:grid;grid-template-columns:auto minmax(0,1fr) 230px;gap:28px;align-items:start;padding:34px 36px}
.founder .avatar{width:72px;height:72px;font-size:var(--t-h2);margin-bottom:0}
.founder .avatar--photo{width:132px;height:132px}
.founder h2{font-size:var(--t-h2);font-weight:400;letter-spacing:-.02em;color:var(--ink);margin:0 0 4px}
.founder p,.founder summary{max-width:68ch}
.founder p + p{margin-top:12px}
.founder-facts{list-style:none;margin:0;padding:0 0 0 28px;border-left:1px solid var(--line-strong);display:grid;gap:22px}
.founder-facts b{display:block;font-size:2.125rem;font-weight:300;line-height:1;letter-spacing:-.03em;color:var(--ink);font-variant-numeric:tabular-nums}
.founder-facts span{display:block;font-size:var(--t-small);color:var(--g6);line-height:1.45;margin-top:6px}
/* His distinctions, from the supplied biography (2026-10-06, "more
   accolades"): a two-column list under the paragraphs, each office in the
   small uppercase label style with its body beneath, marked by a short
   olive rule so the block reads as a record, not more prose. */
.founder-honours{list-style:none;margin:20px 0 0;padding:18px 0 0;border-top:1px solid var(--line);display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 28px;max-width:68ch}
.founder-honours li{position:relative;padding-left:14px}
.founder-honours li::before{content:"";position:absolute;left:0;top:.35em;width:3px;height:1.1em;background:var(--ink);border-radius:2px}
.founder-honours b{display:block;font-size:var(--t-label);font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ink);line-height:1.35}
.founder-honours span{display:block;font-size:var(--t-small);color:var(--g6);line-height:1.45;margin-top:3px}
.founder p.founder-media{margin-top:16px;font-size:var(--t-small);color:var(--g6);font-style:italic}
@media (max-width:900px){
  .founder{grid-template-columns:auto minmax(0,1fr)}
  .founder-facts{grid-column:1 / -1;grid-template-columns:repeat(4,minmax(0,1fr));padding:22px 0 0;border-left:0;border-top:1px solid var(--line-strong)}
}
@media (max-width:760px){.founder-facts{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:640px){
  .founder{grid-template-columns:1fr;gap:16px;padding:26px 22px}
  .founder .avatar--photo{width:104px;height:104px}
  .founder-facts{grid-template-columns:1fr;gap:16px}
  .founder-honours{grid-template-columns:1fr}
}
.faq-group{font-size:var(--t-label);font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--tl);margin:42px 0 12px;padding-bottom:9px;border-bottom:1px solid var(--line)}
.faq-group:first-of-type{margin-top:0}
.qa{border-bottom:1px solid var(--line)}
.qa summary{cursor:pointer;list-style:none;padding:15px 40px 15px 0;font-size:var(--t-lead);font-weight:500;color:var(--ink);position:relative;line-height:1.45}
.qa summary::-webkit-details-marker{display:none}
.qa summary::after{content:"+";position:absolute;right:6px;top:14px;font-size:var(--t-h3);color:var(--red);font-weight:300;line-height:1}
.qa[open] summary::after{content:"\2212"}
.qa summary:hover{color:var(--red)}
.qa p{margin:0 0 17px;font-size:var(--t-body);color:var(--g6);line-height:1.7;max-width:66ch}
.sector-detail{margin-top:4px}
.sector-detail summary{cursor:pointer;list-style:none;font-size:var(--t-body);font-weight:500;color:var(--red);padding:8px 0}
.sector-detail summary::-webkit-details-marker{display:none}
.sector-detail summary::before{content:"+ "}
.sector-detail[open] summary::before{content:"\2212 "}
.sector-detail summary:hover{text-decoration:underline}

/* ---------- CTA band ---------- */
/* ---------- live event band ----------
   A dated announcement, so it is deliberately NOT an ink band: near the top
   of the home page an ink band would read as a second hero. It sits directly
   under the cream marks row, so it is on white, its card outlined, and the
   plain section below it is held off by a firm hairline rather than the
   faint one, so the two whites read as two bands. One card, one accent —
   the brown the eyebrows already use. */
.section--event{background:var(--w);border-top:1px solid var(--line);border-bottom:1px solid var(--line-strong)}
.event{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(320px,.85fr);gap:52px;align-items:start}
.event-pitch h2{font-size:var(--t-h2);font-weight:300;letter-spacing:-.026em;line-height:1.18;margin-bottom:12px}
.event-pitch .event-lede{font-size:var(--t-lead);line-height:1.6;color:var(--ink);margin:0 0 16px;font-weight:400}
.event-pitch p{margin:0 0 20px;max-width:62ch}
.event-pitch .btn-row{margin-top:4px}
/* The gummies fill the bottom-left corner beside the show card (2026-10-08).
   The pitch stretches to the row, whose height the CARD sets: the figure has a
   zero flex basis, so it contributes no height of its own and only takes the
   slack left under the buttons, and the picture scales into that space
   anchored bottom-left. It never makes the section taller than the card,
   whatever the Text size; at larger sizes it simply gets smaller. */
.event-pitch{align-self:stretch;display:flex;flex-direction:column}
.event-visual{flex:1 1 0;min-height:0;margin:0;padding-top:24px;max-width:76.5%}
.event-visual picture{display:block;height:100%}
.event-visual img{display:block;width:100%;height:100%;object-fit:contain;object-position:left bottom}
.eyebrow--live{color:var(--dark-brown)}
.live-dot{width:7px;height:7px;border-radius:50%;background:var(--dark-brown);flex:none}
@media (prefers-reduced-motion:no-preference){
  .live-dot{animation:live-pulse 2.6s ease-in-out infinite}
  @keyframes live-pulse{0%,100%{opacity:1}50%{opacity:.3}}
}
.event-card{background:var(--w);border:1px solid var(--line-strong);border-radius:var(--r);padding:8px 24px;position:relative;transition:border-color .15s,box-shadow .15s}
/* The card's one link, to the show's registration page, stretched over the
   whole card (the card holds no other link, so nothing is covered). */
.event-register{display:inline-flex;align-items:center;gap:6px;margin:6px 0 18px;font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase;font-weight:700;color:var(--tl)}
.event-register::after{content:"";position:absolute;inset:0;border-radius:var(--r)}
.event-card:hover{border-color:var(--ink);box-shadow:0 6px 18px rgba(28,23,21,.08)}
.event-card:hover .event-register{color:var(--ink)}
/* The official SupplySide logo above the facts. Big enough to recognise, small
   enough that the meeting invitation stays the main message (the show's brief). */
.event-logo-wrap{margin:14px 0 8px}
/* A horizontal wordmark (measured content 328x94) centred on a 366x366
   transparent canvas with ~36% empty padding top and bottom. Cropping that
   padding with a 3:1 box and object-fit:cover shows the wordmark itself
   larger, tight to the card, without redrawing the show's artwork; the
   content is centred, so a centred cover crop keeps all of it. */
.event-logo{display:block;width:100%;max-width:300px;aspect-ratio:3/1;height:auto;object-fit:cover;object-position:center}
.event-facts{margin:0}
.event-facts>div{display:grid;grid-template-columns:minmax(82px,max-content) minmax(0,1fr);gap:16px;padding:14px 0;border-top:1px solid var(--line)}
.event-facts>div:first-child{border-top:0}
.event-facts dt{font-size:var(--t-label);font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--g5);padding-top:3px}
.event-facts dd{margin:0;font-size:var(--t-body);font-weight:500;color:var(--ink);line-height:1.45}
.event-facts dd span{display:block;font-weight:400;color:var(--g6);font-size:var(--t-small);margin-top:3px}
@media (max-width:860px){
  .event{grid-template-columns:1fr;gap:34px}
  .event-card{padding:6px 20px}
  .event-visual{display:none}
}
/* Below 420px each fact's label sits above its value. Side by side, the
   longest label ("Meeting availability", one line at max-content) left its
   value 66px at the middle Text size and 27px at the largest on a 320px
   screen, and the value's words ran past the screen edge. */
@media (max-width:420px){
  .event-facts>div{grid-template-columns:minmax(0,1fr);gap:4px}
  .event-facts dt{padding-top:0}
}

/* ---------- the testing menu: one family per block ----------
   Each family is "what you can order" (a table) then "what comes back"
   (analytes, behind a details). Full-width stacked panels, not a grid of
   cards: nine cards of unequal height was the layout the old Services
   strip already proved unreadable. */

/* Each family is a collapsible panel (a native <details>, so it still opens
   with JavaScript off): the summary is the family name and its counts, the
   body is the intro, the table and the analyte list. Outlined in the same
   defined line as the panel cards above it. */
.fam{margin-top:12px}
.fam:first-child{margin-top:0}
.fam-panel{border:1px solid var(--g5);border-radius:var(--r);background:var(--w);overflow:hidden;box-shadow:0 1px 3px rgba(28,23,21,.06)}
.fam-panel > summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:16px;padding:18px 22px;transition:background .15s}
.fam-panel > summary::-webkit-details-marker{display:none}
.fam-panel > summary:hover{background:var(--g0)}
.fam-panel > summary:focus-visible{outline:2px solid var(--ink);outline-offset:-3px}
.fam-panel > summary h3{font-size:var(--t-h3);font-weight:500;color:var(--ink);margin:0;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;flex:1}
.fam-panel > summary::after{content:"";flex:none;width:9px;height:9px;border-right:2px solid var(--ink);border-bottom:2px solid var(--ink);transform:translateY(-3px) rotate(45deg);transition:transform .15s ease}
.fam-panel[open] > summary::after{transform:translateY(2px) rotate(225deg)}
.fam-panel[open] > summary{border-bottom:1px solid var(--line-strong)}
.fam-body{padding:20px 22px 22px}
@media (prefers-reduced-motion:reduce){.fam-panel > summary,.fam-panel > summary::after{transition:none}}
@media (max-width:600px){.fam-panel > summary{padding:16px}.fam-body{padding:16px}}
.fam-n{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--g5)}
.fam-intro{margin:0 0 16px;max-width:70ch;color:var(--g6)}
.fam .table-wrap{margin-bottom:0}
/* The package page's scope, in the same panels (build2.js goedScopePanels). */
.scope-groups{margin-bottom:22px}

/* The analyte list. Closed by default: it is reference detail, not a
   decision, and nine open lists is the 8,700px page this replaced. */
.fam-analytes{margin-top:14px;border-top:1px solid var(--line);padding-top:12px}
.fam-analytes > summary{cursor:pointer;font-size:var(--t-small);font-weight:500;color:var(--ink);display:flex;align-items:center;gap:9px;list-style:none;padding:2px 0}
.fam-analytes > summary::-webkit-details-marker{display:none}
.fam-analytes > summary::before{content:"";width:0;height:0;border-left:5px solid currentColor;border-top:4px solid transparent;border-bottom:4px solid transparent;transition:transform .15s ease;flex:none}
.fam-analytes[open] > summary::before{transform:rotate(90deg)}
.fam-analytes > summary:hover{color:var(--ink-hover)}
.analyte-set{margin-top:14px}
.analyte-set-h{font-size:var(--t-label);font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--g5);margin:0 0 8px}
.analyte-set ul{margin:0;padding:0;list-style:none;columns:2;column-gap:32px}
.analyte-set li{break-inside:avoid;font-size:var(--t-body);color:var(--g7);padding:3px 0}
@media (max-width:760px){ .analyte-set ul{columns:1} }
/* The individual fatty acids: the register's shorthand in a fixed-width
   muted column, then the acid name; a green dot marks a line the standard
   certificate carries (the lead above the first group says so). */
.analyte-lead{margin:18px 0 0;max-width:72ch;font-size:var(--t-small);color:var(--g6);line-height:1.55}
/* flex-wrap and a name span that keeps its longest word: the name sits
   beside its code while it fits and moves whole onto its own line under the
   code when it does not (320px at a larger text size), never clipped. */
.fa-list li{display:flex;flex-wrap:wrap;align-items:baseline;gap:0}
.fa-name{flex:1 1 0}
.fa-code{flex:none;min-width:5.8em;margin-right:8px;font-size:var(--t-small);color:var(--g5);font-variant-numeric:tabular-nums;white-space:nowrap}
.fa-std{color:var(--qc-green);font-weight:700;margin-left:6px}

/* Method cell: the code, then the technique beneath it.

   These two classes were emitted by build.js from the beginning and never
   had a rule, so a <b> and a <span> ran together into one string —
   "LAL-METH-22HRGC/HRMS · US EPA 1613B" — inside a td.num that also
   forbids wrapping. Mirrors .test-name / .test-family, which solved exactly
   this for the first column. */
.mcode{display:block;font-weight:500;color:var(--ink)}
.mcode-none{display:block;color:var(--g5)}
.mtech{display:block;font-size:var(--t-micro);color:var(--g5);margin-top:2px;white-space:normal;max-width:22ch}
td.num:has(.mtech){white-space:normal}

/* Key for the status column. The marks carried a title attribute and
   visually-hidden text and nothing a sighted reader could see — a word like
   "Accredited" or "Calculated" still needs a visible key. Built from
   GOED.marks, so the key and the cells cannot drift apart. */
.mark-key{list-style:none;margin:0 0 18px;padding:14px 18px;background:var(--w);border:1px solid var(--line);border-radius:var(--r);display:grid;gap:9px}
.mark-key li{display:flex;align-items:baseline;gap:11px;font-size:var(--t-small);color:var(--g6);line-height:1.5}
.mark-key .mark{flex:none;min-width:104px;text-align:center}
.mark-key-more{padding-top:4px;border-top:1px solid var(--line);margin-top:2px}
.mark-key-more a{font-weight:500}
@media (max-width:560px){ .mark-key li{flex-direction:column;gap:4px} .mark-key .mark{min-width:0;align-self:flex-start} }

/* The site standard is a visible outline on keyboard focus. The search box
   set outline:none and replaced it with a ring, which is fine for a mouse
   and loses the standard for a keyboard. Both now. */
.search input:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

.cta{background:var(--ink);color:var(--w);padding:64px var(--gutter);text-align:center;margin:0;max-width:none}
.cta h2{font-size:var(--t-h2);font-weight:300;line-height:1.2;margin-bottom:12px;color:var(--w);letter-spacing:-.026em}
.cta p{margin:0 auto 26px;color:rgba(255,255,255,.7);font-size:var(--t-lead);max-width:52ch}
.cta .btn-row{justify-content:center}
.cta .btn-primary{background:var(--w);color:var(--ink);border-color:var(--w)}
.cta .btn-primary:hover{background:rgba(255,255,255,.88);border-color:rgba(255,255,255,.88)}
.cta .btn-secondary{background:transparent;color:var(--w);border-color:rgba(255,255,255,.32)}
.cta .btn-secondary:hover{border-color:var(--w);background:rgba(255,255,255,.08)}
.cta a{border:0}

/* ---------- footer: white, hairline, not a dark slab ---------- */
.site-footer{padding:60px var(--gutter) 28px;background:var(--w);border-top:1px solid var(--line)}
.site-footer .wrap{max-width:var(--maxw);padding:0}
.site-footer .cols{display:grid;grid-template-columns:1.7fr 1fr 1fr 1.2fr;gap:34px;padding-bottom:36px}
.site-footer h2{font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;color:var(--g5);margin-bottom:14px;font-weight:700}
.site-footer a{color:var(--g6);font-size:var(--t-small);display:block;margin-bottom:8px;transition:color .15s;border:0}
.site-footer a:hover{color:var(--ink)}
.site-footer p{font-size:var(--t-small);color:var(--g5);margin:0 0 8px;line-height:1.6;max-width:34ch}
.site-footer .logo{height:28px;width:auto;margin-bottom:14px}
.site-footer .footer-hours{margin-top:6px}
.social{margin-top:14px}
.social-link{display:inline-flex;align-items:center;gap:9px;margin:0;border:0;color:#0A66C2;font-size:var(--t-small);font-weight:600;line-height:1;transition:color .15s}
.social-link .li-logo{width:26px;height:26px;flex:none;fill:#0A66C2;transition:fill .15s}
.social-link span{color:var(--g6);transition:color .15s}
.social-link:hover{color:#084d92}
.social-link:hover .li-logo{fill:#084d92}
.social-link:hover span{color:var(--ink)}
.social-link:focus-visible{outline:2px solid #0A66C2;outline-offset:3px;border-radius:4px}
.legal{display:flex;flex-wrap:wrap;gap:10px 24px;justify-content:space-between;padding-top:20px;font-size:var(--t-micro);color:var(--g5);border-top:1px solid var(--line)}
.legal a{display:inline;font-size:var(--t-micro);margin:0;color:var(--g5)}
.legal a:hover{color:var(--ink)}

/* ---------- cookie banner ---------- */
.cookiebar{position:fixed;left:0;right:0;bottom:0;z-index:150;background:var(--w);border-top:2px solid var(--red);box-shadow:0 -6px 24px -14px rgba(0,0,0,.3);padding:20px 0}
.cookiebar .wrap{display:flex;flex-wrap:wrap;gap:20px 32px;align-items:flex-start;justify-content:space-between;max-width:var(--maxw)}
.cookiebar .copy{flex:1;min-width:280px}
.cookiebar h2{font-size:var(--t-lead);font-weight:500;color:var(--ink);margin-bottom:7px}
.cookiebar p{font-size:var(--t-small);color:var(--g6);margin:0;max-width:72ch;line-height:1.6}
/* One button. The Reject and Customise controls went with the tags they
   chose between (build.js COOKIE_BAR has why); their rules went too, so this
   file does not describe a choice the banner no longer offers. */
.cookiebar .acts{display:flex;flex-wrap:wrap;gap:8px;align-items:center;flex:none}
.cookiebar .acts .btn{min-width:150px}
body.has-banner{padding-bottom:9.5rem}

/* Shown only where the hamburger menu IS the navigation. */
.hide-desktop{display:none}
@media (max-width:860px){ .hide-desktop{display:block} }

/* ---------- responsive ---------- */
/* minmax(0,1fr), for the reason given at body.order-wide above: a bare 1fr
   track's minimum is its content's, so one over-long row in the contact
   page's sidebar widened the single column and took the form's heading,
   labels and fields past a 320px screen with it. */
@media (max-width:980px){ .order-cols{grid-template-columns:minmax(0,1fr)} .summary{position:static} }
@media (max-width:900px){
  .site-footer .cols{grid-template-columns:1fr 1fr}
  .steps > div{padding:0}
  .steps > div + div{padding-left:0;border-left:0;border-top:1px solid var(--line);padding-top:22px;margin-top:22px}
}
@media (max-width:860px){
  .site-nav{display:none;position:absolute;top:100%;left:0;right:0;background:var(--w);flex-direction:column;padding:10px var(--gutter) 14px;gap:0;border-bottom:1px solid var(--line);align-items:flex-start}
  .site-nav[data-open="true"]{display:flex}
  .site-nav a{padding:11px 0;font-size:var(--t-lead);width:100%;border-bottom:1px solid var(--line)}
  .site-nav a[aria-current="page"]::after{display:none}
  .site-nav .nav-search{display:block;width:100%;padding:6px 0 14px;border-bottom:1px solid var(--line)}
  .nav-search label{display:block;font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;font-weight:700;color:var(--g6);margin-bottom:6px}
  .nav-search-row{display:flex;gap:8px;align-items:stretch}
  .nav-search input{flex:1;min-width:0;font-family:var(--font);font-size:var(--t-body);padding:8px 10px;border:1px solid var(--line-strong);border-radius:var(--r);background:var(--w);color:var(--ink)}
  .nav-search input:focus-visible{outline:2px solid var(--ink);outline-offset:1px}
  .nav-search .btn{flex:none}
  .nav-toggle{display:block;order:3}
  /* The order builder is the point of the site; hiding its only entry
     point on phones left no route to it at all. Keep it, tightened. */
  .header-actions .btn{
    display:inline-flex;
    padding:8px 12px;
    font-size:var(--t-micro);
    letter-spacing:.01em;
    white-space:nowrap;
  }
  /* the mobile menu's own ordering link, set apart from the six section links */
  .site-nav .nav-order{
    margin-top:6px;
    padding-top:14px;
    border-top:1px solid var(--line);
    color:var(--ink);
    font-weight:500;
  }
  .site-header .wrap{position:relative}
  /* Register (build.js page()): the header row keeps one button below the
     menu breakpoint, "Start an order"; Register moves into the menu, under
     the ordering link and set apart the same way. */
  .header-actions .header-register{display:none}
  .site-nav .nav-register{color:var(--ink);font-weight:500}
}
/* 320px, the header row: logo, "Start an order" and the menu button must
   share 280px at every Text size. These rules sat with the topbar's, above
   the header's base rules, and lost to them at equal weight, so none of them
   ever applied: at the largest Text size the menu button ended 16px past the
   screen and the whole page scrolled sideways. Here, after the base rules and
   the 860px menu rules, they win. The logo is the one thing that may shrink
   (keeping its shape), so the order button and the menu stay whole. */
@media (max-width:359px){
  .site-header .wrap{gap:12px}
  .header-actions{gap:8px}
  .header-actions .btn{padding:8px 10px}
  .brand{flex:0 1 auto;min-width:0}
  .brand img{height:26px;min-width:0;max-width:100%;object-fit:contain;object-position:left center}
}
@media (max-width:760px){
  .table-wrap table,.table-wrap thead,.table-wrap tbody,.table-wrap tr,.table-wrap td{display:block;width:100%}
  .table-wrap thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .table-wrap tr{border-bottom:1px solid var(--line);padding:16px}
  .table-wrap tr:last-child{border-bottom:0}
  .table-wrap td{border:0;padding:4px 0;display:flex;justify-content:space-between;gap:16px;align-items:baseline}
  .table-wrap td::before{content:attr(data-label);font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;color:var(--g5);font-weight:700;flex:none}
  /* A cell with no data-label (a row headed by its own <th>) has no label to
     sit beside, so it is plain block text. As a flex row its text, <b> and
     <a> runs became side-by-side columns, the empty ::before pushed short
     values to the right, and on the package page ("What we need from you")
     the gaps between those runs made the cell wider than a 320px screen. */
  .table-wrap td:not([data-label]){display:block}
  .table-wrap td:not([data-label])::before{content:none}
  .table-wrap td.first{display:block;padding-bottom:10px}
  .table-wrap td.first::before{display:none}
  .table-wrap td.action{display:block;padding-top:12px}
  .table-wrap td.action .btn{width:100%}
  .spec-table td:first-child{width:auto}
  .spec-table td::before{content:none}
  /* The GOED scope table (goed-monograph) has wide cells — a two-line method
     (code + reference) and a Status cell of marks. As the generic
     space-between flex row, those values were pushed to the right and spilled
     past the card, so the table box needed a sideways swipe. Stack each
     cell's label above its value instead: full width, wraps naturally, no
     swipe — the way the other tables' short cells already read. */
  .scope-table td[data-label]{display:block}
  .scope-table td[data-label]::before{display:block;margin:0 0 3px}
  .form-grid{grid-template-columns:1fr}
  .site-footer .cols{grid-template-columns:1fr}
  .cookiebar .acts{width:100%}
  .cookiebar .acts .btn{flex:1;min-width:0}
  body.has-banner{padding-bottom:15rem}
}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} *{transition:none!important;animation:none!important} }
@media print{
  /* The two pages that actually get printed are a test method and the
     order confirmation, and both were coming out as screen layout minus
     the navigation. */
  .site-header,.topbar,.site-footer,.cta,.cookiebar,.nav-toggle,.controls,.chips,.progress,
  .banner-controls,.btn-row,.skip,.acc-grid,.credentials{display:none!important}

  html{font-size:11pt}
  body{background:#fff;color:#000}
  .wrap{max-width:none;padding:0}
  .section{padding-block:12pt;border:0}

  /* a printed page needs to say where it came from */
  main::after{
    content:"lipidanalytical.com — printed from " attr(data-print-src);
    display:block;margin-top:18pt;padding-top:8pt;
    border-top:1pt solid #999;font-size:8pt;color:#555;
  }

  /* keep a table row and its heading together */
  table{page-break-inside:auto}
  tr{page-break-inside:avoid;page-break-after:auto}
  thead{display:table-header-group}
  h1,h2,h3{page-break-after:avoid}

  /* spell out link targets, which are invisible on paper */
  a[href^="http"]::after{content:" (" attr(href) ")";font-size:8pt;color:#555;word-break:break-all}
  a[href^="#"]::after,a[href^="mailto"]::after,a[href^="tel"]::after{content:""}

  /* The sample submission form (submission-form.html, LAL-QA-F-19 filled
     in from an order). Two sheets: page one is the client and billing
     blocks, rows 1-10, the custody signatures and the For Lab Use Only
     block; page two is rows 11-25, the lab's notes and the shipping
     instructions. build2.js puts the page break between the two .sf-page
     divs; these rules keep each sheet's blocks whole and turn the screen's
     summary panels into ruled boxes a pen can write in. Scoped to .sf-page
     so the test-method and order-confirmation rules above are untouched. */
  .sf-page{page-break-inside:auto}
  .sf-page .order-cols{display:grid;grid-template-columns:1fr 1fr;gap:12pt;align-items:stretch}
  .sf-page .summary{position:static;background:#fff;border:1pt solid #000;border-radius:0;padding:8pt 10pt;page-break-inside:avoid}
  .sf-page .summary h3{font-size:10pt;margin:0 0 6pt}
  .sf-page .srow{padding:3pt 0;font-size:9.5pt;color:#000}
  .sf-page .srow b{border-bottom:1pt solid #000!important;color:#000;font-weight:400}
  .sf-page .check{color:#000;font-size:10pt}
  .sf-page .check input{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .sf-page .table-wrap{border:0;border-radius:0;overflow:visible;margin:8pt 0}
  .sf-page table{width:100%;border-collapse:collapse}
  .sf-page th,.sf-page td{border:1pt solid #000;padding:3pt 5pt;font-size:9.5pt;color:#000;vertical-align:top}
  .sf-page td{height:20pt}
  .sf-page td.num{width:1.6em;text-align:right;color:#555}
  .sf-page ul{page-break-inside:avoid}
  /* The lookup and the fill notice are the screen's business and print
     nothing; build2.js hides #sf-gate itself, and the result box goes too. */
  #sf-status{display:none!important}
}


/* ---------- Windows High Contrast / forced-colors ----------
   In forced-colors the browser discards author background-color, so every
   state this design signals with a fill — the current filter chip, the
   active carousel dot, the selected panel, the in-scope tick — disappears
   entirely. Restore each with a border or an outline, which forced-colors
   keeps, and let system colours do the rest. */
@media (forced-colors: active) {
  /* state that was carried by a fill now carries a border */
  .chip[aria-pressed="true"]{ border:2px solid Highlight; }
  .banner-dot[aria-current="true"]::before{ background:Highlight; height:6px; }
  .pick.on, .panel.on, .pkg.on{ outline:2px solid Highlight; outline-offset:2px; }
  .te-tab[aria-selected="true"]{ border-bottom-color:Highlight; }
  /* The closed tab's transparent border is forced to CanvasText, which would
     underline it like the open one; drop its border so only the open tab is
     underlined (in Highlight). */
  .te-tab:not([aria-selected="true"]){ border-bottom-style:none; }
  .scope{ forced-color-adjust:none; color:CanvasText; }

  /* keep focus visible over everything */
  :focus-visible{ outline:3px solid Highlight; outline-offset:2px; }

  /* hairlines vanish in forced-colors — the layout depends on them */
  .grid, .card, .door, .acc-grid, .table-wrap table, .summary{
    border-color:CanvasText;
  }
  /* buttons lose their fill, so give them an edge */
  .btn{ border:1px solid ButtonText; }
  .btn-primary{ forced-color-adjust:none; background:ButtonFace; color:ButtonText; border:2px solid ButtonText; }
}
/* The UA sheet's [hidden]{display:none} loses a specificity tie to any class
   that sets display — .btn{display:inline-flex} beat it, so a hidden button
   still painted. Restate it as the last word. */
[hidden]{display:none!important}

@media (forced-colors: active){
  .is-selected{outline:3px solid Highlight;outline-offset:-3px}
}
/* .srow--total small was here. The only <small> inside a total row was the
   tax note on the order summary's price line, and the site is quote-only —
   the surviving "Estimated turnaround" row carries no <small> at all. */

/* ==========================================================================
   FLAGSHIP PACKAGE — Lipid Labs Omega-3 Quality Testing Package
   A fixed published scope rather than a list assembled per order, so it is
   given a shape nothing else has: a full-width card rather than a member of
   the panel grid. (It used to be the only priced thing on the site, and that
   was the old reason for the shape; pricing is quote-only now and the scope
   is the reason.) Same flat borders and olive accents as everything else —
   the difference is scale, not style.
   ========================================================================== */
/* White ground (2026-10-06, laboratory's request): the outlined flagship
   card and the framed seal define themselves, so the band sits on white like
   the rest of the page rather than the olive tint it used to carry. The
   hairline top and bottom keep it marked off from the neighbours. */
.section--flagship{background:var(--w);border-top:1px solid var(--line);border-bottom:1px solid var(--line-strong)}

/* The home flagship band: the GOED Monograph badge large on the left, and
   every word of the band housed in one outlined, two-tone box beside it —
   white body, tinted foot — rather than a heading floating over a card. The
   badge file is a laurel on a white square, so a soft border, radius and
   shadow make it a deliberate object on the tinted ground. The box's own
   rules (.flagship--housed) follow the .flagship block below, which they
   override. Under 820px the badge sits above the box, centred. */
.monograph-badge{
  display:block;width:184px;height:auto;border-radius:16px;
  border:1px solid var(--line);box-shadow:0 8px 26px rgba(28,23,21,.11);
}
/* The GOED certificate set INSIDE the housed box (.flagship--feature), in its
   top-right corner: it floats, so the heading, package name and scope list
   wrap to its left; the body contains the float so it cannot reach the foot.
   Under 560px it stacks above the text, left-aligned. */
.flagship--feature .flagship-body{overflow:hidden}
.flagship-badge-inset{float:right;width:210px;margin:2px 0 16px 34px}
/* The certificate is a link to the monograph package page. The anchor is the
   floated inset (it carries .flagship-badge-inset) and the badge image fills
   it, so .monograph-badge keeps its own size everywhere else it is used. */
.flagship-badge-link{display:block;border-radius:16px}
.flagship-badge-link .monograph-badge{width:100%;transition:box-shadow .16s ease, transform .16s ease}
.flagship-badge-link:hover .monograph-badge{transform:translateY(-2px);box-shadow:0 14px 34px rgba(28,23,21,.18)}
.flagship-badge-link:focus-visible{outline:2px solid var(--ink);outline-offset:4px;border-radius:18px}
@media (max-width:680px){
  .flagship-badge-inset{width:170px;margin:2px 0 14px 24px}
}
@media (max-width:560px){
  .flagship-badge-inset{float:none;width:150px;margin:0 0 18px}
}
@media (prefers-reduced-motion:reduce){
  .flagship-badge-link .monograph-badge{transition:none}
  .flagship-badge-link:hover .monograph-badge{transform:none}
}

.flagship{
  display:grid;grid-template-columns:1fr auto;gap:0;
  /* The same defined outline as the panel cards (.panel-deck .panel) and the
     menu's family panels, so every box on the page reads as one set. */
  background:var(--w);border:1px solid var(--g5);border-radius:var(--r);
  box-shadow:0 1px 3px rgba(28,23,21,.06);
  position:relative;text-decoration:none;color:inherit;
  transition:border-color .15s,background .15s,box-shadow .15s;
}
.flagship:hover{border-color:var(--ink);background:var(--g0);box-shadow:0 6px 18px rgba(28,23,21,.10)}
.flagship:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.flagship-mark{
  position:absolute;top:0;left:0;background:var(--ink);color:var(--w);
  font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;font-weight:700;
  padding:6px 14px;
}
.flagship-body{display:block;padding:56px 32px 30px}
.flagship h3{font-size:var(--t-h2);font-weight:400;line-height:1.2;margin:0 0 12px;color:var(--ink);letter-spacing:-.02em}
.flagship-why{display:block;font-size:var(--t-lead);color:var(--g6);line-height:1.6;margin:0 0 22px;max-width:62ch}
.flagship-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.flagship-list li{position:relative;padding-left:22px;font-size:var(--t-body);color:var(--g7);line-height:1.5}
.flagship-list li::before{
  content:"";position:absolute;left:0;top:.55em;width:9px;height:9px;
  background:var(--qc-green);border-radius:50%;
}
.flagship-foot{
  display:flex;flex-direction:column;justify-content:center;gap:18px;
  padding:32px;border-left:1px solid var(--line);background:var(--g05);
  min-width:250px;text-align:right;
}
/* Was .flagship-price, at 40px, holding the package's published figure. The
   foot now leads with the package turnaround, which is words as well as
   digits, so the size comes down to fit the 250px column without wrapping
   mid-phrase. (No figure is named in this file even in a comment: this
   stylesheet ships verbatim and is inlined whole into the shareable bundle,
   so a withdrawn price written here is a withdrawn price in a client's
   hands. The rationale with the numbers in it lives in build.js.) */
.flagship-lead{
  font-size:1.75rem;font-weight:300;color:var(--ink);letter-spacing:-.03em;line-height:1.15;
  font-variant-numeric:tabular-nums;
}
.flagship-lead small{
  display:block;font-size:var(--t-label);font-weight:500;letter-spacing:.12em;
  text-transform:uppercase;color:var(--g5);margin-top:8px;
}
/* Same treatment as .panel .quoted, so the flagship and the panels say the
   one thing the site says about money in the one voice. */
.flagship-quoted{font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;color:var(--tl);font-weight:700}
.flagship-go{font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase;font-weight:700;color:var(--tl)}
@media (max-width:820px){
  .flagship{grid-template-columns:1fr}
  .flagship-foot{border-left:0;border-top:1px solid var(--line);text-align:left;min-width:0}
}
/* The home page's housed flagship box (.flagship-feature above): an ink
   outline, the white body over a tinted foot that runs the full width — two
   tones, top and bottom, so the body keeps the whole width for its text —
   and no hover, because the box is not a link; its link is in the foot. */
.flagship--housed{grid-template-columns:1fr;border-color:var(--ink)}
.flagship--housed:hover{border-color:var(--ink);background:var(--w)}
.flagship--housed .flagship-body h2{font-size:var(--t-h2);font-weight:300;line-height:1.2;letter-spacing:-.02em;color:var(--ink);margin:6px 0 10px}
.flagship--housed h3{font-size:1.25rem;font-weight:500;margin-top:6px}
.flagship-count{font-size:var(--t-body);color:var(--g6);line-height:1.6;margin:8px 0 20px;max-width:56ch}
.flagship--housed .flagship-foot{
  flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:flex-start;gap:14px 28px;
  padding:22px 32px;border-left:0;border-top:1px solid var(--line-strong);text-align:left;min-width:0;
}
.flagship--housed .flagship-quoted{margin-left:auto}
@media (max-width:560px){
  .flagship--housed .flagship-foot{flex-direction:column;align-items:flex-start}
  .flagship--housed .flagship-quoted{margin-left:0}
}

/* EPA and DHA in Our lab's header (fa-structures.js): inline SVG, so the
   bonds, the atom labels and the names take the site's own colours and
   Poppins. Single bonds in the warm dark grey, each acid's double bonds and
   carboxyl in its accent (olive EPA, brown DHA, set per molecule as
   --fa-accent). Type is in em of the inherited size, so the Text size
   control reaches it; at the visual column's width it renders at or above
   the site's 12px floor. */
.fa-visual{width:100%}
.fa-structures{display:block;width:100%;height:auto;overflow:visible;font-family:var(--font);--fa-accent:var(--ink)}
.fa-structures .fa-bond{stroke:var(--g7);stroke-width:1.7;stroke-linecap:round;fill:none}
.fa-structures .fa-db{stroke:var(--fa-accent);stroke-width:1.9}
.fa-structures .fa-co{stroke:var(--fa-accent)}
.fa-structures .fa-atom{fill:var(--fa-accent);font-size:.95em;font-weight:500;dominant-baseline:central}
.fa-structures .fa-name{fill:var(--fa-accent);font-size:2.05em;font-weight:300;letter-spacing:-.02em}
.fa-structures .fa-full{fill:var(--g6);font-size:.98em;font-weight:400}
.fa-structures .fa-short{fill:var(--g5);font-size:.86em;font-weight:600;letter-spacing:.1em}
/* Below 860px the header visual column is capped at 300px, which would set
   this drawing's smallest caption under the site's 12px floor; it may run
   wider. */
@media (max-width:860px){.page-head--visual .page-head-visual:has(.fa-visual){max-width:440px}}
/* Our lab: the header shares the founder card's frame (--seg, like every
   .section below it) so the copy's left edge and the drawing's right edge
   line up with the card instead of overhanging it by 60px each side. */
.page-head--visual:has(.fa-visual) > .wrap{max-width:var(--seg)}

/* Our lab's Equipment section: the heading and its line on the left, the
   instruments photo on the right (white ground, no frame, like the header
   visuals), the four cards below. Under 860px the photo drops under the
   words. */
.equipment-head{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,400px);gap:56px;align-items:center;margin-bottom:34px}
.equipment-head .section-head{margin-bottom:0}
.equipment-visual picture{display:block}
.equipment-visual img{display:block;width:100%;height:auto}
@media (max-width:860px){.equipment-head{grid-template-columns:1fr;gap:24px}.equipment-visual{max-width:360px}}

/* Our lab's "Find the laboratory": address and directions on the left, the
   saved OpenStreetMap map on the right in the same defined outline as the
   site's cards; under 860px the map drops below the words. The map link is
   written on the site-wide in-text link selector plus a class so it loses
   that rule's underline. */
.find-us{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,560px);gap:56px;align-items:center}
.find-us .section-head{margin-bottom:14px}
.find-us address{font-style:normal;font-size:var(--t-lead);color:var(--g7);line-height:1.6;margin:0 0 10px}
.find-us-text > p{color:var(--g6);margin:0}
.find-us-text .btn-row{margin-top:22px}
.find-us-map{margin:0}
main a.map-link:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link){
  display:block;border:1px solid var(--g5);border-radius:var(--r);overflow:hidden;
  box-shadow:0 1px 3px rgba(28,23,21,.06);transition:box-shadow .15s,border-color .15s;
}
main a.map-link:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link):hover{border-color:var(--ink);box-shadow:0 6px 18px rgba(28,23,21,.10)}
main a.map-link:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link):focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.find-us-map img{display:block;width:100%;height:auto}
.find-us-map figcaption{margin-top:8px;font-size:var(--t-label);color:var(--g5)}
@media (max-width:860px){.find-us{grid-template-columns:1fr;gap:28px}}

/* A page head's actions (build.js page() o.actions — the Omega-3 package
   page): the buttons under the lede and a one-line note under them. */
.page-head-actions{margin-top:24px}
.page-head-note{margin:12px 0 0;font-size:var(--t-small);color:var(--g6);max-width:62ch}
/* The package page's single qualifying card ("Right for you if") and, at the
   foot, its "Choose a smaller panel if" partner: one card, at a reading
   width, rather than half of a two-up grid. */
.fit-card{max-width:820px}
.fit-card--smaller{margin-bottom:28px}

/* The package page's "What is covered" head: the GOED member mark on the
   left, the section's words on the right. Under 700px the mark sits above
   the words, smaller. */
.covered-head{display:grid;grid-template-columns:auto minmax(0,1fr);gap:48px;align-items:center}
.covered-head .section-head{margin-bottom:0}
.member-mark{display:block;border:0;text-decoration:none}
.member-mark img{display:block;width:120px;height:auto}
.member-mark:focus-visible{outline:2px solid var(--ink);outline-offset:6px;border-radius:var(--r)}
@media (max-width:700px){
  .covered-head{grid-template-columns:1fr;gap:24px}
  .member-mark img{width:96px}
}
/* The two monograph links in that paragraph, made to stand out (the
   laboratory, 2026-10-06): bold, brand green, a solid underline. Written on
   the site-wide in-text link selector plus a class, so it outranks it. */
main a.mono-link:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link){
  color:var(--ink);font-weight:600;border-bottom:2px solid var(--ink);padding-bottom:1px;
  transition:color .15s,border-color .15s;
}
main a.mono-link:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link):hover{color:var(--ink-hover);border-bottom-color:var(--red)}
main a.mono-link:not(.btn):not(.card):not(.door):not(.panel):not(.tile-link):focus-visible{outline:2px solid var(--ink);outline-offset:3px;border-radius:2px}
.covered-head + .grid{margin-top:36px}

/* (The spec band — the "11 determinations" box with the badge beside it —
   was removed from the package page at the laboratory's request on
   2026-10-06; the badge moved into the page header, styled above with
   .page-head-visual .monograph-badge.) */

/* ---- scope table ---- */
.scope-table .scope-head th{
  background:var(--ink-soft);color:var(--ink);font-size:var(--t-label);
  letter-spacing:.12em;text-transform:uppercase;font-weight:700;padding:10px 14px;
  border-top:1px solid var(--line-strong);text-align:left;
}
.m-code{display:block;font-weight:600;color:var(--ink);white-space:nowrap}
.m-ref{display:block;font-size:var(--t-small);color:var(--g5);margin-top:3px}
.mark{
  display:inline-block;font-size:var(--t-label);letter-spacing:.08em;text-transform:uppercase;
  font-weight:700;padding:3px 9px;border-radius:999px;white-space:nowrap;
}
/* Measured on the chip's own tint, not on white: --pill-green there is 4.41:1. */
.mark--iso{background:rgba(118,127,75,.14);color:var(--ink)}
.mark--prl{background:rgba(80,89,40,.09);color:var(--g7)}
.mark--calc{background:var(--g1);color:var(--g6)}
.mark--nonacc{background:rgba(176,124,42,.14);color:var(--pill-amber)}
.mark-who{display:block;font-size:var(--t-small);color:var(--g5);margin-top:5px}
/* The omega-3 ladder on goed-monograph.html (build2.js LADDER): each rung's
   turnaround line, then the marks of the determinations it contains. The
   card's own <p> rule gives every paragraph flex:1, which would push these
   two apart; they sit tight under the description instead. */
.ladder-rung .ladder-meta,.ladder-rung .ladder-marks{flex:none;margin-top:12px;font-size:var(--t-small)}
.ladder-rung .ladder-marks{display:flex;flex-wrap:wrap;gap:6px}

/* ---- two-column prose block ---- */
.split{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:start}
.split > div > p{color:var(--g7);line-height:1.7;margin:0 0 16px}
/* minmax(0,1fr), not 1fr: a 1fr track grows to its widest content, so a table
   in one half widened the whole stacked block (and the prose beside it) past
   a 320px screen instead of scrolling in its own .table-wrap. */
@media (max-width:900px){.split{grid-template-columns:minmax(0,1fr);gap:36px}}

/* ==========================================================================
   BANNER VISUALS — slides 2-4
   The right-hand column carries a photograph with the data panel resting on
   it, matching the two-column rhythm slide 1 already has. Two tones: dark
   for photographs (panel lifts off a scrim), light for the molecular brand
   texture (panel sits flat on it).
   ========================================================================== */
.banner-visual{
  position:relative;border-radius:var(--r);overflow:hidden;
  display:flex;align-items:flex-end;
  min-height:330px;padding:18px;
  isolation:isolate;
}
.banner-visual-img,
.banner-visual picture{position:absolute;inset:0;display:block}
.banner-visual img{
  width:100%;height:100%;object-fit:cover;object-position:center;
  display:block;
}
/* the scrim: without it the panel's white edge fights the photograph */
.banner-visual--dark::after{
  content:"";position:absolute;inset:0;z-index:0;
  background:linear-gradient(165deg,rgba(35,38,28,.20) 0%,rgba(35,38,28,.58) 62%,rgba(35,38,28,.78) 100%);
}
.banner-visual--light{background:var(--g05);align-items:center}
.banner-visual--light::after{
  content:"";position:absolute;inset:0;z-index:0;
  background:linear-gradient(165deg,rgba(251,250,247,.35) 0%,rgba(251,250,247,.72) 100%);
}
.banner-visual--light img{object-fit:cover;object-position:center}

.banner-visual .banner-panel{
  position:relative;z-index:1;width:100%;
  background:rgba(255,255,255,.95);
  border:1px solid rgba(255,255,255,.7);
  border-radius:var(--r);
  box-shadow:0 2px 20px rgba(35,38,28,.16);
}
.banner-visual--light .banner-panel{
  background:var(--w);
  border-color:var(--line-strong);
  box-shadow:0 1px 10px rgba(35,38,28,.07);
}
@media (max-width:900px){
  .banner-visual{min-height:250px}
}
/* A photograph behind a data panel is decoration; if the viewer has asked
   for less motion they still get it, but High Contrast mode drops it so the
   panel is read against a solid ground. */
@media (forced-colors: active){
  .banner-visual-img{display:none}
  .banner-visual::after{display:none}
  .banner-visual{min-height:0;padding:0}
}
