:root{
  --paper:#F5F7F9; --panel:#FFFFFF; --ink:#0A2440; --soft:#4A5F76; --faint:#5F7387;
  --rule:#D8E1E9; --rule2:#EDF1F5;
  --blue:#0D4E9F; --blue-bg:#E7EFF9;
  --orange:#F47F22; --orange-ink:#B0620A; --orange-bg:#FBEEDD;
  --grey:#5F7183; --grey-bg:#ECF0F4;
  /* Pantone 5565 C, sampled off the client's palette sheet */
  --sage:#7F9D91;
  /* Neue Haas Grotesk — Display for headings and UI labels, Text for running
     copy, which is what the two cuts are drawn for.
       1st name  Adobe Fonts web kit (licensed, works for anyone)
       2nd name  desktop install, so it renders before the kit is authorised
       3rd on    Helvetica Neue — closest metric fallback; NHG is the original
                 Helvetica drawing, so the layout barely shifts. */
  --d:"neue-haas-grotesk-display","Neue Haas Grotesk Display Pro","Helvetica Neue",Helvetica,Arial,sans-serif;
  --t:"neue-haas-grotesk-text","Neue Haas Grotesk Text Pro","Helvetica Neue",Helvetica,Arial,sans-serif;
  /* FreightBig Pro, which the brand sheet specs for patient testimonials
     and provider quotes. The .quote component asked for var(--serif) and
     nothing defined it, so the whole font-family declaration was invalid
     and the one place it is used fell back to the running face. */
  --serif:"freight-big-pro","Freight Big Pro",Georgia,"Times New Roman",serif;
  --ease:cubic-bezier(.22,1,.36,1);
}
:root[data-theme="dark"]{
  --paper:#0B1622; --panel:#132434; --ink:#E9F0F6; --soft:#A9BDCE; --faint:#71889B;
  --rule:#26394A; --rule2:#1C2D3E;
  --blue:#6FA8F0; --blue-bg:#16293D;
  --orange:#F0954A; --orange-ink:#E8A657; --orange-bg:#2E2113;
  --grey:#96AABC; --grey-bg:#1B2835;
  --sage:#9FBBAD;
}
:root[data-theme="light"]{
  --paper:#F5F7F9; --panel:#FFFFFF; --ink:#0A2440; --soft:#4A5F76; --faint:#5F7387;
  --rule:#D8E1E9; --rule2:#EDF1F5;
  --blue:#0D4E9F; --blue-bg:#E7EFF9;
  --orange:#F47F22; --orange-ink:#B0620A; --orange-bg:#FBEEDD;
  --grey:#5F7183; --grey-bg:#ECF0F4;
  /* Pantone 5565 C, sampled off the client's palette sheet */
  --sage:#7F9D91;
}
/* Base palette is white/light — dark is opt-in via data-theme. */
*{box-sizing:border-box}
/* Text cut is the default: most of what is on screen is running copy. */
/* The whole scale hangs off the root, so one number moves every rem in the
   stylesheet -- type, padding and gaps together, which is what keeps a
   scale-up from turning into loose type in tight boxes. */
html{font-size:17px}
body{margin:0;min-height:100vh;background:var(--paper);color:var(--ink);font-family:var(--t);font-size:1rem;line-height:1.58;-webkit-font-smoothing:antialiased}


/* ---------- header ---------- */
.site{position:relative;background:var(--panel);border-bottom:1px solid var(--rule);z-index:5}
.hdr{display:flex;align-items:center;gap:1.1rem;padding:1.1rem clamp(1rem,3vw,2.2rem);max-width:1440px;margin:0 auto}
.brand{background:none;border:0;padding:0;cursor:pointer;display:flex;align-items:center;flex:none;line-height:0}
/* One number sets the mark, and the trademark beside it is derived from it.
   Every place that resizes the logo sets --logo-h and nothing else. */
.brand{--logo-h:38px}
.brand img{height:var(--logo-h);width:auto;display:block}
/* The trademark the client asked for, set beside the mark rather than cut
   into the SVG -- their own logo file stays the file they sent us, and when
   a vector carrying it arrives this rule comes straight back out.

   Both offsets are fractions of --logo-h because the file's own geometry is:
   the viewBox is 504.01x101 and the ink inside it runs x 22.77-470.00,
   y 18.72-82.30 (measured off the rendered SVG, not guessed). So the SVG
   carries 34.01 units of empty space past the last letter -- 0.3367 of its
   height -- and the cap line sits 18.72 units down, 0.1853 of it. Left as a
   plain gap the glyph floats a third of a logo-height away from the wordmark
   it belongs to; the negative margin eats that space back and leaves 2px.
   Colour follows --blue, so it inverts with the mark when the theme does. */
.brand .tm,.fbrand .tm{font-size:calc(.25 * var(--logo-h));line-height:1;font-weight:500;
  color:var(--blue);align-self:flex-start;letter-spacing:0;top:0;
  margin:calc(.1853 * var(--logo-h)) 0 0 calc(2px - .3367 * var(--logo-h))}
:root[data-theme="dark"] .brand .tm{color:#fff}
.brand .rev{display:none}
:root[data-theme="dark"] .brand .pos{display:none}
:root[data-theme="dark"] .brand .rev{display:block}
:root[data-theme="light"] .brand .pos{display:block}
:root[data-theme="light"] .brand .rev{display:none}
@media(max-width:820px){.brand{--logo-h:31px}}
.mainnav{display:flex;gap:0;flex-wrap:wrap;min-width:0}
.mainnav > a{font:inherit;font-size:.88rem;letter-spacing:.004em;background:none;border:0;color:var(--ink);padding:.7rem clamp(.5rem,1.15vw,.95rem);cursor:pointer;position:relative;white-space:nowrap}
.mainnav > a::after{content:"";position:absolute;
  left:clamp(.5rem,1.15vw,.95rem);right:clamp(.5rem,1.15vw,.95rem);bottom:.3rem;height:2px;background:var(--orange);transform:scaleX(0);transform-origin:left;transition:transform .3s var(--ease)}
.mainnav > a[aria-expanded="true"]::after,.mainnav > a:hover::after,.mainnav > a.active::after{transform:scaleX(1)}
.mainnav > a:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
/* The logo needs air on its right or the first link reads as part of it. */
.hdr .brand{margin-right:clamp(0rem,1vw,.9rem)}
.util{margin-left:auto;display:flex;align-items:center;gap:.9rem;flex:none}
.util a{font:inherit;font-size:.82rem;letter-spacing:.004em;color:var(--soft);background:none;border:0;cursor:pointer;padding:0}
.util a:hover{color:var(--blue)}
.util .portal{border:1px solid var(--blue);color:var(--blue);padding:.45rem .75rem;
  white-space:nowrap;
  font-size:.78rem;letter-spacing:.004em;border-radius:0 1.09em 0 1.09em}
.util .portal:hover{background:var(--blue);color:#fff}

/* ---------- mega panel: links only ---------- */
.mega{border-top:1px solid var(--rule);background:var(--panel);max-height:0;overflow:hidden;transition:max-height .35s var(--ease)}
.mega > .inner{padding:1.6rem clamp(1rem,3vw,2.2rem) 1.9rem;max-width:1440px;margin:0 auto}
.mega.open{max-height:1100px;box-shadow:0 24px 40px -32px rgba(10,36,64,.45)}
.cols{display:grid;gap:1.6rem;grid-template-columns:repeat(auto-fit,minmax(155px,1fr))}
.col h4{margin:0 0 .75rem;padding-bottom:.5rem;border-bottom:1px solid var(--rule);font-size:.8rem;letter-spacing:.004em;color:var(--blue);font-weight:600}
.col ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.42rem}
.col li button{font:inherit;font-size:.87rem;color:var(--ink);background:none;border:0;padding:0;cursor:pointer;text-align:left;display:flex;align-items:baseline;gap:.5rem;transition:color .2s}
.col li button:hover{color:var(--blue)}
.col li button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.col li button::before{content:"";width:5px;height:5px;flex:none;background:var(--blue);transform:translateY(-2px)}
.col li.lead button{font-weight:700}
.col li.link button{color:var(--blue)}
.col li.link button::before{background:var(--orange)}
.col.cta{border-left:1px solid var(--rule);padding-left:1.3rem}

/* Products: two panes. Pick a way in on the left, see its items on the
   right — so 30 items are reachable in one hover without being a wall. */
.pmenu{display:grid;grid-template-columns:minmax(195px,235px) 1fr;gap:clamp(1.4rem,3vw,2.6rem);align-items:start}
.prail{display:flex;flex-direction:column;gap:.2rem;border-right:1px solid var(--rule);padding-right:1.2rem}
.prail .rl{font-size:.76rem;letter-spacing:.004em;color:var(--orange-ink);margin:0 0 .55rem}
/* Route to the archive page itself — the same control, in the same position,
   as the "Go to" button in the other three menus. */
.prail .fbtn{align-self:flex-start;margin:1.1rem 0 0}
.ptab{display:flex;align-items:baseline;gap:.6rem;width:100%;font:inherit;text-align:left;cursor:pointer;
  background:none;border:0;border-left:2px solid transparent;padding:.55rem .7rem;color:var(--soft);
  transition:color .2s,border-color .2s,background .2s}
.ptab .tn{font-weight:600;font-size:.9rem}
.ptab .tc{margin-left:auto;font-size:.66rem;color:var(--faint);font-variant-numeric:tabular-nums}
.ptab:hover{color:var(--ink);background:var(--rule2)}
.ptab.is-active{color:var(--ink);border-left-color:var(--orange);background:var(--rule2)}
.ptab[aria-selected="true"] .tn{color:var(--ink)}
.ptab:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}

.ppane{min-height:202px}
.ppane .ph{font-size:.76rem;letter-spacing:.004em;color:var(--blue);margin:0 0 .9rem;
  padding-bottom:.5rem;border-bottom:1px solid var(--rule)}
/* The pane header is the second route to a browse path's own page — the rail
   item itself is the first. Same target, two affordances. */
.ppane .phgo{font:inherit;font-size:inherit;letter-spacing:inherit;text-transform:inherit;
  color:inherit;background:none;border:0;padding:0;cursor:pointer;text-align:left}
.ppane .phgo:hover{text-decoration:underline}
.ppane .phgo:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
/* Path-level "view all" sits between the path row and its items. */
.dpath .dgo{padding-left:2.2rem;font-size:.8rem}
.pitems{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.15rem 1.4rem}
@media(max-width:1080px){.pitems{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:620px){.pitems{grid-template-columns:1fr}}
.pitem{display:block;width:100%;text-align:left;font:inherit;background:none;border:0;cursor:pointer;
  padding:.5rem .6rem .5rem 0;color:inherit;border-bottom:1px solid var(--rule2)}
.pitem:hover{color:var(--blue)}
.pitem:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.pitem .in{font-weight:600;font-size:.88rem;display:block}
/* A brand's own mark in place of its name, in the Brands pane. Bounds on both
   axes rather than a fixed height: the pane is three columns wide and drops to
   two and then one, so the column is often narrower than a wide lockup wants
   -- with a fixed height the column would clamp the width and squash the
   mark. Sized to sit with the type it replaces rather than to shout over it;
   the row below it is the same description either way. */
.pitem .in .wordmark{display:block;height:auto;width:auto;
  max-height:1.15rem;max-width:100%;margin:.12rem 0 .1rem}
.pitem .id{font-size:.76rem;color:var(--soft);display:block;margin-top:.12rem;line-height:1.4}
.pitem:hover .id{color:var(--soft)}

.pfoot{grid-column:1/-1;margin-top:1.4rem;padding-top:1.1rem;border-top:1px solid var(--rule);
  display:flex;flex-wrap:wrap;align-items:center;gap:.6rem 1.5rem}
.pfoot .fl{font-size:.76rem;letter-spacing:.004em;color:var(--faint)}
.pfoot > a:not(.cta){font:inherit;font-size:.85rem;background:none;border:0;padding:0;cursor:pointer;color:var(--blue);
  display:flex;align-items:baseline;gap:.45rem}
.pfoot > a:not(.cta)::before{content:"";width:5px;height:5px;background:var(--orange);flex:none;transform:translateY(-2px)}
.pfoot > a:not(.cta):hover{text-decoration:underline}
.pfoot .reach{margin-left:auto;display:flex;flex-wrap:wrap;align-items:center;gap:.35rem 1.1rem}
.pfoot .reach a{font-size:.84rem;color:var(--ink);text-decoration:none;display:flex;align-items:baseline;gap:.45rem}
.pfoot .reach a:hover{color:var(--blue);text-decoration:underline}
.pfoot .reach a svg{width:14px;height:14px;color:var(--orange-ink);flex:none;transform:translateY(1px)}
.pfoot .reach .tel{font-variant-numeric:tabular-nums;letter-spacing:.01em}
.pfoot .cta{border:1px solid var(--blue);padding:.5rem .8rem;
  border-radius:0 1.16em 0 1.16em;font-size:.66rem;
  letter-spacing:.004em}
.pfoot .cta::before{display:none}
.pfoot .cta:hover{background:var(--blue);color:#fff;text-decoration:none}
@media(max-width:1100px){.pfoot .reach{margin-left:0;flex-basis:100%}}
@media(max-width:820px){
  .pmenu{grid-template-columns:1fr}
  .prail{border-right:0;border-bottom:1px solid var(--rule);padding-right:0;padding-bottom:.9rem;
    flex-direction:row;flex-wrap:wrap;gap:.3rem}
  .ptab{width:auto;border-left:0;border-bottom:2px solid transparent;padding:.45rem .6rem}
  .ptab[aria-selected="true"]{border-left-color:transparent;border-bottom-color:var(--orange)}
  .ptab .tc{margin-left:.35rem}
  .prail .rl{flex-basis:100%}
  /* Rail is a wrapped row here, so the button would otherwise sit inline as
     if it were a fifth tab. */
  .prail .fbtn{flex-basis:100%;margin:.6rem 0 0}
}

/* simple sections: a feature block plus cards, so they carry the same
   visual weight as the Products panel without inventing fake depth */
.split{display:grid;grid-template-columns:minmax(210px,270px) 1fr;gap:clamp(1.4rem,3.5vw,2.8rem);align-items:start}
@media(max-width:860px){.split{grid-template-columns:1fr}}
.feature .fl{font-size:.76rem;letter-spacing:.004em;color:var(--orange-ink);display:block;margin-bottom:.6rem}
.feature .ft{font-weight:400;font-size:1.45rem;letter-spacing:-.028em;line-height:1.1;display:block;margin-bottom:.6rem}
.feature .ft b{font-weight:700}
.feature .fp{font-size:.86rem;color:var(--soft);line-height:1.5;margin:0 0 1rem;max-width:32ch}
/* Used by the three feature blocks and by the Products rail. Deliberately not
   scoped to .feature — every menu offers the same route to its landing page,
   so it should be the same control everywhere. */
/* The mark's own corner, rounded top-right and bottom-left. The radius is
   35% of each control's height, which is the proportion measured off the
   logo link — so the em value differs per control because their heights do:
   .btn 3.84em, .fbtn 3.46em, .pfoot .cta 3.30em, .util .portal 3.11em. */
.fbtn{display:inline-block;border:1px solid var(--blue);color:var(--blue);background:none;
  border-radius:0 1.21em 0 1.21em;font:inherit;
  padding:.55rem .85rem;font-size:.76rem;letter-spacing:.004em;cursor:pointer}
.fbtn:hover{background:var(--blue);color:#fff}
.fbtn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

.cardgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:.7rem}
.pcard{border:1px solid var(--rule);background:var(--paper);padding:1rem 1.05rem;text-align:left;
  font:inherit;color:inherit;cursor:pointer;display:flex;flex-direction:column;gap:.55rem;
  transition:border-color .22s,transform .22s var(--ease)}
.pcard:hover{border-color:var(--blue);transform:translateY(-2px)}
.pcard:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.pcard .ic{width:26px;height:26px;color:var(--blue);flex:none}
.pcard:hover .ic{color:var(--orange)}
.pcard .ct{font-weight:600;font-size:.92rem;letter-spacing:-.008em}
.pcard .cd{font-size:.78rem;color:var(--soft);line-height:1.45}
.pcard .cn{font-size:.72rem;letter-spacing:.004em;color:var(--faint);margin-top:auto}
.faces{display:flex;align-items:center}
.faces img{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1.5px solid var(--paper);margin-left:-7px}
.faces img:first-child{margin-left:0}
.faces .more{font-size:.68rem;color:var(--faint);margin-left:.5rem}



/* ===================== page-level design system =====================
   Sits on top of the navigation styles lifted from the prototype. The
   nav owns :root, body and everything under .site / .drawer; everything
   below is the page itself. */

body{font-size:17px;line-height:1.6}
.wrap{max-width:1240px;margin:0 auto;padding:0 clamp(1.1rem,4vw,2.6rem)}

/* The primary nav sits in the middle of the header rather than tucked against
   the logo. Both outer groups take an equal share of the free space, which
   centres the nav on the header itself — a plain `margin:0 auto` would only
   centre it between the logo and the utility links, and those two are nowhere
   near the same width, so the nav would sit visibly off to one side.
   Below 1080px the nav and the utility links are replaced by the burger, so
   none of this applies there -- this number is the burger breakpoint in
   navdata.py and has to move with it. */
@media(min-width:1081px){
  .hdr > .brand{flex:1 1 0}
  .hdr > .mainnav{flex:0 1 auto;justify-content:center}
  .hdr > .util{flex:1 1 0;justify-content:flex-end;margin-left:0}
}

/* Three labels in the mega menu are set at 600 by the prototype's own rules
   and none of them names a family, so each takes whatever it inherits:
   .ptab .tn lands on Display, .pitem .in and .pcard .ct land on Text. That
   split was accidental, and it only became visible once the web kit gained a
   real 600 — Neue Haas Grotesk Text has no 600 weight at all (it runs
   400/500/700), so those two were quietly rendering as Bold while their
   neighbour rendered as Semibold.

   Display is the right cut for them regardless: it is what the stack
   comments reserve for headings and UI labels, and it is what the sibling
   tab labels already use at almost the same size. */
.pitem .in,.pcard .ct{font-family:var(--d)}
.skip{position:absolute;left:-9999px;top:0;background:var(--blue);color:#fff;
  padding:.6rem 1rem;z-index:200}
.skip:focus{left:0}
main{display:block}
a{color:inherit;text-decoration:none}

/* section rhythm */
section.band{padding:clamp(3rem,7vw,5.5rem) 0}
/* The band under a centred hero starts closer to it: the two are one
   composition, and a full band's worth of air between a heading and the form
   it introduces reads as a missing section. */
.hero.mid + section.band{padding-top:clamp(1.6rem,3.4vw,2.6rem)}
section.band.alt{background:var(--panel)}
/* A slim stripe rather than a full band. The partner row is one line of
   artwork, and a band sized for a heading and three paragraphs leaves it
   marooned in its own whitespace. On the panel colour with a rule under it,
   so it reads as its own register between the white hero and the paper
   below rather than as the top of the next section. */
section.band.strip{padding:clamp(1.7rem,3.4vw,2.6rem) 0;background:var(--paper);
  border-bottom:1px solid var(--rule)}
.bandhead{max-width:60ch;margin:0 0 2.2rem}
.bandhead.long h2{font-size:clamp(1.5rem,2.6vw,1.95rem);line-height:1.16}
.bandhead.mid{margin-left:auto;margin-right:auto;text-align:center}
.bandhead.mid .lead{margin-left:auto;margin-right:auto}


.prose.mid{margin-left:auto;margin-right:auto;text-align:center}

/* A hero with nothing beside it can hold the middle of the page. The rule is
   the same one the section heads follow: centre over something symmetric, and
   a single column of copy is symmetric once the artwork is gone. */
/* The hero gives up its own white and its rule. White hero meeting the grey
   band drew a hard line across the page exactly where the eye travels from
   the heading to the form; with both on the page's own ground the card is
   the only white, which is the thing that should be carrying the edge. */
/* A header with no photograph beside it. The grid was holding a column open
   for a picture that is never coming — on a 1200px page that left the
   heading in 558px with 505px of nothing next to it, and the header read as
   a fragment of a layout rather than as a header. One column, the measure on
   the heading, and the height the picture used to provide given back.

   The measure is on the h1 and not on the box around it: ch is a character
   of the element's own type, so the same number on the wrapper would be
   17px body characters — 165px — and the heading would set a word to a line. */
.hero.solo{padding-top:clamp(3rem,7vw,5rem);padding-bottom:clamp(2.6rem,6vw,4.4rem)}
/* The centred one carries a little more air than the ranged-left one. With
   no picture to give the header its height and the copy in the middle of the
   page, the same padding read as a strip rather than as a header. */
.hero.solo.mid{padding-top:clamp(3.6rem,8vw,6.2rem);
  padding-bottom:clamp(3.2rem,7vw,5.4rem)}
.hero.solo .hero-in{grid-template-columns:minmax(0,1fr)}
.hero.solo .hero-txt h1{max-width:17ch}
.hero.solo .hero-txt .lead{max-width:54ch}

.hero.mid{background:none;border-bottom:0;
  padding-bottom:clamp(1.2rem,2.6vw,2rem)}
/* The blue rule that wipes in under a hero marks where the hero ends. Here
   the hero does not end — it runs into the form it introduces — so the rule
   drew the hard line the grey band was being blamed for. */
.hero.mid::after{content:none}
.hero.mid .hero-in{grid-template-columns:minmax(0,1fr)}
/* "Left justify the headline copy while keeping it centered on the page" --
   the client's review. So the block still sits in the middle of the page
   (margin:0 auto) and the type inside it starts at one left edge: the
   heading, its paragraph and the button all begin on the same line, which
   a centred setting cannot give them. */
.hero.mid .hero-txt{text-align:left;max-width:46rem;margin:0 auto}
.hero.mid .hero-txt h1,.hero.mid .hero-txt .lead{max-width:none}
/* The lead was centred inside the block as a box of its own. Ranged left it
   has to start where the heading starts, or the two disagree by however much
   narrower the paragraph happens to be. */
.hero.mid .lead{margin-left:0;margin-right:0}

/* ---------- the home hero's rotating ground ----------
   Four photographs in one box, cross-fading. The rotation is a single
   animation on every frame, staggered by a delay computed from the frame's
   own index, so there is no script to load, nothing to initialise, and no
   state to get wrong: if the CSS arrives the pictures turn, and if it does
   not the first one still fills the hero.

   24s round, 6s to a frame: 1s in, 5s held, 1s out -- the extra second is
   the overlap with the next one. As percentages of the round that is
   4.1667% and 25% and 29.1667%, which is what the keyframes below say. The
   delay runs one second negative so frame 0 is already at full opacity when
   the page paints rather than fading up into view. */
/* The photographic hero is taller than the lattice one was. A drawn ground
   is a texture and needs only as much room as the words; a photograph is a
   picture and wants area, or it reads as a strip behind a headline.

   Four classes because the padding-top it overrides is set on
   `.hero.has-bg.onink` in honeycomb.CSS, which is appended after this sheet.
   The header compensation has to be carried across with it: the hero is
   pulled up under the floating header and pays the height back as padding,
   so the top padding is that debt plus the breathing room, not just the
   breathing room. */
/* The room is measured against the window's height as well as its width.
   Width alone is what the rest of the sheet uses, and for a band of type it
   is right -- but a hero sized only on vw is 69% of a 900px window and 95% of
   a 720px one, and the second is a laptop with nothing on screen but a
   headline. min() takes whichever of the two is smaller, so a short window
   gets a shorter hero; max() puts a floor under it for a phone, where both
   readings are small. */
.hero.has-bg.onink.hero-car{
  padding-top:calc(var(--hdr-h,4rem) + var(--float-gap,.7rem)
    + max(4.2rem, min(12vw, 16vh, 10rem)));
  padding-bottom:max(3.6rem, min(10vw, 14vh, 8.5rem))}

.hcar{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.hcar-f{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:center;opacity:0;
  animation:en-hcar 24s linear infinite both;
  animation-delay:calc(var(--i) * 6s - 1s)}
@keyframes en-hcar{
  0%{opacity:0} 4.1667%{opacity:1} 25%{opacity:1} 29.1667%{opacity:0}
  100%{opacity:0}}
/* The veil sits over the pictures and under the copy. It is what makes four
   different photographs -- a white product shot and a navy laboratory frame
   among them -- carry the same white type.

   One vertical gradient rather than a veil plus a radial pool under the copy.
   The pool was the honeycomb hero's device and it does not survive here: that
   hero's copy is a column, this one's is a 782px band, and honeycomb.CSS
   states the rule an ellipse has to keep -- it must reach zero inside its own
   box, or the box's edge cuts it dead straight. It could not. At 1024 the
   band leaves 121px either side of itself before the hero clips, which is not
   enough run-off for any ellipse wide enough to cover it; the version that
   shipped was still carrying .33 alpha where its box ended, drawing two hard
   lines across the photograph 154px below the top of the hero and 50px above
   the bottom.

   A vertical gradient has no corners and nothing to cut: it spans the full
   width at every stop, so there is no edge for a clip or a box to find. The
   band is weighted where the copy sits -- 34% to 82% of the hero's height,
   measured off the text rather than guessed -- and lifts above and below it,
   so the photograph is at its most visible exactly where no words are over
   it. */
.hcar::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(10,36,64,.56) 0%,
    rgba(10,36,64,.48) 24%,
    rgba(10,36,64,.72) 34%,
    rgba(10,36,64,.72) 82%,
    rgba(10,36,64,.62) 100%)}
/* Older imported homepage content can contain the original empty veil span.
   The pseudo-element above is deliberately authoritative so the overlay no
   longer depends on WordPress preserving an empty HTML element. */
.hcar-veil{display:none}
/* And the honeycomb hero's pool is switched off here, or it paints on top of
   the band and the copy sits under two devices doing one job. Five classes
   because that is what it takes to out-specify the rule it cancels, which is
   set on four and lives in a sheet appended after this one. */
.hero.has-bg.onink.mid.hero-car .hero-txt::before{background:none}
/* Nothing should move for a reader who has asked for that. The first frame
   stays, the rest are simply not shown -- a carousel that cannot animate is
   a picture, not a broken carousel. */
@media(prefers-reduced-motion:reduce){
  .hcar-f{animation:none;opacity:0}
  .hcar-f[style*="--i:0"]{opacity:1}}

/* A form that is the page reads as a column down the middle. The labels stay
   ranged left inside it: a label centred over its own input stops marking
   where the typing will start, which is the one thing it is there to do. */
/* A form that is the page gets a container. Floating in an open band the
   fields read as an unfinished area rather than as one thing to fill in.
   48rem is about 800px: wide enough for two columns of field, narrow enough
   that the eye does not have to travel between a label and its box. */
.form.mid{max-width:48rem;margin-left:auto;margin-right:auto;text-align:left;
  background:var(--panel);border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  padding:clamp(1.5rem,3.6vw,2.3rem);
  box-shadow:0 18px 44px -36px rgba(10,36,64,.55)}
.form.mid .btn{display:block;margin-left:auto;margin-right:auto}
/* The other way in, for somebody who already has an account. It sits under
   the centred form, so it centres with it -- left-ranged under a centred
   page it read as a stray.
   The separation is margin and nothing else. An earlier version drew a
   hairline above it by giving the button 1.9rem of top padding, border-top:0
   and an ::after -- which is a separator drawn ON the button instead of
   above it. The label sat low in a box with 32px of air over it and 12px
   under, the frame lost its top edge while keeping its rounded corners, and
   the hover fill covered the whole of it. Air is enough: the submit button
   is inside the form and this one is not.
   max-width is load-bearing, though. width:max-content on a label this long
   is 408px of button in a 375px phone, and the page scrolled sideways.
   Capped, the label wraps and the button stays inside the screen. */
.form.mid + .btn{display:block;width:max-content;max-width:100%;
  margin:2.8rem auto 0;text-align:center}

/* The submit is the only thing on this page a person came to do, so it is
   filled rather than outlined. Everywhere else an outlined button is right:
   they sit among other things and should not shout over them. */
.form .btn{background:var(--blue);border-color:var(--blue);color:#fff;
  padding:.95rem 1.8rem}
.form .btn::before{background:#092F62}
.form .btn:hover,.form .btn:focus-visible{color:#fff}

/* A button with nowhere to go yet. It keeps the button's shape so the page
   can be judged as designed, and loses everything that says "press me": no
   hover, no pointer, and a line beside it saying what is missing. */
.waiting{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;margin:1.5rem 0 0}
.btn.off{margin-top:0;border-style:dashed;border-color:var(--rule);
  color:var(--faint);cursor:default;background:none}
.btn.off::before{content:none}
.waiting .wnote{font-size:.8rem;color:var(--faint)}

/* ---------- a page with a rail ----------
   Two columns: a standing summary and the detail. The rail is sticky under
   the floating island — it has to clear both the island and the gap the
   island floats in, which is what --hdr-h and --float-gap are for. Below
   860px it stops being a rail and becomes the page's opening paragraph,
   which is the only honest thing a sidebar can do on a phone. */
.railwrap{display:grid;grid-template-columns:minmax(0,15rem) minmax(0,1fr);
  gap:clamp(1.8rem,4vw,3.4rem);align-items:start}
@media(max-width:860px){.railwrap{grid-template-columns:1fr}}
.rail{position:sticky;top:calc(var(--hdr-h,4rem) + var(--float-gap) + 1.2rem)}
@media(max-width:860px){.rail{position:static}}
.rfig{margin:0;display:grid;gap:1.1rem}
.rfig dt{font-family:var(--d);font-size:.66rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.rfig dd{margin:.15rem 0 0;font-family:var(--d);font-weight:600;
  font-size:1.85rem;line-height:1;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.rfig p{margin:.3rem 0 0;font-size:.76rem;color:var(--soft);max-width:22ch}
.rjump{display:grid;gap:.45rem;margin-top:1.8rem;padding-top:1.2rem;
  border-top:1px solid var(--rule)}
/* 23px of line box, one short of the 24 WCAG 2.2 asks of a navigation
   target. The grid gap absorbs the padding, so the list does not move. */
.rjump a{font-size:.86rem;color:var(--soft);text-decoration:none;
  padding-block:1px;margin-block:-1px}
.rjump a:hover{color:var(--blue)}
@media(max-width:860px){
  .rfig{grid-template-columns:repeat(auto-fit,minmax(9rem,1fr))}
  .rjump{display:none}
}
/* The body's own bands have already been opened by the section around the
   rail, so they need spacing rather than padding of their own. */
.railbody > .bandhead{margin-top:3rem}
.railbody > .bandhead:first-child{margin-top:0}

/* ---------- trials ----------
   Two columns: these carry a paragraph each, and at three across the text
   sets too narrow for the sentence the client wrote. The figures sit on a
   rule at the foot of the card, so a reader scanning for scale finds them
   in the same place on every one. */
/* Cards in a row take the same height. The figures are then pushed to the
   foot rather than following the paragraph, so the rule they sit on lands at
   the same place on every card and a reader scanning for scale finds them
   without reading anything — which was the point of setting them as figures.
   A card with no figures simply keeps the space. */
.trials{display:grid;gap:1rem;grid-template-columns:repeat(var(--c),minmax(0,1fr))}
@media(max-width:860px){.trials{grid-template-columns:1fr}}
.trial{background:var(--panel);border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  padding:clamp(1.2rem,2.6vw,1.6rem);display:flex;flex-direction:column;gap:.55rem}
.trial .tst{font-family:var(--d);font-size:.66rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--orange-ink)}
.trial h3{font-family:var(--d);font-size:1.06rem;letter-spacing:-.01em;margin:0}
.trial p{margin:0;color:var(--soft);font-size:.92rem}
.tfig{display:flex;flex-wrap:wrap;gap:0 2.2rem;margin:auto 0 0;padding-top:.9rem;
  border-top:1px solid var(--rule2)}
.tfig dt{font-family:var(--d);font-size:.64rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.tfig dd{margin:.1rem 0 0;font-family:var(--d);font-weight:600;font-size:1.5rem;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}

/* ---------- published work ---------- */
.studies{display:grid;gap:0;border-top:1px solid var(--rule)}
.study{padding:1.15rem .2rem;border-bottom:1px solid var(--rule)}
.study .sy-t{display:block;font-family:var(--d);font-weight:600;font-size:1rem;
  letter-spacing:-.01em;color:inherit;text-decoration:none;max-width:62ch}
.study .sy-t:hover{color:var(--blue)}
.study .sy-m{margin:.3rem 0 0;color:var(--soft);font-size:.88rem;max-width:70ch}
.study .sy-d{display:inline-block;margin-top:.45rem;font-size:.78rem;
  font-variant-numeric:tabular-nums;color:var(--blue);word-break:break-all}

/* ---------- the certificates ----------
   A card per document, lit from under the pointer. The same light as the
   header's lamp, at the scale of a card: a spotlight that follows rather
   than a state that switches, so a grid of eight reads as one surface being
   moved over rather than eight things blinking on and off. */
.certs{display:grid;gap:1rem;grid-template-columns:repeat(var(--c),minmax(0,1fr))}
@media(max-width:1080px){.certs{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:560px){.certs{grid-template-columns:1fr}}

.cert{position:relative;isolation:isolate;overflow:hidden;display:flex;
  flex-direction:column;gap:.3rem;min-height:11.5rem;
  padding:1.15rem 1.15rem 1.05rem;text-decoration:none;color:inherit;
  background:var(--panel);border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  transition:border-color var(--dur-1),box-shadow var(--dur-2) var(--ease)}
.cert:hover,.cert:focus-visible{border-color:var(--blue);
  box-shadow:0 10px 26px -18px rgba(10,36,64,.45)}

/* The spotlight itself. Its position is two custom properties the script
   writes on the card; absent the script it simply never turns on. */
.cert .spot{position:absolute;inset:0;z-index:-1;opacity:0;pointer-events:none;
  background:radial-gradient(190px circle at var(--mx,50%) var(--my,50%),
    rgba(214,234,255,.85) 0%,rgba(220,237,255,.42) 38%,rgba(224,238,255,0) 72%);
  transition:opacity .35s var(--ease-out)}
.cert:hover .spot,.cert:focus-visible .spot{opacity:1}

.cert .cw{font-family:var(--d);font-size:.68rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.cert .ct{font-family:var(--d);font-weight:600;font-size:.98rem;line-height:1.25;
  letter-spacing:-.01em}
.cert .cv{font-size:.82rem;color:var(--soft);margin-top:.15rem}
.cert .cf{margin-top:auto;padding-top:.8rem;font-family:var(--d);font-size:.68rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--blue)}

@media (hover:none),(pointer:coarse){.cert .spot{display:none}}

/* A photograph in the body of a page. Full measure, the mark's corner, and
   its own aspect — nothing is cropped to a shape the page prefers. */
/* The photograph shares the measure of the prose beside it — at full wrap
   width it ran 360px wider than the paragraph under it, and two different
   left-to-right edges in one section read as two different pages. And it
   carries the space beneath it: .prose has no top margin, so the text was
   landing against the picture. */
.photo{margin:0 0 1.7rem;max-width:62ch}
.photo img{display:block;width:100%;height:auto;
  border-radius:0 var(--card-r) 0 var(--card-r)}

/* ---------- what the product is, in one line ----------
   Every product carries a descriptor -- "Synthetic Antimicrobial Matrix" --
   and until now it was passed as the band's eyebrow, which stopped being
   drawn when the uppercase captions came off the site. So it was on none of
   the eight pages, though the client's own page prints it under the mark.
   It sits under the heading here, in sentence case: a descriptor, not the
   caption that was removed. */
.hero .hsub{font-family:var(--d);font-size:clamp(.94rem,1.5vw,1.06rem);
  font-weight:500;color:var(--soft);margin:.5rem 0 0;letter-spacing:.004em}
.hero.mid .hsub{margin-left:0;margin-right:0}

/* ---------- a brand's own wordmark in a heading ----------
   Set by the height of the type around it, not by a pixel width, so it holds
   its place as the heading scales. The client's file is the full lockup --
   the mark over a line of white subtitle that only exists on a dark ground --
   and only the mark is used here; the line under it is typeset, where it can
   be read and searched. */
/* Measured, not guessed. The mark is 76.4% cap and 23.6% descender, and the
   Display face sets a cap of .715em, so .936em of mark puts the two caps at
   one height. An inline-block sits on the text baseline by its bottom edge,
   which here is the tail of the y, so it is pushed back down by its own
   descender: .236 x .936. */
/* Every brand mark is set by its own cap height, not by a guessed pixel
   size, so the word inside it is the size of the type it stands in for on
   every page that uses one. The height and the baseline offset are worked
   out per file from where its baseline actually falls -- .764 of the
   Microlyte mark, .570 of the PainGuard lockup, .940 of the APIS wordmark --
   and arrive as --wm-h and --wm-top. An inline-block sits on the text
   baseline by its bottom edge, so it is pushed back down by its own
   descender. */
.hero h1 .wordmark{display:inline-block;width:auto;height:var(--wm-h,.936em);
  vertical-align:baseline;position:relative;top:var(--wm-top,.221em);
  margin-right:.16em}
/* A mark that carries the whole name has no type beside it to share a
   baseline with, so it is a block of its own. */
.hero h1 .wordmark.full{display:block;margin:0;position:static;max-width:100%}

/* ---------- film of the product in use ----------
   Two clips at one size. The client's page gives them different boxes and
   crops the second one square, which loses the edge of the dressing -- the
   thing the clip is of. */
.demoblk{display:grid;gap:clamp(1.3rem,2.8vw,2rem)}
.clips{display:grid;grid-template-columns:repeat(var(--c,2),minmax(0,1fr));
  gap:clamp(.9rem,2vw,1.4rem)}
@media(max-width:720px){.clips{grid-template-columns:1fr}}
.clip{margin:0;position:relative;aspect-ratio:16/9;overflow:hidden;
  background:var(--ink);border-radius:0 var(--card-r) 0 var(--card-r);
  box-shadow:0 18px 40px -30px rgba(10,36,64,.5)}
/* out of the flow, or the video's own intrinsic height becomes the box's
   automatic minimum and the aspect-ratio above is quietly ignored */
.clip video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  display:block}
/* The client's own overlay, over the film it is made for. It is square and
   the badge is in its bottom corner, so a cover crop is anchored to the
   bottom: on the stacked 16:9 box that is the difference between showing the
   product's name and cropping it off. */
.clip .ovl{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 100%;display:block;pointer-events:none}
.demotxt{display:grid;gap:1.2rem;justify-items:center;text-align:center;
  max-width:54ch;margin:0 auto}
.demotxt p{margin:0;color:var(--soft);font-size:1rem;line-height:1.6}

/* An icon card that ends on a phrase rather than an arrow. It is not a
   button -- the whole card is the link, and a button inside a link is not a
   thing -- so it is set as one: the underline draws in on hover, the way the
   text links elsewhere do. */
.iccard.said{align-content:start}
.icgo{font-family:var(--d);font-size:.82rem;font-weight:500;color:var(--blue);
  margin-top:.9rem;display:inline-flex;align-items:center;gap:.4rem}
.icgo::after{content:"\2192";transition:transform .25s var(--ease)}
.iccard.said:hover .icgo::after{transform:translateX(4px)}

/* ---------- the rest of a brand ----------
   A row per sibling: its photograph, its name, the client's own sub-line,
   and the code. Wide enough for two on a page and one on a phone, so the
   photographs stay big enough to tell a single-layer membrane from a triple. */
.famly{list-style:none;margin:0;padding:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,23rem),1fr));
  gap:clamp(.7rem,1.6vw,1.1rem)}
.fam{display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center;gap:clamp(.9rem,2vw,1.3rem);
  padding:clamp(.7rem,1.4vw,.9rem);text-decoration:none;color:inherit;
  background:var(--panel);border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  transition:border-color var(--dur-1),transform var(--dur-2) var(--ease),
             box-shadow var(--dur-2) var(--ease)}
.fam:hover,.fam:focus-visible{border-color:var(--blue);transform:translateY(-2px);
  box-shadow:0 8px 22px -14px rgba(13,78,159,.45)}
section.band.alt .fam{background:var(--paper)}
.fam-i{display:block;width:clamp(5rem,9vw,6.5rem);aspect-ratio:4/3;overflow:hidden;
  border-radius:0 calc(var(--card-r) * .6) 0 calc(var(--card-r) * .6);
  background:var(--paper);position:relative}
.fam-i img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.fam-b{display:grid;gap:.18rem;min-width:0}
.fam-t{font-family:var(--d);font-size:1rem;font-weight:500;color:var(--ink);
  transition:color var(--dur-1)}
.fam:hover .fam-t{color:var(--blue)}
.fam-d{font-size:.84rem;line-height:1.4;color:var(--soft)}
.fam-c{justify-self:start;margin-top:.3rem;font-family:var(--d);font-size:.68rem;
  letter-spacing:.1em;color:var(--blue);border:1px solid var(--rule);
  padding:.16rem .45rem;font-variant-numeric:tabular-nums}
.fam-a{color:var(--orange);opacity:0;align-self:center;
  transition:opacity var(--dur-1),transform var(--dur-2) var(--ease)}
.fam:hover .fam-a,.fam:focus-visible .fam-a{opacity:1;transform:translateX(3px)}

/* ---------- the journey, one step at a time ----------
   Eight steps in a four-column grid and the open one below. A real tablist: arrow
   keys move between the steps, and each panel is named by its tab. */
.jrny{display:grid;gap:clamp(1.4rem,3vw,2.2rem)}
.jtabs{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(.5rem,1.2vw,.9rem)}
@media(max-width:900px){.jtabs{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:520px){.jtabs{grid-template-columns:1fr}}
.jtab{display:grid;gap:.3rem;justify-items:start;text-align:left;cursor:pointer;
  padding:clamp(.9rem,1.8vw,1.25rem);background:var(--panel);
  border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  transition:border-color .2s ease,background .2s ease}
.jtab .ic{width:24px;height:24px;color:var(--blue);transition:color .2s ease}
.jtab .jn{font-family:var(--d);font-size:.68rem;letter-spacing:.12em;
  color:var(--faint);font-variant-numeric:tabular-nums}
.jtab .jt{font-family:var(--d);font-size:1.02rem;font-weight:500;color:var(--ink)}
.jtab .js{font-size:.85rem;line-height:1.4;color:var(--soft)}
.jtab:hover{border-color:var(--soft)}
.jtab:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.jtab.on{background:var(--ink);border-color:var(--ink)}
.jtab.on .jn{color:rgba(255,255,255,.5)}
.jtab.on .jt{color:#fff}
.jtab.on .js{color:rgba(255,255,255,.74)}
.jtab.on .ic{color:var(--orange)}

/* display:grid on a class beats the user agent's [hidden]{display:none},
   so the closed panels stayed on the page. The override has to be said
   here, in the same specificity, or hiding one does nothing. */
.jpanel{display:grid;gap:1.1rem}
.jpanel[hidden]{display:none}
.jlead{font-size:clamp(1.05rem,1.7vw,1.22rem);line-height:1.5;margin:0;max-width:58ch}
.jextra{margin:0;color:var(--soft);max-width:62ch}
.jlist{list-style:none;margin:0;padding:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr));
  gap:0 clamp(1.2rem,3vw,2.4rem);border-top:1px solid var(--rule)}
.jlist li{display:grid;gap:.15rem;padding:.85rem 0;
  border-bottom:1px solid var(--rule2)}
.jpn{font-family:var(--d);font-size:.98rem;font-weight:500;color:var(--ink);
  transition:color .2s ease}
.jlist a{display:inline-flex;align-items:baseline;gap:.4rem;text-decoration:none}
.jlist a .jarr{color:var(--orange);transition:transform .25s var(--ease)}
.jlist a:hover .jpn{color:var(--blue)}
.jlist a:hover .jarr{transform:translateX(3px)}
.jd{font-size:.88rem;line-height:1.45;color:var(--soft)}
/* Quiet: it is a note about this site, not a claim about the product. */
/* The name and the tag are one line: the list item is a grid, so without a
   wrapper the tag becomes a row of its own and stretches the width of the
   column. */
/* A label over a list or a grid, not a footnote under one. It was .82rem
   against a .95rem list, which read as small print introducing the thing it
   is the heading of. */
.ticklab{font-family:var(--d);font-size:1.1rem;font-weight:500;color:var(--ink);
  letter-spacing:-.012em;margin:0 0 .95rem}

.jhead{display:inline-flex;align-items:baseline;gap:.5rem;justify-self:start}
.jsoon{font-family:var(--d);font-size:.62rem;letter-spacing:.11em;
  text-transform:uppercase;color:var(--faint);
  border:1px solid var(--rule);padding:.14rem .42rem;
  white-space:nowrap;line-height:1.3}
.toolbox-coming{margin-top:clamp(2rem,5vw,3.5rem)}
/* the sub-section the client marks as highlighted inside Control */
.jhi{background:var(--paper);border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  padding:clamp(1.1rem,2.4vw,1.6rem);display:grid;gap:.6rem;max-width:64ch}
.jhi h3,.jhi h4{margin:0;font-size:1.05rem;font-weight:500}
.jhi p{margin:0;color:var(--soft);font-size:.94rem;line-height:1.6}
.jhi .jhik{color:var(--ink)}
/* no script: every panel shows, which is the same content in a plainer
   order, with its own heading rule instead of a tab */
.jrny:not([data-ready]) .jpanel[hidden]{display:grid}
.jrny[data-ready] .jpanel[hidden]{display:none}
.jrny:not([data-ready]) .jtabs{display:none}
.jrny:not([data-ready]) .jpanel{padding-top:1.4rem;border-top:1px solid var(--rule)}

/* The advantages with the loop beside them. The clip takes the height of the
   list rather than its own 16:9: four sentences run to about 540px and a
   landscape rectangle centred against them floated in the middle of its
   column with a hundred-odd pixels of nothing above and below. Stretched, it
   is a panel the same height as the thing it sits next to, and the crop
   costs nothing — the sheet is in the middle of the frame.
   Below the breakpoint it stacks and goes back to 16:9, where it is the full
   width of the page and there is no column height to match. */
.advwrap{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:clamp(1.4rem,3.4vw,2.6rem);align-items:stretch}
.advwrap .clip{aspect-ratio:auto;min-height:clamp(15rem,26vw,22rem)}
@media(max-width:860px){
  .advwrap{grid-template-columns:1fr}
  .advwrap .clip{aspect-ratio:16/9;min-height:0}
}

/* ---------- the photographs, one at a time ----------
   The slide in the middle is the one being read and the next two sit half
   off either edge, so the row says there is more without a dot to count.
   It is a list of <li> and a pair of buttons: with no script it is a row of
   photographs that scrolls, which is a worse carousel and a working page. */
.carou{--slide:min(620px,72vw);--peek:clamp(.6rem,2vw,1.3rem)}
.carou-vp{overflow:hidden}
.carou-track{list-style:none;margin:0;padding:0;display:flex;
  gap:var(--peek);
  transform:translate3d(var(--x,0px),0,0);
  transition:transform .62s cubic-bezier(.22,.61,.36,1);
  will-change:transform}
.slide{flex:0 0 var(--slide);margin:0;position:relative;aspect-ratio:3/2;
  overflow:hidden;background:var(--panel);
  border-radius:0 var(--card-r) 0 var(--card-r);
  box-shadow:0 22px 50px -34px rgba(10,36,64,.55);
  opacity:.5;transform:scale(.955);
  transition:opacity .62s ease,transform .62s cubic-bezier(.22,.61,.36,1)}
.slide.on{opacity:1;transform:none}
.slide img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  display:block}
.carou-nav{display:flex;gap:.7rem;justify-content:center;margin:1.4rem 0 0}
.cbtn{width:2.9rem;height:2.9rem;border-radius:50%;display:grid;place-items:center;
  background:var(--panel);color:var(--ink);cursor:pointer;font-size:1.05rem;
  border:1px solid color-mix(in srgb,var(--rule) 62%,var(--soft));
  transition:background .18s ease,color .18s ease,border-color .18s ease}
.cbtn:hover{background:var(--ink);color:#fff;border-color:var(--ink)}
.cbtn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.cbtn[disabled]{opacity:.34;cursor:default}
.cbtn[disabled]:hover{background:var(--panel);color:var(--ink);
  border-color:color-mix(in srgb,var(--rule) 62%,var(--soft))}
/* no script, no transform: let the row scroll instead of hiding two thirds
   of the photographs behind buttons that do nothing */
.carou:not([data-ready]) .carou-vp{overflow-x:auto;scroll-snap-type:x mandatory}
.carou:not([data-ready]) .slide{opacity:1;transform:none;scroll-snap-align:center}
.carou:not([data-ready]) .carou-nav{display:none}

/* ---------- what people say about working here ----------
   The photograph is the top of the card and dissolves into it: the plate is
   full-bleed and a gradient of the card's own colour is laid over its foot,
   so there is no edge between the face and the words. The quote mark sits
   where that dissolve ends, and the attribution is ranged right at the
   bottom, which is where a reader looks for it after the words rather than
   before them.

   Two columns, because these run to a paragraph each. At four across the
   text would set to twelve characters a line. */
.voices{display:grid;gap:1.1rem;grid-template-columns:repeat(var(--c),minmax(0,1fr))}
@media(max-width:860px){.voices{grid-template-columns:1fr}}
.voice{margin:0;background:var(--panel);border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);overflow:hidden;
  display:flex;flex-direction:column;
  transition:transform var(--dur-3) var(--ease-out),
    box-shadow var(--dur-3) var(--ease-out),border-color var(--dur-2)}

/* Arrival. The four come up in turn as they are reached rather than all at
   once on load, because on a page this long they are two screens below the
   fold and a load animation would have finished before anyone saw it.

   The resting state is set by the script, not the stylesheet: with no
   script, or before it runs, four testimonials are simply on the page. A
   quote that needs JavaScript to become visible is a quote that is
   sometimes not there. */
[data-reveal] .voice{opacity:0;transform:translateY(18px)}
[data-reveal] .voice.in{opacity:1;transform:none;
  transition:opacity .5s var(--ease-out) var(--d,0ms),
    transform .62s var(--ease-out) var(--d,0ms)}

/* The response to a pointer is the photograph coming forward a little, and
   the card with it. Slow, and slower on the way in than the way out: a
   portrait that snaps is a portrait being operated. */
.voice .vimg img{transition:transform .9s var(--ease-out)}
@media (hover:hover) and (pointer:fine){
  .voice:hover{transform:translateY(-3px);border-color:var(--rule);
    box-shadow:0 18px 38px -26px rgba(10,36,64,.5)}
  .voice:hover .vimg img{transform:scale(1.045)}
  [data-reveal] .voice.in:hover{transform:translateY(-3px)}
}
@media (prefers-reduced-motion:reduce){
  .voice .vimg img{transition:none}
  .voice:hover .vimg img{transform:none}
}
/* 4/3 rather than 12/11. A plate almost as tall as it is wide made a card
   860px high for four lines of quotation: the photograph was the block and
   the words were underneath it. */
.voice .vimg{position:relative;aspect-ratio:4/3;background:var(--rule2);
  display:grid;place-items:center;overflow:hidden;min-height:0}
/* The photograph is taken out of the flow. In it, its own height is the
   box's automatic minimum, so aspect-ratio can set a shorter plate and get
   overruled by the picture in it without a word — which is why 4/3 was
   still drawing 12/11. */
.voice .vimg img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:50% 30%;display:block}
/* No dissolve. The photograph ends where it ends — a plate with an edge,
   which is what a printed card does — and the movement that was being asked
   of the gradient is done by movement instead. */

.voice .vini{font-family:var(--d);font-weight:600;font-size:2.4rem;color:var(--blue)}

/* The quote sat 32px up inside the plate, which was right while the foot of
   the photograph dissolved into the card and became an overlap the moment it
   stopped. It starts below the picture now, with room of its own. */
.voice blockquote{margin:0;padding:clamp(1.1rem,2.4vw,1.4rem)
  clamp(1.2rem,2.6vw,1.5rem) 0;position:relative}
.voice .vq{display:block;font-family:var(--d);font-weight:700;font-size:2.4rem;
  line-height:.6;color:var(--ink);margin-bottom:.55rem}
.voice blockquote p{margin:0;font-family:var(--d);font-weight:600;font-size:.97rem;
  line-height:1.45;letter-spacing:-.01em}
.voice figcaption{margin-top:auto;padding:1rem clamp(1.2rem,2.6vw,1.5rem)
  clamp(1.1rem,2.4vw,1.35rem);text-align:right;color:var(--soft);font-size:.85rem}

/* Folded quotes. The clamp is applied by script and only to a quote that
   actually overflows it, so nothing is hidden behind a control that is not
   there: with no script every word is on the page, which is the state a
   testimonial has to survive in. */
.voice blockquote.fold p{display:-webkit-box;-webkit-box-orient:vertical;
  -webkit-line-clamp:6;overflow:hidden}
.voice blockquote.fold.open p{display:block;-webkit-line-clamp:none;overflow:visible}
.vmore{margin:.6rem 0 0;padding:0;background:none;border:0;cursor:pointer;
  font:inherit;font-family:var(--d);font-size:.8rem;font-weight:600;
  color:var(--blue)}
.vmore:hover{text-decoration:underline}
.vmore:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* A field that would otherwise end the form alone on its own row takes the
   whole width instead: a half-width box with nothing beside it reads as a
   column that failed to fill rather than as the last question. */
.fld.wide{grid-column:1/-1}
.bandhead h2,.hero h1{letter-spacing:-.014em}
h2{font-size:clamp(1.72rem,3.5vw,2.5rem);font-weight:400;line-height:1.1;margin:0}
h2 b,h1 b{font-weight:700}
h3{font-size:1.08rem;font-weight:600;margin:0}
.lead{color:var(--soft);font-size:1.12rem;max-width:58ch;margin:1rem 0 0}
.prose{max-width:62ch;color:var(--soft)}
.prose p{margin:0 0 1rem}
/* Two paragraphs that are a pair read as one across the page rather than as
   a narrow column with half the width empty beside it. Each keeps its own
   measure; only the stack becomes a row. */
.prose.pair{max-width:none;display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:0 clamp(1.6rem,4vw,3.4rem)}
.prose.pair p{margin:0;max-width:46ch}
@media(max-width:760px){
  .prose.pair{grid-template-columns:1fr;gap:0}
  .prose.pair p{margin:0 0 1rem}
}

/* hero */
/* The header stands on the page's own tint, not on a white sheet of its own.
   White is left to the things that are objects — cards, panels, the form —
   so the top of a page is one continuous ground from the floating island
   down to the first band, with nothing to seam. */
.hero{padding:clamp(2.6rem,6vw,4.6rem) 0 clamp(2.4rem,5vw,4rem);background:var(--paper);
  border-bottom:1px solid var(--rule)}
.hero-in{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:clamp(1.5rem,4vw,3.5rem);
  align-items:center}
.hero h1{font-size:clamp(2.35rem,5.8vw,4rem);font-weight:400;line-height:1.02;margin:0;
  max-width:19ch;text-wrap:balance}
.hero .lead{font-size:1.1rem;max-width:52ch}
.hero-art{aspect-ratio:4/3;background:
  linear-gradient(135deg,var(--blue-bg),var(--panel) 60%),var(--paper);
  border:1px solid var(--rule);display:grid;place-items:center;position:relative}
/* The dashed rule marks the bottom of an empty placeholder frame. A frame
   holding a real photograph, a diagram or a drawing is not empty, so it does
   not get one. `.art` -- the drawn heroes from heroart.py -- was missing
   from this list: heroart.py cancelled the rule with `.hero-art.art::after
   {content:none}`, two classes against this selector's three, so the
   placeholder's dashes were ruled under the carton on Products whatever
   order the two rules landed in. The condition belongs here, once. */
.hero-art:not(.has-img):not(.has-dia):not(.art)::after{content:"";position:absolute;
  inset:auto 0 0 0;height:3px;
  background:repeating-linear-gradient(90deg,var(--orange) 0 14px,transparent 14px 28px)}
.hero-art span{font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint);text-align:center;padding:0 1.5rem}
@media(max-width:860px){
  .hero-in{grid-template-columns:1fr}
  .hero-art{order:-1;aspect-ratio:16/9}
  /* A drawing is not a photograph in either respect. Its own shape has to
     survive -- a forced 16/9 frame under an auto-height image leaves the
     drawing hanging out of its box -- and it does not go first: a
     photograph read at a glance earns the top of a phone screen, twelve
     labels at six pixels do not, so the headline keeps it. */
  .hero-art.has-dia{order:0;aspect-ratio:auto}
  /* Stacked, a portrait at full width would fill the screen before a word
     of the page showed, so here it does crop — aimed at the upper third,
     where a person in a photograph generally is. */
  .hero-art.has-img{aspect-ratio:16/10}
  .hero-art.has-img img{object-position:50% 32%}
}

/* buttons */
/* The button takes the link's own corner treatment: rounded at top-right and
   bottom-left, square at the other two. Measured off the mark rather than
   guessed — the radius there is 35% of the shape's height, so it is set from
   the button's own height and stays in proportion at any size.

   The value is in em, not a fraction of the box: border-radius percentages
   resolve against width and height separately and would give an ellipse. A
   .btn stands 3.84em tall — .72rem of padding above and below its .7rem
   text — so 35% of that is 1.34em, and any control sharing the token keeps
   the same corner. */
:root{--btn-r:1.34em; --card-r:1.6rem}

/* The card takes the same corner, but not the same 35%. That fraction was
   read off a shape 51 by 35 units; a card stands 159px tall, and 35% of that
   is a 56px scoop that would eat the description sitting in the bottom-left
   corner. A shape family holds at different scales through a corner of
   similar weight, not a corner of identical proportion, so the card's is
   fixed at 1.6rem — large enough to read as the mark's corner, small enough
   to clear the text by the card's own padding. */
.btn{display:inline-block;position:relative;isolation:isolate;overflow:hidden;
  border-radius:0 var(--btn-r) 0 var(--btn-r);
  margin-top:1.5rem;border:1px solid var(--blue);color:var(--blue);
  background:none;padding:.72rem 1.15rem;font-family:var(--d);font-size:.7rem;
  letter-spacing:.13em;text-transform:uppercase;cursor:pointer;
  transition:color var(--dur-2) var(--ease-out)}
/* A button that stands on its own in a band has a top margin and nothing
   below it -- right when it ends the band, wrong when something follows. The
   product grid under "Explore Featured Technologies" was touching it, 0px,
   while the drawn figures in the blocks either side kept their distance
   because a figure brings its own margin.
   The space goes on the grid rather than under the button: .btn is
   inline-block, so its margins never collapse with a sibling's, and a
   bottom margin on it simply added to the figures' own and double-spaced
   the two blocks that were already right. */
.wrap > .btn + .pgrid{margin-top:2.4rem}
.btn::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--blue);
  transform:scaleX(0);transform-origin:left center;
  transition:transform var(--dur-2) var(--ease)}
.btn:hover::before,.btn:focus-visible::before{transform:scaleX(1)}
.btn:hover,.btn:focus-visible{color:#fff}
.btn.light{border-color:#fff;color:#fff;margin:0;flex:none}
.btn.light::before{background:#fff}
.btn.light:hover,.btn.light:focus-visible{color:var(--blue)}

/* grids and cards */
.grid{display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));gap:1rem}
@media(max-width:980px){.grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:620px){.grid{grid-template-columns:1fr}}
.card{display:block;border:1px solid var(--rule);background:var(--paper);padding:1.15rem;
  position:relative;transition:border-color .2s,transform .25s var(--ease)}
section.band.alt .card{background:var(--paper)}
a.card:hover{border-color:var(--blue);transform:translateY(-2px)}
/* The link out of the EmeraNova mark. The logo draws three of them
   interlocking: a square with two opposite corners rounded and the other two
   left square. It stands in for the orange dash that used to sit above a
   card and in front of a list item -- the same accent, in a shape the brand
   already owns rather than a plain rule. The radius is measured off the
   artwork: the link there is 206x143 with a 48 corner, so the curve is a
   third of its short side, and a square bullet keeps that third. A
   quarter, which is what it measures against the long side, reads as a
   plain square once the shape is nine pixels wide. */
.mk{--mk:11px;display:block;width:var(--mk);height:var(--mk);background:var(--orange);
  border-radius:0 34% 0 34%}
.card .cart{--mk:11px;display:block;width:var(--mk);height:var(--mk);
  background:var(--orange);border-radius:0 34% 0 34%;margin-bottom:.9rem}
.card .ct{display:block;font-family:var(--d);font-weight:600;font-size:.98rem;margin-bottom:.3rem}
.card .cd{display:block;font-size:.86rem;color:var(--soft);line-height:1.5}
.card .carr{position:absolute;right:1.1rem;bottom:1rem;color:var(--blue);opacity:0;
  transition:opacity .2s,transform .2s}
a.card:hover .carr{opacity:1;transform:translateX(3px)}

/* listing rows */
.listing{border-top:1px solid var(--rule)}
.lrow{display:grid;grid-template-columns:minmax(0,15rem) 1fr auto;gap:1.2rem;align-items:baseline;
  padding:1rem .2rem;border-bottom:1px solid var(--rule2);transition:background .2s}
.lrow:hover{background:var(--panel)}
.lrow .lt{font-family:var(--d);font-weight:600;font-size:.96rem}
.lrow .ld{font-size:.85rem;color:var(--soft)}
.lrow .larr{color:var(--blue);opacity:0;transition:opacity .2s}
.lrow:hover .larr{opacity:1}
@media(max-width:720px){.lrow{grid-template-columns:1fr auto}.lrow .ld{grid-column:1/-1}}

/* the continuum */
.continuum{display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));gap:.4rem}
.cstep{display:block;border:1px solid var(--rule);background:var(--paper);padding:.85rem .7rem;
  transition:border-color .2s,background .2s}
section.band.alt .cstep{background:var(--paper)}
.cstep:hover{border-color:var(--blue)}
.cstep.on{border-color:var(--orange);background:var(--orange-bg)}
.cstep .cn{display:block;font-family:var(--d);font-size:.62rem;letter-spacing:.1em;
  color:var(--faint);font-variant-numeric:tabular-nums}
.cstep.on .cn{color:var(--orange-ink)}
.cstep .cl{display:block;font-family:var(--d);font-weight:600;font-size:.85rem;margin-top:.25rem}
.cstep .cs{display:block;font-size:.76rem;color:var(--soft);margin-top:.25rem;line-height:1.35}
@media(max-width:900px){.continuum{grid-template-columns:repeat(3,1fr)}}
@media(max-width:560px){.continuum{grid-template-columns:repeat(2,1fr)}}

/* split with ticks */
.splitblk{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(1.4rem,4vw,3rem);
  align-items:start}
.splitblk.mid{align-items:center}
/* Unless a heading is sitting directly on top of it. Centring a short column
   of text against a tall figure pushes the text down -- 98px on the Patients
   diagram -- and the heading does not go with it, so "Seeing the whole
   picture" was left stranded 136px above the paragraph it introduces, where
   every other heading on the site clears its text by 38. A block with no
   heading over it has nothing to strand and keeps the centring. */
.bandhead + .splitblk.mid{align-items:start}
/* Whatever starts a column starts it, with no margin above to push it off
   the top edge it is meant to sit on. */
.splitblk > div > :first-child{margin-top:0}
/* A heading with text above it needs the room a heading needs. This one had
   none at all: a 42px line sat flush against the 17px paragraph before it,
   which is the one place in the block the spacing was not a judgement but an
   omission. The figure is the band heading's own rhythm, 37px, so the column
   reads at the same pace as the page it is on. */
.splitblk h2:not(:first-child){margin-top:2.2rem}
/* A heading that opens the column is that section's heading and is set like
   one -- same size and the same 2.2rem under it that .bandhead gives. It sits
   inside the column so that it travels with its own text when the two columns
   are centred against a figure taller than either. */
.splitblk > div > h2:first-child{font-size:clamp(1.9rem,3.3vw,2.6rem);
  line-height:1.1;letter-spacing:-.014em;margin:0 0 2.2rem;max-width:20ch}
.splitblk.person > div > h2:first-child{font-size:clamp(1.35rem,2.3vw,1.72rem);
  line-height:1.25;margin-bottom:1rem}
/* Except where the section already has a heading of its own directly above.
   Then the one in the column is a sub-heading under it -- "For press" beneath
   "Media enquiries" -- and setting two headings the same size in a row says
   they rank the same, which they do not. Three sections read this way. */
.bandhead + .splitblk > div > h2:first-child{
  font-size:clamp(1.72rem,3.5vw,2.5rem);margin-bottom:1rem;max-width:none}
@media(max-width:860px){.splitblk{grid-template-columns:1fr}}
/* 1rem, which is the 17px the prose blocks set between paragraphs -- the
   .9 here was two pixels tighter for no reason anyone would notice except
   by measuring the two side by side, which is how it was found. */
.splitblk p{color:var(--soft);margin:1rem 0 0;max-width:52ch}
.ticks{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.ticks li{padding:.85rem 0 .85rem 1.6rem;border-bottom:1px solid var(--rule2);position:relative;
  font-size:.92rem;color:var(--soft)}
.ticks li::before{content:"";position:absolute;left:0;top:1.02rem;width:9px;height:9px;
  border-radius:0 34% 0 34%;background:var(--orange)}

/* steps */
.steps{list-style:none;margin:0;padding:0;display:grid;gap:0;border-top:1px solid var(--rule)}
.steps li{display:grid;grid-template-columns:auto 1fr;gap:1.2rem;padding:1.3rem 0;
  border-bottom:1px solid var(--rule2)}
.steps .sn{font-family:var(--d);font-size:.72rem;color:var(--orange-ink);
  font-variant-numeric:tabular-nums;letter-spacing:.08em}
.steps p{color:var(--soft);font-size:.92rem;margin:.3rem 0 0;max-width:64ch}

/* A step that goes somewhere. The whole row is the target, so the number and
   the icon are part of the hit area rather than decoration beside it. */
.steps.linked li{padding:0}
.steps .steprow{display:grid;grid-template-columns:auto auto 1fr auto;gap:1.2rem;
  align-items:start;padding:1.3rem .2rem;text-decoration:none;color:inherit;
  transition:background var(--dur-2) var(--ease)}
.steps .steprow .ic{width:26px;height:26px;color:var(--blue);margin-top:-.15rem;
  transition:transform var(--dur-2) var(--ease)}
.steps .steprow .sarr{color:var(--blue);opacity:0;align-self:center;
  transition:opacity var(--dur-1),transform var(--dur-2) var(--ease)}
.steps .steprow:hover,.steps .steprow:focus-visible{background:var(--panel)}
.steps .steprow:hover .sarr,.steps .steprow:focus-visible .sarr{opacity:1;transform:translateX(3px)}
.steps .steprow:hover .ic{transform:translateY(-2px)}
.steps .steprow:hover h3{color:var(--blue)}
@media(max-width:600px){
  .steps .steprow{grid-template-columns:auto 1fr;gap:.5rem 1rem}
  .steps .steprow .ic{grid-column:1;grid-row:2}
  .steps .steprow>div{grid-column:2;grid-row:2}
  .steps .steprow .sarr{display:none}
}

/* ===================== partner marquee =====================
   Four logos is not enough to fill a wide viewport, so the run is printed
   twice and the track slides by exactly one run. The spacing lives in
   margin-right on every item — including the last — rather than in flex gap:
   with gap, the space between the two copies is not counted the same way as
   the spaces inside them, the travel no longer equals one run, and the seam
   shows up as a jump once a loop.

   The logos are four different companies' brand colours next to a palette of
   one blue and one orange, so they are muted at rest to keep the band quiet.
   The two halves of the interaction are deliberately at different scopes:
   entering the strip stops the travel, and colour then comes back one logo at
   a time. That order is what makes it usable — on a row still moving, a single
   logo is a target that slides out from under the cursor, so the pause has to
   be the wider gesture and the colour the narrow one.

   The padding on each item is the hit area. Without it the target is the
   artwork's own bounds, which for a wordmark is a few pixels tall. */
.pmq{padding:.4rem 0 .2rem}
.pmq-t{font-family:var(--t);font-size:.94rem;color:var(--faint);
  text-align:center;margin:0 0 1.7rem}
.pmq-vp{overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent)}
.pmq-track{display:flex;align-items:center;list-style:none;margin:0;padding:0;
  width:max-content;animation:pmq-run 38s linear infinite}
.pmq-track li{margin-right:clamp(1.8rem,6vw,4.6rem);flex:none;
  padding:.55rem .8rem}
.pmq-track img{display:block;max-height:38px;max-width:172px;width:auto;height:auto;
  object-fit:contain;filter:grayscale(1);opacity:.5;
  transition:filter var(--dur-2) var(--ease),opacity var(--dur-2) var(--ease)}
.pmq-vp:hover .pmq-track{animation-play-state:paused}
.pmq-track li:hover img{filter:none;opacity:1}
@keyframes pmq-run{to{transform:translateX(-50%)}}

@media(max-width:860px){.pmq-track img{max-height:29px;max-width:132px}}

/* Standing still, one run is enough and the second is dead weight in the
   layout, so it goes; the row centres and wraps instead of running off. */
@media(prefers-reduced-motion:reduce){
  .pmq-track{animation:none;width:100%;flex-wrap:wrap;justify-content:center;
    row-gap:1.6rem}
  .pmq-track li[aria-hidden]{display:none}
  .pmq-track img{filter:none;opacity:.72}
}

/* icon-led cards, the portfolio variant: boxed and clickable */
.icgrid{display:grid;gap:1rem;grid-template-columns:repeat(var(--c),minmax(0,1fr))}
@media(max-width:980px){.icgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:560px){.icgrid{grid-template-columns:1fr}}
.iccard{display:block;position:relative;border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  background:var(--panel);padding:1.25rem 1.15rem 1.35rem;text-decoration:none;
  color:inherit;transition:border-color var(--dur-1),transform var(--dur-2) var(--ease),
  box-shadow var(--dur-2) var(--ease)}
a.iccard:hover,a.iccard:focus-visible{border-color:var(--blue);transform:translateY(-2px);
  box-shadow:0 6px 18px -10px rgba(13,78,159,.42)}
/* One box for both kinds of glyph. A drawn icon is square and a supplied one
   is whatever shape the client sent -- 113x160 for one of the careers icons
   and 160x141 for another -- so the height is what they share and the width
   follows. They were 28px and 34px, which is why one set sat visibly bigger
   than the other. */
.iccard .icw{--ic:32px;display:block;height:var(--ic);margin-bottom:.9rem;
  color:var(--blue)}
/* the same glyph over a hero title. Orange rather than the cards' blue:
   this is the step the reader is standing on, which is how the journey tabs
   mark the open one. */
.hico{display:block;color:var(--orange);margin:0 0 .9rem}
.hico .ic{width:38px;height:38px}
@media(max-width:860px){.hico .ic{width:32px;height:32px}}
.iccard .ic{width:var(--ic);height:var(--ic)}
.iccard .icw{transition:transform var(--dur-2) var(--ease)}
.iccard:hover .icw{transform:translateY(-3px)}
.iccard .ct{display:block;font-family:var(--d);font-weight:600;font-size:.95rem;
  letter-spacing:-.01em}
.iccard .cd{display:block;color:var(--soft);font-size:.86rem;margin-top:.3rem}
.iccard .carr{position:absolute;right:1.1rem;bottom:1rem;color:var(--blue);opacity:0;
  transition:opacity var(--dur-1),transform var(--dur-2) var(--ease)}
a.iccard:hover .carr,a.iccard:focus-visible .carr{opacity:1;transform:translateX(3px)}

/* A supplied icon sits in the same box as a drawn one, at the same height,
   so a grid can hold both without one set floating above the other. */
.iccard .icf{display:block;width:auto;height:var(--ic);object-fit:contain}

/* ---------- the icons arrive ----------
   The card rises and the glyph comes up after it with a little overshoot,
   which is the whole animation: at this size anything more is fidgeting.
   The resting state is set by the script, so a page whose script never runs
   shows the icons rather than four gaps, and it is not set at all for a
   reader who has asked for less movement. */
[data-reveal] .claims li{opacity:0;transform:translateY(14px)}
[data-reveal] .claims li.in{opacity:1;transform:none;
  transition:opacity .5s var(--ease-out) var(--d,0ms),
             transform .6s var(--ease) var(--d,0ms)}
[data-reveal] .claims .ck{opacity:0;transform:scale(.72)}
[data-reveal] .claims li.in .ck{opacity:1;transform:none;
  transition:opacity .32s ease calc(var(--d,0ms) + 90ms),
             transform .52s cubic-bezier(.34,1.46,.64,1) calc(var(--d,0ms) + 90ms)}
[data-reveal] .claims li.in:hover .ck{transform:translateY(-3px)}
[data-reveal] .iccard{opacity:0;transform:translateY(14px)}
[data-reveal] .iccard.in{opacity:1;transform:none;
  transition:opacity .5s var(--ease-out) var(--d,0ms),
             transform .6s var(--ease) var(--d,0ms)}
[data-reveal] .iccard .icw{opacity:0;transform:scale(.72)}
[data-reveal] .iccard.in .icw{opacity:1;transform:none;
  transition:opacity .32s ease calc(var(--d,0ms) + 90ms),
             transform .52s cubic-bezier(.34,1.46,.64,1) calc(var(--d,0ms) + 90ms)}
[data-reveal] .iccard.in:hover .icw{transform:translateY(-3px)}

/* the plain variant: no box at all, a rule over each column. These four are
   context rather than navigation, and boxing them made them compete with the
   portfolio grid directly above. */
.icgrid.plain{gap:1.6rem clamp(1.2rem,3vw,2.4rem)}
.icgrid.plain .iccard{border:none;background:none;padding:1.1rem 0 0;
  border-top:1px solid var(--rule);border-radius:0}
.icgrid.plain .iccard .icw{color:var(--orange)}
.icgrid.plain .iccard .ct{font-size:.9rem}
/* Cards whose whole content is a sentence. A sentence set in the display
   face at 600 is a label that has outgrown itself: it reads as a heading the
   eye keeps waiting to be followed by something. In the text face at a
   normal weight it reads as what it is, four things the company says about
   itself. */
.icgrid.say .iccard .ct{font-family:var(--t);font-weight:400;font-size:1rem;
  line-height:1.45;letter-spacing:0;color:var(--ink)}

/* tables */
/* positioned, so an absolutely placed child -- the hidden header on the
   comparison table -- is contained and clipped here rather than
   escaping to the page and widening the body */
.tblwrap{overflow-x:auto;position:relative}
.tblwrap:focus-visible{outline:2px solid var(--blue);outline-offset:3px}
.tblwrap[data-scrollable="true"]::before{content:"Scroll to view →";display:none;
  color:var(--soft);font-family:var(--d);font-size:.72rem;letter-spacing:.06em;
  margin:0 0 .45rem;text-transform:uppercase}
@media(max-width:760px){.tblwrap[data-scrollable="true"]::before{display:block}}
.tbl{width:100%;border-collapse:collapse;font-size:.9rem;min-width:34rem}
.tbl th{text-align:left;font-family:var(--d);font-size:.63rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint);font-weight:600;padding:.6rem .7rem;
  border-bottom:1px solid var(--rule)}
.tbl td{padding:.7rem;border-bottom:1px solid var(--rule2);color:var(--soft)}
.tbl tr td:first-child{color:var(--ink);font-weight:500}

/* media placeholders */
.media{aspect-ratio:16/9;background:var(--paper);border:1px solid var(--rule);display:grid;
  place-items:center;margin:0 0 1rem;position:relative;
  background-image:linear-gradient(135deg,transparent 49.6%,var(--rule2) 49.6% 50.4%,transparent 50.4%),
                   linear-gradient(45deg,transparent 49.6%,var(--rule2) 49.6% 50.4%,transparent 50.4%)}
section.band.alt .media{background-color:var(--paper)}
.media.tall{aspect-ratio:2.4/1}
.media span{background:var(--paper);padding:.3rem .8rem;font-size:.72rem;
  letter-spacing:.09em;text-transform:uppercase;color:var(--faint);z-index:1}
.media .play{width:0;height:0;border-left:14px solid var(--blue);border-top:9px solid transparent;
  border-bottom:9px solid transparent;background:none;padding:0;margin-bottom:.6rem}

/* quote — the one place FreightBig Pro appears, per the brand guidelines */
/* The company's own line, not a testimonial — so it does not take FreightBig,
   which the brand guidelines reserve for patient and provider quotes. */
.statement{font-family:var(--d);font-size:clamp(1.15rem,2.6vw,1.7rem);font-weight:400;
  line-height:1.25;letter-spacing:-.01em;color:var(--ink);max-width:34ch;
  margin:clamp(2rem,4.4vw,3rem) 0 0;
  padding-top:1.1rem;border-top:2px solid var(--orange)}
/* A statement written as a turn -- one line that sets it up and one that
   answers -- is a different object from a closing paragraph, and takes the
   larger size. Keyed on the turn itself rather than on a flag, because the
   forty-one word statement on Meetings at this size and measure came out
   eight lines tall. */
.statement:has(.sl + .sl){font-size:clamp(1.3rem,3.1vw,2.1rem);line-height:1.2;
  letter-spacing:-.015em;max-width:26ch}
/* Each line of a multi-line statement is its own line, whatever the measure
   does. The second one is the half that answers the first, so it carries the
   colour. */
.statement .sl{display:block}
.statement .sl+.sl{color:var(--blue)}
/* The band built round the world map centres on it. Its head and its
   paragraphs already do -- the map is in CENTRES_OVER, which is the rule
   that hangs a centred head over a symmetrical figure -- and this is the
   line under the picture, which was the only thing in the band still ranged
   left. The orange rule centres with the words it belongs to. */
.wrap:has(> .wmap) .statement{margin-left:auto;margin-right:auto;
  text-align:center}
/* A statement that closes a two-column block sits under the second column,
   so the section finishes on the side the next band starts from instead of
   leaving the same half of the page empty twice. */
@media(min-width:761px){
  .statement.col2{margin-left:calc(50% + clamp(.8rem,2vw,1.7rem))}
}
.quote{margin:2rem 0 0;padding-left:1.3rem;border-left:2px solid var(--orange);max-width:56ch}
.quote p{font-family:var(--serif);font-size:1.35rem;
  line-height:1.35;color:var(--ink)}
.quote cite{display:block;font-style:normal;font-family:var(--d);font-size:.7rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--faint);margin-top:.8rem}

/* ---- editorial feed (News) ---- */
.filters{display:flex;gap:.4rem;flex-wrap:wrap;margin:0 0 1.6rem}
/* The editorial line that opens the feed sits above the buttons, not on top
   of them: a paragraph's bottom margin is the space between paragraphs, and
   this is the space between a sentence and a control. */
.prose + .filters{margin-top:2.2rem}
.filt{font-family:var(--d);font-size:.66rem;letter-spacing:.11em;text-transform:uppercase;
  border:1px solid var(--rule);background:none;color:var(--soft);padding:.5rem .8rem;
  cursor:pointer;transition:border-color .2s,color .2s}
.filt:hover{border-color:var(--blue);color:var(--blue);background:var(--blue-bg)}
.filt.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.filt.on:hover{background:var(--ink);color:var(--paper)}
.filt:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

.featured{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:clamp(1.2rem,3vw,2.4rem);align-items:center;border-top:1px solid var(--rule);
  padding-top:1.6rem}
@media(max-width:860px){.featured{grid-template-columns:1fr}}
.fimg{aspect-ratio:16/10;background:var(--paper);border:1px solid var(--rule);display:grid;
  place-items:center;background-image:linear-gradient(135deg,transparent 49.6%,var(--rule2) 49.6% 50.4%,transparent 50.4%),
  linear-gradient(45deg,transparent 49.6%,var(--rule2) 49.6% 50.4%,transparent 50.4%)}
.fimg span{background:var(--paper);padding:.25rem .7rem;font-size:.68rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.ftag,.atag{display:inline-block;font-family:var(--d);font-size:.58rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--orange-ink);border:1px solid var(--orange);
  padding:.12rem .4rem;margin-bottom:.7rem}
.fbody h3{font-size:clamp(1.15rem,2.4vw,1.6rem);font-weight:400;letter-spacing:-.012em;
  line-height:1.15}
.fbody p{color:var(--soft);margin:.7rem 0 0;max-width:46ch}
.fmeta,.ameta{display:block;font-family:var(--d);font-size:.66rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint);margin-top:.9rem}
/* In a grid of seventeen, fifteen of which say the same word, the bordered
   badge is noise. A kicker instead: same type, no box. */
.art .atag{border:0;padding:0;margin-bottom:0;color:var(--blue)}
.art .ameta{margin-top:0}

/* --ab is the card's own horizontal padding, and the grid is pulled out by
   exactly that much, so the first headline still starts on the same line as
   the paragraph above it while the hover ground has room to breathe either
   side of the words. The wrap's own padding is 1.1rem at its narrowest, so
   the bleed never escapes the section. In one column it widens to the wrap's
   padding and the rows go edge to edge, which is what a list of headlines on
   a phone wants anyway. */
.artgrid{--ab:1rem;display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));
  gap:1.4rem 1.1rem;margin-inline:calc(var(--ab) * -1)}
@media(max-width:980px){.artgrid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:620px){.artgrid{grid-template-columns:1fr;
  --ab:clamp(1.1rem,4vw,2.6rem)}}
/* A press release is a headline with a date on it. No plate, no frame: a
   rule across the top, the kind above it, the standfirst under it, and the
   date at the foot where the eye leaves the card. The whole card is the
   link where there is one to follow. */
.art{display:flex;flex-direction:column;position:relative;
  border-top:1px solid var(--rule);padding:1rem var(--ab) 1.1rem;
  color:inherit;text-decoration:none;transition:background .2s,border-color .2s}
/* Background and rule on hover, and nothing that moves: a card that shifts
   its text by a padding under the pointer is a card you have to chase. */
a.art:hover{background:var(--rule2);border-top-color:var(--blue)}
a.art:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.art h2,.art h3{font-size:1rem;font-weight:600;line-height:1.3;margin:.5rem 0 0;
  letter-spacing:-.008em}
a.art:hover h2,a.art:hover h3{color:var(--blue)}
.art p{font-size:.86rem;color:var(--soft);margin:.45rem 0 1rem;flex:1 1 auto}
/* The arrow is the affordance the underline used to be. It sits on the date
   line rather than after the headline, so it does not break the wrap. */
.aarr{position:absolute;right:var(--ab);bottom:1.1rem;color:var(--blue);
  opacity:0;transform:translateX(-4px);transition:opacity .2s,transform .2s}
a.art:hover .aarr,a.art:focus-visible .aarr{opacity:1;transform:none}
/* Filtered out. .art sets display:flex, which a bare [hidden] cannot beat. */
.art[hidden]{display:none}

.pager{display:flex;align-items:center;gap:.35rem;margin-top:2.2rem;font-family:var(--d);
  font-size:.72rem}
.pcur,.pnum{display:grid;place-items:center;width:2rem;height:2rem;border:1px solid var(--rule)}
.pcur{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.pnext{margin-left:.5rem;color:var(--blue);letter-spacing:.08em}

/* ---- document library (Licensing) ---- */
.searchrow{display:grid;grid-template-columns:minmax(0,2fr) repeat(3,minmax(0,1fr));gap:.6rem;
  margin:0 0 2rem}
@media(max-width:860px){.searchrow{grid-template-columns:1fr 1fr}}
@media(max-width:520px){.searchrow{grid-template-columns:1fr}}
.searchrow input,.searchrow select{font:inherit;font-size:.9rem;padding:.6rem .7rem;
  border:1px solid var(--rule);background:var(--panel);color:var(--ink);border-radius:0;
  -webkit-appearance:none;appearance:none;width:100%}
.searchrow input:focus,.searchrow select:focus{outline:2px solid var(--blue);outline-offset:-1px}

.docs{display:grid;gap:2rem}
.docgrp h3{font-family:var(--d);font-size:.64rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--blue);margin:0 0 .5rem;font-weight:600}
.doc{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,14rem) auto auto;gap:1rem;
  align-items:baseline;padding:.9rem .2rem;border-bottom:1px solid var(--rule2);
  border-top:1px solid transparent;transition:background .2s}
.docgrp .doc:first-of-type{border-top:1px solid var(--rule)}
.doc:hover{background:var(--panel)}
section.band.alt .doc:hover{background:var(--paper)}
.doc .dt{font-family:var(--d);font-weight:600;font-size:.93rem}
.doc .dm{font-size:.85rem;color:var(--soft)}
.doc .dk{font-family:var(--d);font-size:.58rem;letter-spacing:.11em;color:var(--faint);
  border:1px solid var(--rule);padding:.1rem .35rem}
.doc .dd{color:var(--blue);opacity:0;transition:opacity .2s,transform .2s}
.doc:hover .dd{opacity:1;transform:translateY(2px)}
@media(max-width:760px){
  .doc{grid-template-columns:1fr auto auto}
  .doc .dm{grid-column:1/-1;margin-top:.15rem}
}

/* people */
.people{display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));gap:1.1rem}
/* A row holding fewer faces than the grid was sized for. Capping the grid's
   width was wrong: the two breakpoints below re-count the columns, so at any
   width between them the pair went back to filling the left of a three-track
   row with the third track empty -- the same fault, just at a size it had
   not been looked at. Sizing the tracks instead has no breakpoint in it. The
   cap is the width a card has in the roster, and the group is centred, so a
   partial row reads as a partial row at every width. */
.people.part{grid-template-columns:repeat(var(--n),minmax(0,17rem));
  justify-content:center}
@media(max-width:980px){.people{grid-template-columns:repeat(3,1fr)}}
@media(max-width:720px){.people{grid-template-columns:repeat(2,1fr)}}
.person{margin:0}
.pimg{aspect-ratio:1;background:var(--paper);border:1px solid var(--rule);overflow:hidden;
  display:grid;place-items:center;position:relative}
section.band.alt .pimg{background:var(--panel)}
.pimg img{width:100%;height:100%;object-fit:cover;object-position:center top;display:block;
  filter:grayscale(1) contrast(1.03);transition:filter .35s var(--ease)}
.person:hover .pimg img{filter:grayscale(0)}
.pimg .noface{font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.person figcaption{padding:.7rem 0 0;display:block}
.pn{display:block;font-family:var(--d);font-weight:600;font-size:.92rem}
.pt{display:block;font-size:.8rem;color:var(--soft);line-height:1.4;margin-top:.15rem}
.pinf{display:inline-block;margin-top:.35rem;font-family:var(--d);font-size:.56rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--orange-ink);
  border:1px solid var(--orange);padding:.05rem .3rem}

/* forms */
.form{max-width:44rem}
.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:.9rem}
@media(max-width:620px){.fgrid{grid-template-columns:1fr}}
.fld{display:block}
.fld:has(textarea){grid-column:1/-1}
/* --faint on white is 2.9:1. That is under the 4.5:1 a label needs, and a
   form label is the one piece of text a person reads while their eye is
   already on the box below it. --soft is 5.6:1. Every form on the site takes
   this, not only the one it was raised against. */
.fld span{display:block;font-family:var(--d);font-size:.72rem;letter-spacing:.09em;
  text-transform:uppercase;color:var(--soft);font-weight:500;margin-bottom:.42rem}
.fld .req{color:var(--orange);font-style:normal;margin-left:.18em}
/* Taller boxes and a border with enough weight to read as an edge rather
   than as a tint. Square corners are deliberate: the mark's corner belongs
   to actions and containers, and putting it on every input turns a signature
   into wallpaper. */
.fld input,.fld textarea,.fld select{width:100%;font:inherit;font-size:.94rem;
  padding:.72rem .85rem;background:var(--panel);color:var(--ink);
  border:1px solid color-mix(in srgb,var(--rule) 62%,var(--soft));
  border-radius:0;-webkit-appearance:none;appearance:none}
.fld input:hover,.fld textarea:hover,.fld select:hover{border-color:var(--soft)}
/* the arrow disappears with appearance:none, so draw one */
.fld select{background-image:linear-gradient(45deg,transparent 50%,var(--soft) 50%),
  linear-gradient(135deg,var(--soft) 50%,transparent 50%);
  background-position:calc(100% - 18px) 55%,calc(100% - 13px) 55%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:2.2rem}
.fld input:focus,.fld textarea:focus,.fld select:focus{outline:2px solid var(--blue);
  outline-offset:-1px}
.fnote{font-size:.76rem;color:var(--faint);margin:.9rem 0 0}

/* faq */
.faq{border-top:1px solid var(--rule);max-width:64ch}
.faq details{border-bottom:1px solid var(--rule2)}
.faq summary{padding:.95rem 0;cursor:pointer;font-family:var(--d);font-weight:600;
  font-size:.94rem;list-style:none}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";float:right;color:var(--faint)}
.faq details[open] summary::after{content:"\2212"}
.faq p{padding:0 0 1rem;color:var(--soft);font-size:.9rem;margin:0}

/* cta band */
.ctaband{background:var(--blue);color:#fff}
.ctain{display:flex;align-items:center;justify-content:space-between;gap:1.6rem;
  padding:clamp(2rem,4vw,3rem) 0;flex-wrap:wrap}
.ctaband h2{color:#fff}
.ctaband p{color:rgba(255,255,255,.82);margin:.6rem 0 0;max-width:48ch}

/* breadcrumbs */
.crumbs{background:var(--panel);border-bottom:1px solid var(--rule);font-family:var(--d);
  font-size:.68rem;letter-spacing:.1em;text-transform:uppercase}
.crumbs .wrap{display:flex;gap:.5rem;flex-wrap:wrap;padding-top:.75rem;padding-bottom:.75rem}
/* WCAG 2.2 2.5.8 asks 24x24 CSS px of any target that is not a link inside
   a sentence, and a breadcrumb is navigation rather than prose. The line box
   is 19px, so the padding takes it to 25 and the negative margin hands the
   row back the height it just gained -- the crumbs do not move, the target
   grows. It reaches every inner page: 46 of the 47 carry a breadcrumb. */
.crumbs a{color:var(--soft);padding-block:3px;margin-block:-3px}
.crumbs a:hover{color:var(--blue)}
.crumbs span{color:var(--orange-ink)}
.crumbs em{font-style:normal;color:var(--faint)}

/* draft note — visible because this is a draft, and pretending otherwise
   would let placeholder copy pass for approved copy */
.draftnote{border-left:2px solid var(--orange);background:var(--orange-bg);
  padding:.7rem .9rem;font-size:.82rem;color:var(--orange-ink);line-height:1.5;
  max-width:74ch;margin:1.4rem 0 0}
.draftnote::before{content:"Draft note — ";font-weight:600}
/* Editorial drafting notes must never appear on the public site. */
.draftnote{display:none!important}

/* footer */
.foot{background:var(--ink);color:#fff;padding:clamp(2.5rem,5vw,4rem) 0 0}
.fwrap{max-width:1240px;margin:0 auto;padding:0 clamp(1.1rem,4vw,2.6rem);
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2.2fr);gap:clamp(1.6rem,4vw,3rem)}
/* 960, not 900. The tagline's first line -- "Tissue restoration, from
   assessment" -- measures 252px, and in the two-column grid the brand column
   is 0.275 of the viewport: below 916px it is too narrow, so the forced break
   would land in the middle of a three-line block instead of the end of a
   two-line one. 920 closed that band but left one pixel of headroom at the
   breakpoint itself, which is not headroom. 960 gives twelve, and stacking
   the footer a little earlier costs nothing. */
@media(max-width:960px){.fwrap{grid-template-columns:1fr}}
/* The mark and its trademark travel together, so they need a line box of
   their own -- the img is display:block and would otherwise push the glyph
   onto the next row. Same --logo-h contract as the header. */
.fbrand .fmark{--logo-h:30px;display:inline-flex}
.fbrand img{height:var(--logo-h);width:auto;filter:brightness(0) invert(1)}
/* The footer mark is inverted to white, so the glyph follows it rather than
   --blue, which would be the one blue thing on a dark-ink ground. */
.fbrand .tm{color:#fff}
.fbrand p{color:rgba(255,255,255,.62);font-size:.88rem;margin:1rem 0 0;max-width:30ch}
.fbrand .freach a{color:rgba(255,255,255,.82);font-size:.85rem}
.fbrand .freach a:hover{color:#fff}
.fcols{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:1.2rem}
@media(max-width:960px){.fcols{grid-template-columns:repeat(2,1fr)}}
.fcol h3,.fcol .fhead{font-family:var(--d);font-size:.63rem;letter-spacing:.13em;text-transform:uppercase;
  color:rgba(255,255,255,.5);margin:0 0 .7rem;font-weight:600}
.fcol a{display:block;font-size:.85rem;color:rgba(255,255,255,.78);padding:.2rem 0}
.fcol a:hover{color:#fff}
.fbase{max-width:1240px;margin:2.5rem auto 0;padding:1.1rem clamp(1.1rem,4vw,2.6rem);
  border-top:1px solid rgba(255,255,255,.14);display:flex;justify-content:space-between;
  gap:1rem;flex-wrap:wrap;font-size:.75rem;color:rgba(255,255,255,.5)}


/* the nav's own page-view classes do not exist here; make sure the mega
   panels still size correctly against a real page underneath */
.site{position:sticky;top:0}
.mainnav a{display:inline-block;text-decoration:none}
.pitem,.pcard,.ptab,.fbtn,.dleaf,.dgo{text-decoration:none}
.pgroup[hidden]{display:none}

/* ===================== motion =====================
   Every moving part lives here, so the WordPress theme can take the layer
   across in one piece. Three durations and two curves; nothing depends on
   JavaScript or on scroll position.

   Entrance animations run once on load and use animation-fill-mode:backwards,
   so the resting state in the cascade is the finished state: if animation
   never runs, the page is already correct. Nothing is parked at opacity:0
   waiting to be revealed.

   The reduced-motion block in navdata.CSS_TYPEFACE switches all of it off. */

:root{
  --dur-1:140ms;   /* micro   — arrows, underlines, focus */
  --dur-2:240ms;   /* state   — fills, panels, rows */
  --dur-3:440ms;   /* entrance — hero on first paint */
  --ease-out:cubic-bezier(.33,1,.68,1);
}

@keyframes en-rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes en-fade{from{opacity:0}to{opacity:1}}
@keyframes en-wipe{from{transform:scaleX(0)}to{transform:scaleX(1)}}

/* hero: a short stagger down the text column, art fading in alongside */
.hero-txt>*{animation:en-rise var(--dur-3) var(--ease-out) backwards}
.hero-txt h1{animation-delay:110ms}
.hero-txt .lead{animation-delay:190ms}
.hero-txt .btn{animation-delay:260ms}
.hero-art{animation:en-fade var(--dur-3) var(--ease-out) 140ms backwards}
/* ---------- the lamp ----------
   Light rising off the bottom edge of the header, the full width of it, when
   the pointer is anywhere in the section. Two stops rather than one: a
   single linear fade reads as a grey wash, and what makes it read as light
   is that it falls off fast near the source and slowly above it.

   It sits at z-index 0 under .hero-in, which honeycomb.CSS already lifts to
   1, so it passes behind the copy and the artwork rather than over them, and
   it is pointer-events:none so it cannot take a click from the button
   standing in it. The fade is long on the way in and short on the way out —
   a lamp warming up, not a hover state blinking. */
.hero::before{content:"";position:absolute;left:0;right:0;bottom:0;height:64%;
  z-index:0;pointer-events:none;opacity:0;
  /* Two layers. The linear one is the light along the whole edge; the radial
     one is where the lamp actually is, and it follows the pointer across the
     width. A flat gradient alone is even, and even light is what makes a
     header look printed rather than lit. */
  background:
    radial-gradient(58% 118% at var(--lx,50%) 100%,
      rgba(214,234,255,.92) 0%,
      rgba(218,236,255,.42) 42%,
      rgba(220,237,255,0) 72%),
    linear-gradient(to top,
      rgba(228,241,255,.78) 0%,
      rgba(226,240,255,.44) 22%,
      rgba(224,238,255,.18) 48%,
      rgba(224,238,255,0) 78%);
  transition:opacity .12s var(--ease-out)}
/* The spot itself slides rather than jumping between samples. */
.hero.lit::before{transition:opacity .55s var(--ease-out),
  background-position .2s linear}
.hero:hover::before{opacity:1;transition-duration:.55s}

/* On the dark hero the same light, in the only direction it can go there. */
.hero.onink::before{background:
  radial-gradient(58% 118% at var(--lx,50%) 100%,
    rgba(160,200,255,.34) 0%,
    rgba(150,193,255,.14) 44%,
    rgba(150,193,255,0) 72%),
  linear-gradient(to top,
    rgba(150,193,255,.20) 0%,
    rgba(140,186,255,.11) 24%,
    rgba(140,186,255,.05) 52%,
    rgba(140,186,255,0) 80%)}

@media (hover:none),(pointer:coarse){.hero::before{display:none}}

.hero::after{content:"";position:absolute;left:0;bottom:0;height:1px;width:100%;
  background:var(--blue);transform-origin:left center;
  animation:en-wipe var(--dur-3) var(--ease) 320ms backwards}
.hero{position:relative}

/* cards: the lift already existed — give it a shadow and a settled arrow */
a.card{transition:border-color var(--dur-1),transform var(--dur-2) var(--ease),
  box-shadow var(--dur-2) var(--ease)}
a.card:hover,a.card:focus-visible{box-shadow:0 6px 18px -10px rgba(13,78,159,.42)}
.card .carr{transition:opacity var(--dur-1),transform var(--dur-2) var(--ease)}
a.card:focus-visible .carr{opacity:1;transform:translateX(3px)}

/* listing rows: the rule under the row draws in from the left on hover */
.lrow{position:relative}
.lrow::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;
  background:var(--blue);transform:scaleX(0);transform-origin:left center;
  transition:transform var(--dur-2) var(--ease)}
.lrow:hover::after,.lrow:focus-within::after{transform:scaleX(1)}
.lrow .larr{transition:opacity var(--dur-1),transform var(--dur-2) var(--ease)}
.lrow:hover .larr,.lrow:focus-within .larr{opacity:1;transform:translateX(3px)}

/* toolbox steps: the active step keeps its orange edge, hover only warms it */
.cstep{transition:border-color var(--dur-1),background var(--dur-2),transform var(--dur-2) var(--ease)}
.cstep:hover,.cstep:focus-visible{transform:translateY(-1px)}

/* document rows and people tiles */
.doc{transition:background var(--dur-2),border-color var(--dur-1)}
.doc .dd{transition:opacity var(--dur-1),transform var(--dur-2) var(--ease)}
.doc:hover .dd,.doc:focus-within .dd{opacity:1;transform:translateX(3px)}
.people img{transition:filter var(--dur-3) var(--ease)}
.people li:hover img,.people li:focus-within img{filter:grayscale(0) contrast(1)}

/* prose links: an underline that grows rather than blinks on */
.prose a{background-image:linear-gradient(var(--blue),var(--blue));
  background-repeat:no-repeat;background-position:0 100%;background-size:0 1px;
  transition:background-size var(--dur-2) var(--ease);color:var(--blue)}
.prose a:hover,.prose a:focus-visible{background-size:100% 1px}

/* table rows */
.tbl tbody tr{transition:background var(--dur-2)}
.tbl tbody tr:hover{background:var(--panel)}

/* focus, everywhere the page owns. The nav supplies its own. */
main a:focus-visible,main button:focus-visible,main input:focus-visible,
main select:focus-visible,main textarea:focus-visible{
  outline:2px solid var(--blue);outline-offset:2px;border-radius:1px}

/* form fields settle rather than snap */
main input,main select,main textarea{
  transition:border-color var(--dur-1),box-shadow var(--dur-2) var(--ease-out)}
main input:focus,main select:focus,main textarea:focus{
  box-shadow:0 0 0 3px var(--orange-bg)}

/* ===================== 404 =====================
   The numerals are two copies of the same string, clipped above and below
   one shared irregular boundary. They rest apart and are drawn together on
   load, with the seam fading as they meet: a break closing, which is the
   one metaphor this company can use without reaching for it.

   The polygons share their boundary vertices exactly, so no sliver of
   background shows through the join. Both copies are aria-hidden; the h1
   underneath carries the meaning. */

.nf{padding:clamp(2.6rem,7vw,5rem) 0 clamp(3rem,8vw,6rem);text-align:center}
.nf .wrap{max-width:56rem}
/* Shrink-wrapped to the numerals. The box used to run the full width of the
   column, and the seam runs the full width of the box — so the crack carried
   on past the digits as a rule across the page. Played once on load that
   flickered by; on a loop it is a line that keeps coming back. */
.nf-art{position:relative;display:block;width:fit-content;
  margin:0 auto clamp(1.4rem,4vw,2.4rem);line-height:.82;isolation:isolate}
.nf-n{display:block;font-family:var(--d);font-weight:700;color:var(--blue);
  font-size:clamp(6rem,26vw,17rem);letter-spacing:-.045em;
  font-variant-numeric:tabular-nums;user-select:none}
.nf-bot{position:absolute;inset:0}
/* The top fragment is carried 0.4% past the shared boundary so the two
   clip paths overlap rather than abut. Identical fill, so the overlap is
   invisible; an exact join is not — subpixel antialiasing leaves a
   hairline of background showing through the closed numerals. */
.nf-top{clip-path:polygon(0 0,100% 0,100% 45.4%,78% 51.9%,55% 37.4%,32% 50.9%,0 45.4%)}
.nf-bot{clip-path:polygon(0 45%,32% 50.5%,55% 37%,78% 51.5%,100% 45%,100% 100%,0 100%)}
.nf-seam{position:absolute;left:0;right:0;top:33%;height:22%;width:100%;
  color:var(--orange);pointer-events:none;
  /* Resting state is invisible: the seam exists only while the break closes.
     Without this the animation ends and the element falls back to opacity 1,
     leaving the crack drawn across the finished numerals. Safe to hide,
     because the seam is decorative — the numerals and the h1 never are. */
  opacity:0;
  /* the seam belongs to the numerals, so it fades out before the page edge
     rather than running off as a stray rule across the whole column */
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 16%,#000 84%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 16%,#000 84%,transparent)}

/* The break closes, holds, opens again. One keyframe set rather than an
   entrance plus a loop on top of it: the cycle starts apart and ends apart,
   so its first play is the arrival and 100% hands back to 0% with nothing
   moving. The hold either side is most of the 6s — a crack that never rests
   is a strobe, and this sits above the only sentence on the page.

   Reduced motion stops it: navdata's guard cancels animation outright, and
   with the cycle starting apart the numerals would be left broken, so the
   resting transform is set there too. */
.nf-top{animation:nf-cycle-t 6s var(--ease) 160ms infinite backwards}
.nf-bot{animation:nf-cycle-b 6s var(--ease) 160ms infinite backwards}
.nf-seam{animation:nf-seam 6s var(--ease) 160ms infinite backwards}
@keyframes nf-cycle-t{
  0%{transform:translate(-.9%,-5%)}
  17%,62%{transform:none}
  80%,100%{transform:translate(-.9%,-5%)}}
@keyframes nf-cycle-b{
  0%{transform:translate(.9%,5%)}
  17%,62%{transform:none}
  80%,100%{transform:translate(.9%,5%)}}
@keyframes nf-seam{
  0%{opacity:1}
  24%{opacity:0}
  58%{opacity:0}
  82%,100%{opacity:1}}
@media(prefers-reduced-motion:reduce){
  .nf-top,.nf-bot{transform:none}
  .nf-seam{opacity:0}}

.nf h1{font-family:var(--d);font-weight:600;letter-spacing:-.02em;
  font-size:clamp(1.5rem,4.2vw,2.3rem);margin:0 0 .7rem;text-wrap:balance}
.nf .lead{max-width:44ch;margin:0 auto;color:var(--soft)}
/* One way back rather than six. The list of routes was a second navigation
   for someone who has already lost their place; the header above it holds
   the same six destinations and more. */
.nf .btn{margin-top:clamp(1.6rem,4vw,2.4rem)}

/* ===================== product pages =====================
   Regulated copy, so the page has to make three things unmistakable: what
   the product is, what you order, and what the footnotes say. The claim
   strip and the ordering table carry the weight; nothing else competes. */

/* A tile each, at the size of the icon rows elsewhere on the site: 32px of
   glyph and text a step above body copy, rather than four labels set smaller
   than everything near them. */
.claims{list-style:none;margin:0;padding:0;display:grid;
  grid-template-columns:repeat(var(--c,4),minmax(0,1fr));
  gap:clamp(1rem,2.4vw,1.8rem)}
@media(max-width:900px){.claims{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:520px){.claims{grid-template-columns:1fr}}
.claims li{display:grid;gap:.6rem;justify-items:start}
.claims .ck{width:32px;height:32px;color:var(--orange);
  transition:transform var(--dur-2) var(--ease)}
.claims li:hover .ck{transform:translateY(-3px)}
.claims li span{font-family:var(--d);font-size:clamp(.98rem,1.5vw,1.08rem);
  font-weight:500;color:var(--ink);line-height:1.35}
/* On a category page the claims sit between the heading and the grid of
   products and were touching both. */
.claims + *{margin-top:clamp(2rem,4.4vw,3rem)}

/* These four sentences are the argument for the product and they were set
   smaller than the body copy around them, with a .72rem numeral beside each
   that read as a row label on a table. The number is now the size of a
   heading and the sentence is a size above the body, so the list is the
   loudest thing in its band rather than the quietest. Light weight and a
   tint keep the numerals from shouting over the words they are counting. */
.adv{list-style:none;margin:0;padding:0;display:grid;gap:0;
  border-top:1px solid var(--rule);counter-reset:adv}
.adv li{counter-increment:adv;display:grid;grid-template-columns:auto 1fr;
  gap:clamp(.9rem,2vw,1.5rem);align-items:start;
  padding:clamp(1.1rem,2.2vw,1.5rem) .2rem;border-bottom:1px solid var(--rule2)}
.adv .an{font-family:var(--d);font-size:clamp(1.75rem,3.4vw,2.5rem);
  font-weight:300;line-height:.86;letter-spacing:-.02em;
  color:color-mix(in srgb,var(--blue) 34%,transparent);
  font-variant-numeric:tabular-nums;
  transition:color .35s ease}
.adv .an:empty::before{content:counter(adv,decimal-leading-zero)}
.adv li:hover .an{color:var(--orange)}
.adv .at{font-size:clamp(1rem,1.55vw,1.12rem);line-height:1.58;
  align-self:center;max-width:46ch}
@media(min-width:861px){
  .adv.wide{grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:clamp(1.8rem,4.4vw,3.6rem)}
  /* the column is the measure now, so the paragraph stops fighting it */
  .adv.wide .at{max-width:52ch}
}
.adv sup{font-size:.62em;vertical-align:super;color:var(--soft)}

/* The label and the code are two halves of one fact and were set as if they
   were unrelated: .62rem of the palest grey in the palette beside 1.05rem of
   bold blue, so the chip read as a shout with a whisper in front of it. They
   are a quarter of a step apart in size now, one weight apart rather than
   three, and both dark enough to be read. */
.ordcode{display:inline-flex;align-items:baseline;gap:.55rem;margin:0 0 1.2rem;
  border:1px solid color-mix(in srgb,var(--blue) 42%,transparent);
  padding:.48rem .8rem}
.ordcode span{font-family:var(--d);font-size:.78rem;font-weight:500;
  letter-spacing:.07em;text-transform:uppercase;color:var(--soft)}
.ordcode b{font-family:var(--d);font-size:.92rem;font-weight:600;
  letter-spacing:.01em;color:var(--blue);font-variant-numeric:tabular-nums}
.tbl.ord td,.tbl.ord th{font-variant-numeric:tabular-nums}
.tbl.ord td:nth-child(2){font-family:var(--d);color:var(--soft)}
.tblwrap+.tblwrap{margin-top:.9rem}

/* the family comparison on a brand page. Wider than the SKU tables it is
   built from -- five columns, one of them a size list -- so it gets its own
   minimum and scrolls inside .tblwrap below that, like every other table. */
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);
  clip-path:inset(50%);white-space:nowrap}
.tbl.cmp{min-width:44rem;font-size:.88rem}
.tbl.cmp td{vertical-align:top;padding:.85rem .7rem}
.tbl.cmp td:first-child{white-space:nowrap}
.tbl.cmp td:first-child a{color:var(--ink);font-weight:500;text-decoration:none;
  border-bottom:1px solid transparent;transition:color var(--dur-2),border-color var(--dur-2)}
.tbl.cmp td:first-child a:hover{color:var(--orange);border-bottom-color:currentColor}
.tbl.cmp .ccode{font-family:var(--d);font-weight:600;color:var(--blue);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.tbl.cmp .csz{font-variant-numeric:tabular-nums}
/* the sizes are a list, not a sentence: set as chips they stay scannable
   down the column, which is the whole point of putting them side by side */
.tbl.cmp .csz span{display:inline-block;margin:0 .5rem .18rem 0;color:var(--soft)}
.tbl.cmp .csz span+span{padding-left:.5rem;border-left:1px solid var(--rule2)}
.tbl.cmp .cfly{text-align:right;white-space:nowrap}
.tbl.cmp .cfly a{font-family:var(--d);font-size:.72rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--soft);text-decoration:none;
  transition:color var(--dur-2)}
.tbl.cmp .cfly a:hover{color:var(--orange)}
.tbl.cmp tr.cgrp td{font-family:var(--d);font-size:.63rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint);font-weight:600;
  padding:1.5rem .7rem .5rem;border-bottom:1px solid var(--rule)}
.tbl.cmp tr.cgrp:hover td{background:none}

/* A button that follows a centred heading is centred on it. The grid or the
   people row between them is what centred the heading, and the button was
   the one thing in the band still hanging off the left margin. */
.bandhead.mid ~ .btn{display:block;width:max-content;margin-left:auto;margin-right:auto}

/* ---------- the support diagram ----------
   The client draws this as a loop with the phases on the arc and the items
   floating inside it. A loop does not survive a phone, so the same reading
   is laid out straight: the rail runs their orange to their blue, Day 1 to
   Day 30+, and each phase keeps its own items under it. */
.phas{margin-top:clamp(1.6rem,3vw,2.4rem)}
.ph-rail{display:block;height:4px;border-radius:2px;
  background:linear-gradient(to right,var(--orange),var(--blue))}
.ph-cols{display:grid;gap:clamp(1.6rem,3.4vw,3rem);
  margin-top:clamp(1.3rem,2.6vw,1.9rem)}
@media(min-width:761px){.ph-cols{grid-template-columns:1fr 1fr}}
.ph{--k:var(--orange)}
.ph.post{--k:var(--blue)}
.ph-when{margin:0;font-family:var(--d);font-size:.7rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--k)}
.ph-name{margin:.4rem 0 0;font-family:var(--d);font-weight:500;
  font-size:clamp(1.1rem,2.2vw,1.4rem);letter-spacing:-.01em;color:var(--ink)}
.ph-list{list-style:none;margin:1.1rem 0 0;padding:0;
  border-top:1px solid var(--rule)}
.ph-list li{position:relative;padding:.8rem 0 .8rem 1.6rem;
  border-bottom:1px solid var(--rule2);color:var(--soft);font-size:.92rem}
/* the same link out of the mark the rest of the site's lists carry, in the
   phase's own colour */
.ph-list li::before{content:"";position:absolute;left:0;top:1.02rem;
  width:9px;height:9px;border-radius:0 34% 0 34%;background:var(--k)}
.ph-foot{margin:clamp(1.4rem,2.8vw,2rem) 0 0;padding-top:1rem;
  border-top:1px solid var(--rule);font-family:var(--d);font-size:.88rem;
  font-style:italic;color:var(--soft);text-align:center}

/* ---------- the three circles ----------
   Their slide: Patient, Payor and Provider overlapping, and a win wherever
   two of them meet. Drawn rather than placed as a picture, so it scales, it
   takes the palette, and it can answer a pointer.

   The discs are the brand blue at full strength and the lenses are the
   brand orange, which means each carries the opposite label colour: white
   on the blue is 8.1:1 and the ink on the orange is 5.9:1, where the other
   way round they are 2.0 and 2.7 -- the two words would both be
   unreadable, and each on the half you would expect to be safe.

   An earlier version had no lenses at all: three translucent discs stacked
   and the overlaps fell out of the arithmetic. That cannot take a colour of
   its own, so the lens is now a shape -- one disc clipped by another. */
/* ---- the meeting media: a strip on the hub, the archive on its page ---- */
.mstrip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:.9rem;margin:2.2rem 0 0}
@media(max-width:900px){.mstrip{grid-template-columns:repeat(2,1fr)}}
/* A meeting is a row you scroll, not a grid that runs out. Native overflow
   first: with no script the row still scrolls, snaps and takes the keyboard,
   and the two arrows are simply never shown. */
/* grid-auto-columns takes the width flat, not minmax(0,...): a minmax whose
   floor is 0 lets the tracks squeeze themselves into the container and the
   row never overflows, so there is nothing to scroll. */
.mrow{display:grid;grid-auto-flow:column;grid-auto-columns:var(--mw);
  gap:.9rem;overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;scroll-padding-left:0;
  padding-bottom:.6rem;--mw:calc((100% - 1.8rem) / 3)}
@media(max-width:900px){.mrow{--mw:calc((100% - .9rem) / 2)}}
@media(max-width:560px){.mrow{--mw:86%}}
.mrow > .mtile{scroll-snap-align:start}
.mrow:focus-visible{outline:2px solid var(--blue);outline-offset:4px}
.mrow::-webkit-scrollbar{height:6px}
.mrow::-webkit-scrollbar-thumb{background:var(--rule);border-radius:3px}
.mrow::-webkit-scrollbar-track{background:transparent}
/* The heading takes the width it needs and the arrows keep theirs. Without
   min-width:0 a long meeting name is a flex item that will not shrink, and
   on a phone it is cut off mid-word with its date pushed out of sight. */
.mghead{display:flex;align-items:baseline;justify-content:space-between;
  gap:.6rem 1rem;margin:0 0 .9rem;flex-wrap:wrap}
.mgh{flex:1 1 14rem;min-width:0}
.mrow-nav{display:flex;gap:.5rem;flex:none}
/* display:flex beats the hidden attribute's UA display:none, so a row that
   fits would still show two arrows that do nothing. */
.mrow-nav[hidden]{display:none}
.mrow-nav .cbtn:disabled{opacity:.3;cursor:default}
.marchive{display:grid;gap:clamp(2rem,4vw,3.2rem);margin:2.2rem 0 0}
.mgh{font-family:var(--d);font-size:1rem;font-weight:600;letter-spacing:-.008em;
  margin:0;display:flex;flex-wrap:wrap;gap:.2rem .8rem;align-items:baseline}
.mgh span{font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint);font-weight:400}
/* One tile. The photograph is the content, so the frame is a hairline and a
   crop and nothing else. */
.mtile{margin:0;display:block}
.mplate{position:relative;display:block;overflow:hidden;aspect-ratio:4/3;
  background:var(--rule2);border:1px solid var(--rule)}
.mplate img{display:block;width:100%;height:100%;object-fit:cover;
  transition:transform .5s var(--ease-out)}
a.mplate:hover img{transform:scale(1.04)}
a.mplate:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
/* Which meeting, and when. The archive says it once per group; the strip on
   the Meetings page says it on every frame, because there it is the only
   thing that says it at all. */
.mtc{margin:.55rem 0 0;font-family:var(--d);font-size:.78rem;line-height:1.3;
  display:grid;gap:.12rem}
.mtc .mtw{font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint)}
/* A video says so: the length, and the triangle that means play. */
.mtk{position:absolute;left:.55rem;bottom:.55rem;display:flex;align-items:center;
  gap:.34rem;font-family:var(--d);font-size:.64rem;letter-spacing:.08em;
  color:#fff;background:rgba(10,36,64,.78);padding:.24rem .5rem .24rem .42rem}
.mtk svg{width:.72rem;height:.72rem;display:block}
a.mplate:hover .mtk{background:var(--blue)}
/* A frame that has not been shot yet. The lattice, cropped differently in
   each tile so a row of them is not a row of the same rectangle, and the
   badge the real tile will carry. */
/* Twice the cards' cell: on a tile this size the card's tile reads as
   noise, and the mask has no intrinsic size of its own to fall back on --
   left unset it stretches to one enormous hexagon. */
.mplate.is-ph{--cw:48.4px;--ch:84px}
.mplate.is-ph::before{content:"";position:absolute;inset:0;
  background:color-mix(in srgb,var(--blue) 16%,transparent);
  -webkit-mask-image:var(--comb);mask-image:var(--comb);
  -webkit-mask-size:var(--cw) var(--ch);mask-size:var(--cw) var(--ch);
  -webkit-mask-position:var(--o);mask-position:var(--o)}
.mplate.is-ph .mtk{background:rgba(10,36,64,.42)}

/* ---- the meeting calendar --------------------------------------------- */
/* A meeting is a date before it is anything else, so the date is a block of
   its own on the left and the name reads off it. Three fields, because three
   are what we have: the booth number and the booth picture their note also
   asks for have not been sent. */
.mtgrid{display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));
  gap:1rem;margin:2.4rem 0 0}
@media(max-width:820px){.mtgrid{grid-template-columns:1fr}}
.mtg{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:1.2rem;
  align-items:center;padding:1.15rem 1.2rem;border:1px solid var(--rule);
  background:var(--panel);color:inherit;text-decoration:none;
  transition:background .2s,border-color .2s}
section.band.alt .mtg{background:var(--paper)}
a.mtg:hover{background:var(--blue-bg);border-color:var(--blue)}
a.mtg:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.mtd{display:grid;justify-items:center;line-height:1;font-family:var(--d);
  padding-right:1.2rem;border-right:1px solid var(--rule)}
.mtd b{font-size:1.9rem;font-weight:600;letter-spacing:-.02em;color:var(--blue)}
.mtd i{font-style:normal;font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink);margin-top:.3rem}
.mtd em{font-style:normal;font-size:.62rem;letter-spacing:.1em;
  color:var(--faint);margin-top:.2rem}
.mth{display:block;font-family:var(--d);font-weight:600;font-size:1rem;
  line-height:1.25;letter-spacing:-.008em}
a.mtg:hover .mth{color:var(--blue)}
.mtl{display:block;font-size:.84rem;color:var(--soft);margin-top:.3rem}
.mtarr{color:var(--blue);opacity:0;transform:translateX(-4px);
  transition:opacity .2s,transform .2s}
a.mtg:hover .mtarr,a.mtg:focus-visible .mtarr{opacity:1;transform:none}

/* ---- artwork behind a band -------------------------------------------- */
/* Hard against the right, under the words, and hanging off the bottom of its
   own section so that the next band cuts it. Being cut is the point: a globe
   shown whole is an illustration of a globe, a globe three-quarters shown is
   a page that carries on past it. The section clips; the wrap is what the
   figure is hung from, so it keeps its distance from the text column rather
   than from the window. */
section:has(> .wrap > .bgart){overflow:hidden}
.wrap:has(> .bgart){position:relative}
/* the words above the artwork -- but not the artwork itself, which is
   absolutely placed and would lose its corner to position:relative */
.wrap:has(> .bgart) > *:not(.bgart){position:relative;z-index:1}
/* The overhang is a share of the figure itself, not of the band: a band that
   happens to run long would otherwise show the globe whole, which is the one
   thing this is not meant to do. Three tenths of it are always under the
   next section. */
.bgart{--gs:clamp(17rem,32vw,29rem);
  position:absolute;z-index:0;pointer-events:none;user-select:none;
  right:-3%;width:var(--gs);height:auto;opacity:.7;
  /* The wrap is what it hangs from, and the section's own bottom padding
     sits between the wrap and the cut, so that padding comes off the
     overhang -- otherwise a third of the figure is spent inside the band and
     barely a tenth of it goes under the next one. */
  bottom:calc(var(--gs) * -.3 - clamp(3rem,7vw,5.5rem))}
@media(max-width:1040px){
  /* Narrower, and further out of the way: the text column has taken the
     width the figure was keeping clear of. */
  .bgart{--gs:21rem;right:-16%;opacity:.34}
}
@media(max-width:640px){.bgart{display:none}}
:root[data-theme="dark"] .bgart{opacity:.28}

/* ---- the four verbs, and the five lines the page ends on --------------- */
.wverbs{list-style:none;margin:2.6rem 0 0;padding:0;display:grid;
  grid-template-columns:repeat(var(--c),1fr);gap:0 1.7rem}
.wverbs li{position:relative;padding:2.1rem 0 0}
/* Each rule runs from its own mark, across the gap, to the next one, so the
   four together read as one line -- and the last has none, which is what
   makes the orange mark the end of it rather than a point it passes. */
.wverbs li::after{content:"";position:absolute;top:8px;left:0;right:-1.7rem;
  height:1px;background:var(--rule)}
.wverbs li:last-child::after{display:none}
.wverbs .wvm{position:absolute;top:2.5px;left:0;width:12px;height:12px;z-index:1;
  background:var(--blue);border-radius:0 34% 0 34%}
.wverbs li:last-child .wvm{background:var(--orange)}
.wverbs .wvt{display:block;font-family:var(--d);font-weight:600;
  font-size:clamp(1.02rem,1.55vw,1.28rem);line-height:1.24;letter-spacing:-.012em}
@media (max-width:780px){
  .wverbs{grid-template-columns:1fr;gap:0}
  .wverbs li{padding:0 0 1.15rem 1.7rem}
  .wverbs li:last-child{padding-bottom:0}
  .wverbs li::after{top:6px;bottom:-6px;left:5.5px;right:auto;width:1px;height:auto}
  .wverbs li:last-child::after{display:none}
  .wverbs .wvm{top:0}
}
.venn{margin:0}
.venn svg{display:block;width:100%;max-width:24rem;height:auto;margin-inline:auto;
  overflow:visible}
.vc{fill:var(--blue);transition:fill var(--dur-2) var(--ease)}
.vl{fill:var(--orange);transition:fill var(--dur-2) var(--ease)}
/* the white arcs, drawn over both so the lens does not swallow them */
.vr{fill:none;stroke:var(--panel);stroke-width:3}
/* The name is drawn over its own disc, so it was swallowing the pointer and
   the disc under it never saw the hover -- and the name is the obvious thing
   to point at. It passes the pointer through; the wins keep theirs, because
   they are the other half of the interaction. */
.vt{font-family:var(--d);font-size:27px;font-weight:500;fill:#fff;
  text-anchor:middle;pointer-events:none}
.vw{font-family:var(--d);font-size:20px;font-weight:600;fill:var(--ink);
  text-anchor:middle}

/* Hovering a disc deepens it; hovering a win deepens the two it belongs to
   and its own lens with them. Deeper rather than lighter, so the white on
   the blue and the ink on the orange both only gain. */
@supports selector(:has(*)){
  @media (hover:hover) and (pointer:fine){
    .venn .vc:hover{fill:color-mix(in srgb,var(--blue) 78%,#000)}
    .venn svg:has(.vw-py:hover) .vc-p,.venn svg:has(.vw-py:hover) .vc-y,
    .venn svg:has(.vw-pv:hover) .vc-p,.venn svg:has(.vw-pv:hover) .vc-v,
    .venn svg:has(.vw-yv:hover) .vc-y,.venn svg:has(.vw-yv:hover) .vc-v{
      fill:color-mix(in srgb,var(--blue) 78%,#000)}
    .venn svg:has(.vw-py:hover) .vl-py,
    .venn svg:has(.vw-pv:hover) .vl-pv,
    .venn svg:has(.vw-yv:hover) .vl-yv{
      fill:color-mix(in srgb,var(--orange) 88%,#000)}
  }
}
@media (prefers-reduced-motion:reduce){.vc,.vl{transition:none}}

/* A portrait in a split's second column. Smaller than the half it sits in,
   because the note asking for it asks for it smaller, and left-aligned so it
   sits against the words rather than floating in the middle of its half. */
/* The block that pairs a person with their portrait reads as its own half
   of the band, so it takes a rule above it and a name at a name's size --
   42px, the section heading's own, made the person louder than the section
   they are in. */
.splitblk.person{border-top:1px solid var(--rule);
  padding-top:clamp(1.8rem,3.6vw,2.8rem);
  margin-top:clamp(1.8rem,3.6vw,2.8rem)}
.splitblk.person h2{font-size:clamp(1.35rem,2.3vw,1.72rem);line-height:1.25;
  letter-spacing:-.015em}
.spfig{margin:0;max-width:24rem;margin-left:auto}
.spfig img{display:block;width:100%;height:auto;
  border-radius:0 var(--card-r) 0 var(--card-r);
  filter:grayscale(1) contrast(1.03);transition:filter .35s var(--ease)}
.splitblk:hover .spfig img{filter:grayscale(0)}
@media(prefers-reduced-motion:reduce){.spfig img{transition:none}}

/* A photograph breaking out of the page's measure to the full width, and a
   band that stops where the picture does. 100vw counts the scrollbar and
   100% does not, so the break-out is written against the wrap's own width;
   the section clips what is left rather than letting the page scroll
   sideways -- the same guard the hero carries for its tilting artwork. */
section.band.sendoff{padding-bottom:0;overflow-x:clip;position:relative}
/* The copy sits on the picture rather than above it, centred over it. The
   picture's top is white for about a fifth of its height, and its height is
   its width over 2.037, so that white band is about 9% of the width -- a
   percentage margin resolves against width, so -10% lands the copy right at
   the end of the white and the same number holds on a phone and on a
   desktop. Everything else in the band is lifted a layer so the words stay
   on top. */
/* The head is capped at 60ch, so centring its text only centred it inside a
   681px box still sitting against the left margin -- which on the page reads
   as left-aligned. It needs the auto margins the .mid variant uses, which is
   what these two lines are. */
section.band.sendoff .bandhead{margin-left:auto;margin-right:auto;
  text-align:center}
section.band.sendoff .prose{text-align:center;max-width:58ch;
  margin-left:auto;margin-right:auto}
section.band.sendoff .btn{display:block;width:max-content;
  margin-left:auto;margin-right:auto}
section.band.sendoff .wrap > *{position:relative;z-index:1}
/* The picture is a child of the wrap too, so the rule above put it on the
   same layer -- and it comes last, which means it covered the button it was
   meant to sit behind. Named here so it loses that tie. */
section.band.sendoff .wrap > .fbleed{z-index:0}
.fbleed{display:block;width:100vw;max-width:100vw;height:auto;
  margin:-10% 0 0 50%;transform:translateX(-50%)}

/* ===================== the journey beam =====================
   Their direction asked for the path from ideas in several places, through
   EmeraNova, to the clinician and then the patient, and for it to be
   subtle. So the run is a dotted line at rest and the only thing that moves
   is a short bright segment travelling it -- the reference she pointed at
   does exactly that, and it is the one mechanism here that says "reaching"
   rather than "containing".

   pathLength on every run normalises them to 100, so one dash pattern and
   one duration carry a short hop and a long sweep at the same apparent
   speed. */
/* The board is wide by nature -- five stops left to right -- so below about
   750px its labels shrink with it: at a phone's width they came out at 6.7px,
   which is a word nobody reads. It scrolls inside its own box instead, the
   way the site's tables do, and the type stays at about 15px. */
.beam{margin:clamp(1.6rem,3.2vw,2.6rem) 0 0;overflow-x:auto}
.beam svg{display:block;width:100%;min-width:44rem;height:auto;overflow:visible}
.bp{fill:none;stroke:var(--rule);stroke-width:2;stroke-dasharray:2 7;
  stroke-linecap:round}
/* A spark, not a stripe. At 10 of 100 the lit part was a tenth of the run,
   which on the long sweep to the patient is a line crossing a third of the
   board; at 3 it is a travelling point, which is what the reference does.
   The glow is the rest of it -- a bright core with a soft halo reads as
   light moving, where a hard dash reads as a dash. */
.bm{fill:none;stroke:var(--orange);stroke-width:4.5;stroke-linecap:round;
  stroke-dasharray:3 97;animation:beam-run 3.4s linear infinite;
  filter:drop-shadow(0 0 5px color-mix(in srgb,var(--orange) 70%,transparent))}
@keyframes beam-run{from{stroke-dashoffset:100}to{stroke-dashoffset:0}}
/* the cells: hollow along the way, filled at the two ends that matter */
.bn{fill:none;stroke:var(--blue);stroke-width:2}
.bn-en{fill:var(--blue);stroke:none}
.bn-pt{fill:var(--blue);stroke:none}
/* the link out of the mark, inside the middle cell */
.bmk{fill:#fff}
.bl{font-family:var(--d);font-size:19px;font-weight:500;fill:var(--ink);
  text-anchor:middle}
/* the mark and the icon inside their cells, both on the filled blue */
.bmk path{fill:#fff}
.bico{color:#fff}
@media(prefers-reduced-motion:reduce){
  /* Standing still a dash parked somewhere along the run is a mark with no
     meaning, so the beams go and the dotted runs carry the drawing alone.
 */
  .bm{display:none}
  .bp{stroke-dasharray:none;stroke:var(--rule2)}}

/* ===================== the living gallery =====================
   The partner marquee's mechanism with photographs in it. The spacing is
   margin-right on every item including the last, not flex gap: with gap the
   space between the two copies is not counted like the spaces inside them,
   the travel stops equalling one run, and the seam shows as a jump once a
   loop. That is the same trap the logo row documents, and the same way out.

   The logos are muted at rest and take their colour back one at a time.
   These are not: the warmth is the whole reason they are here, so they are
   full colour throughout and the hover does what the pause cannot -- lifts
   the one you stopped on. */
.gmq{margin-top:clamp(1.6rem,3.2vw,2.4rem)}
.gmq-vp{overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.gmq-track{display:flex;align-items:center;list-style:none;margin:0;padding:0;
  width:max-content;animation:gmq-run 64s linear infinite}
.gmq-track li{margin-right:clamp(.7rem,1.6vw,1.15rem);flex:none}
.gmq-track img{display:block;width:auto;height:clamp(11rem,17vw,14rem);
  object-fit:cover;border-radius:0 var(--card-r) 0 var(--card-r);
  transition:transform var(--dur-2) var(--ease),box-shadow var(--dur-2) var(--ease)}
.gmq-vp:hover .gmq-track{animation-play-state:paused}
.gmq-track li:hover img{transform:translateY(-4px);
  box-shadow:0 16px 34px -22px rgba(10,36,64,.5)}
@keyframes gmq-run{to{transform:translateX(-50%)}}

/* Standing still, one run is enough and the second is dead weight in the
   layout, so it goes; the row wraps into a grid instead of running off. */
@media(prefers-reduced-motion:reduce){
  .gmq-track{animation:none;width:100%;flex-wrap:wrap;justify-content:center;
    row-gap:1rem}
  .gmq-track li[aria-hidden]{display:none}
  .gmq-track li:hover img{transform:none;box-shadow:none}
  .gmq-vp{-webkit-mask-image:none;mask-image:none}}

/* ---------- a line of ways to reach someone ----------
   The icons are the same size and take the same reveal as every other icon
   on the site, so a row of them here reads as the same family as the row on
   the contact page. */
.cline{list-style:none;margin:clamp(1.1rem,2.2vw,1.6rem) 0 0;padding:0;
  display:flex;flex-wrap:wrap;gap:clamp(1.4rem,3.4vw,3rem)}
.cline li{display:flex;align-items:center;gap:.75rem}
.clw{--ic:28px;display:block;height:var(--ic);color:var(--orange);flex:none;
  transition:transform var(--dur-2) var(--ease)}
.clw .ic{width:var(--ic);height:var(--ic)}
.cline li:hover .clw{transform:translateY(-3px)}
.cline a{font-family:var(--d);font-size:1.02rem;color:var(--ink);
  text-decoration:none;border-bottom:1px solid var(--rule);
  transition:color var(--dur-1),border-color var(--dur-1)}
.cline a:hover,.cline a:focus-visible{color:var(--blue);border-bottom-color:currentColor}
[data-reveal] .cline li{opacity:0;transform:translateY(12px)}
[data-reveal] .cline li.in{opacity:1;transform:none;
  transition:opacity .5s var(--ease-out) var(--d,0ms),
             transform .5s var(--ease-out) var(--d,0ms)}
@media(prefers-reduced-motion:reduce){
  [data-reveal] .cline li{opacity:1;transform:none}
  .cline li:hover .clw{transform:none}}

/* ---------- capability cards ----------
   The plate is the brand's corner rather than a uniform radius, the
   gradient runs the page's two grounds into each other, and the honeycomb
   ruled behind the words is masked away downwards so it never competes
   with them.

   The lattice is the site's own cell -- pointy-top, the shape the hero is
   built from -- drawn once as a seamless tile and used as a mask, so the
   colour comes from the theme's token rather than being baked into the
   file. 714 of URI, and it repeats without a seam. */
.fgrid{display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));
  gap:clamp(.8rem,1.6vw,1.15rem);margin-top:clamp(1rem,2vw,1.4rem)}
@media(max-width:980px){.fgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:520px){.fgrid{grid-template-columns:1fr}}
/* The honeycomb tile, named once. It is a data URI rather than a file, so
   there is no folder for it to resolve against and it is safe in a custom
   property -- which a url() pointing at assets/ is not. */
:root{--comb:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024.2%2042.0%22%3E%3Cpath%20d%3D%22M0.0%20-14.0L12.1%20-7.0L12.1%207.0L0.0%2014.0L-12.1%207.0L-12.1%20-7.0ZM24.2%20-14.0L36.4%20-7.0L36.4%207.0L24.2%2014.0L12.1%207.0L12.1%20-7.0ZM-12.1%207.0L0.0%2014.0L0.0%2028.0L-12.1%2035.0L-24.2%2028.0L-24.2%2014.0ZM12.1%207.0L24.2%2014.0L24.2%2028.0L12.1%2035.0L-0.0%2028.0L0.0%2014.0ZM36.4%207.0L48.5%2014.0L48.5%2028.0L36.4%2035.0L24.2%2028.0L24.2%2014.0ZM0.0%2028.0L12.1%2035.0L12.1%2049.0L0.0%2056.0L-12.1%2049.0L-12.1%2035.0ZM24.2%2028.0L36.4%2035.0L36.4%2049.0L24.2%2056.0L12.1%2049.0L12.1%2035.0Z%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%221%22%2F%3E%3C%2Fsvg%3E");}
.fcard{position:relative;overflow:hidden;isolation:isolate;
  --cw:24.2px;--ch:42.0px;
  min-height:8.5rem;display:flex;align-items:flex-end;
  padding:clamp(1rem,2vw,1.3rem);
  border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  background:linear-gradient(to bottom,var(--paper),var(--panel));
  transition:border-color var(--dur-1)}
section.band .fcard{background:linear-gradient(to bottom,var(--panel),var(--paper))}
.fcard:hover{border-color:color-mix(in srgb,var(--blue) 34%,var(--rule))}
.fpat{position:absolute;inset:0;z-index:-1;pointer-events:none;
  -webkit-mask-image:linear-gradient(to bottom,#000 0,transparent 82%);
  mask-image:linear-gradient(to bottom,#000 0,transparent 82%)}
/* the lattice itself */
.fpat::before{content:"";position:absolute;inset:0;background:var(--rule2);
  -webkit-mask-image:var(--comb);mask-image:var(--comb);
  -webkit-mask-size:var(--cw) var(--ch);mask-size:var(--cw) var(--ch)}
/* and the comb lights under the pointer, the way the hero's does */
.fglow{position:absolute;inset:0;opacity:0;
  transition:opacity var(--dur-2) var(--ease-out);
  background:radial-gradient(circle 130px at var(--mx,50%) var(--my,50%),
    color-mix(in srgb,var(--blue) 62%,transparent) 0,
    color-mix(in srgb,var(--blue) 18%,transparent) 38%,transparent 70%);
  -webkit-mask-image:var(--comb);mask-image:var(--comb);
  -webkit-mask-size:var(--cw) var(--ch);mask-size:var(--cw) var(--ch)}
@media (hover:hover) and (pointer:fine){.fcard:hover .fglow{opacity:1}}
@media (prefers-reduced-motion:reduce){.fglow{display:none}}
/* .fct, not .ft: navdata already styles a .ft -- the mega panel's feature
   title -- and a two-letter class in a global stylesheet is a collision
   waiting to happen. The mega's own rule is the more specific of the two so
   nothing was visibly wrong, which is exactly why it would have stayed. */
.fct{position:relative;font-family:var(--d);font-weight:500;
  font-size:.95rem;line-height:1.35;letter-spacing:-.01em;color:var(--ink)}

/* The client's drawing. It is wide artwork with small type in it, so on a
   phone it is pinched -- the written version that used to take over there
   has been taken out, and the alt text is what carries the content when the
   picture cannot. */
.dia{margin:clamp(1.6rem,3vw,2.4rem) 0 0}
.dia img{display:block;width:100%;height:auto}

/* The same drawing in a hero's second column. It tilts to the pointer the
   way the product photographs do -- same markup, same script -- but it is
   not a card: no fill, no frame, no shadow and nothing clipping its corners,
   because the artwork is a transparent PNG and every one of those would draw
   a rectangle around a drawing that has no edge. What is left of the card is
   the part she asked for, the reaction to the cursor. */
.hero-art.has-dia{border:none;background:none;padding:0;display:block;
  width:100%;overflow:visible;perspective:1200px;aspect-ratio:var(--ar,4/3)}
.hero-art.has-dia .tilt{position:absolute;inset:0;transform-style:preserve-3d;
  transform:rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) scale(var(--s,1));
  transition:transform .55s var(--ease)}
.hero-art.has-dia img{display:block;width:100%;height:100%;object-fit:contain}
/* The highlight is masked to the drawing itself. Unmasked it paints a pale
   disc over the page around it, which on a transparent figure reads as a
   smudge rather than as light on a surface. */
.hero-art.has-dia .spec{position:absolute;inset:0;pointer-events:none;opacity:0;
  transition:opacity var(--dur-2) var(--ease-out);
  background:radial-gradient(circle at var(--mx,50%) var(--my,50%),
    rgba(255,255,255,.30),rgba(255,255,255,0) 44%);
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}
.hero-art.has-dia[data-tilt].live .tilt{transition-duration:.09s}
@media (hover:hover) and (pointer:fine){
  .hero-art.has-dia[data-tilt]:hover .tilt{--s:1.025}
  .hero-art.has-dia[data-tilt]:hover .spec{opacity:1}}
@media (prefers-reduced-motion:reduce),(hover:none){
  .hero-art.has-dia .tilt{transform:none!important;transition:none}
  .hero-art.has-dia .spec{display:none}}
@media(min-width:861px){
  .hero-in:has(.hero-art.has-dia){grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}

/* A hairline and a little air is all that separates the small print from the
   content above it; it sits inside that content's section and on its ground. */
.notes{margin-top:clamp(2.2rem,4.5vw,3.2rem);padding-top:1.2rem;
  border-top:1px solid var(--rule)}
.legal{margin:0;max-width:70ch}
.legal p{font-size:.75rem;line-height:1.5;color:var(--faint);margin:0 0 .35rem}
.legal.refs{margin-top:1.4rem}
.legal .rh{font-family:var(--d);font-size:.62rem;letter-spacing:.13em;
  text-transform:uppercase;color:var(--soft);margin-bottom:.45rem}

/* A hero that has real photography drops the placeholder's dashed frame and
   centred caption, and lets the image fill the frame instead. */
/* The tilted card spills a little past its box — about 15px at full rotation.
   That fits inside the page margin at the widths measured, but `clip` on the
   section removes the whole class of bug on anything narrower. `clip` rather
   than `hidden`, so no scroll container is created and sticky positioning
   elsewhere in the page is unaffected. */
.hero{overflow-x:clip}
/* A photograph should be the tall thing in its own header, and it was not:
   measured at 1280, the copy column ran 388px against the picture's 348, so
   the image was the smaller half of its own hero and the band came out at
   530. Two changes. The columns are evened up, so the picture gets the width
   the copy was holding; and it is given a floor, so a wide frame cannot
   leave the header stubby. Together that is about 435px of picture and 580
   of header. The floor costs a 3:2 frame roughly a sixth of its width, which
   is the price of the header having any presence at all. */
/* width:100% is load-bearing once there is a floor. Without it the box is
   auto-width, and raising the height widens the box to keep the ratio --
   653px in a 550px column, overflowing it by 59 and getting quietly clipped
   by the section's overflow-x. With the width pinned, the floor raises the
   height and the picture crops inside it, which is what was wanted. */
.hero-art.has-img{border:none;background:none;padding:0;display:block;
  width:100%;overflow:visible;perspective:1200px;aspect-ratio:var(--ar,4/3)}
/* Both of these belong to the two-column header, and both sit after the
   stacking breakpoint in this file, so they carry their own guard: without
   it they would put two columns and a 300px floor back on a phone, where
   the picture is already the full width of the page. */
@media(min-width:861px){
  .hero-in:has(.hero-art.has-img){grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .hero-art.has-img{min-height:clamp(19rem,34vw,30rem)}
}
/* The photograph takes the corner every other surface on the site has, and a
   shadow to sit on the ground with. Square and flat, it was the one
   rectangle that belonged to nothing. */
.hero-art.has-img .tilt{position:absolute;inset:0;overflow:hidden;
  transform-style:preserve-3d;
  border-radius:0 var(--card-r) 0 var(--card-r);
  box-shadow:0 24px 48px -30px rgba(10,36,64,.42);
  transform:rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) scale(var(--s,1));
  transition:transform .55s var(--ease),box-shadow .45s var(--ease);
  background:var(--panel)}
.hero-art.has-img img{display:block;width:100%;height:100%;object-fit:cover}

/* A specular highlight tracking the pointer, so the tilt reads as a surface
   catching light rather than as a plane being rotated. */
.hero-art.has-img .spec{position:absolute;inset:0;pointer-events:none;opacity:0;
  transition:opacity var(--dur-2) var(--ease-out);
  background:radial-gradient(circle at var(--mx,50%) var(--my,50%),
    rgba(255,255,255,.26),rgba(255,255,255,0) 44%)}

/* While the pointer is inside, the transition is short enough to track it and
   long enough to smooth the jitter; on the way out the long duration takes
   over and the card settles. */
.hero-art.has-img[data-tilt].live .tilt{transition-duration:.09s}

@media (hover:hover) and (pointer:fine){
  .hero-art.has-img[data-tilt]:hover .tilt{--s:1.025;
    box-shadow:0 26px 50px -28px rgba(10,36,64,.5)}
  .hero-art.has-img[data-tilt]:hover .spec{opacity:1}
}
/* The pointer drives a transform that no transition can stand in for, so the
   whole thing is switched off rather than left tracking silently. */
@media (prefers-reduced-motion:reduce),(hover:none){
  .hero-art.has-img .tilt{transform:none!important;transition:none}
  .hero-art.has-img .spec{display:none}
}

/* ===================== hero: 3D hex field =====================
   A hero with bg="hex3d" or bg="hex3d-light" sits on a field of hexagonal
   cells drawn in perspective by en.js — a canvas rather than an image, so it
   is crisp at any size and it can move. The section owns its gradient and,
   for the dark field, the light type, so the hero reads correctly before the
   script runs, and if it never does. The scrim that keeps the copy legible is
   a pseudo-element: down the left on wide screens, up from the bottom once the
   layout stacks and the copy moves there. */
.hero-hex .hexbg{position:absolute;inset:0;width:100%;height:100%;display:block;
  pointer-events:none;animation:en-fade var(--dur-3) var(--ease-out) backwards}
.hero-hex .hero-in{position:relative;z-index:1}
/* This is the scrim that keeps the copy legible over the lattice -- and it
   is the same pseudo-element the lamp uses on every other hero. It had two
   of the lamp's properties and needed neither.

   opacity:0, which the lamp fades in on hover: the scrim was invisible at
   rest and the whole darkened panel came up under the pointer.

   height:64%, which the lamp uses to sit along the bottom edge. inset:0 sets
   top and bottom but not height, and when all three are set the height wins
   and the bottom is dropped -- so the box ran from the top of the hero to
   64% of it and stopped dead, with its gradient at .45 alpha right at that
   edge. That is the hard horizontal line across the header, and making the
   scrim permanent is what made the line permanent. Both are reset here and
   the lamp has a layer of its own below. */
.hero-hex::before{content:"";position:absolute;inset:0;height:auto;z-index:1;
  pointer-events:none;opacity:1;transition:none}
.hero-hex:hover::before{opacity:1}

/* The lamp, on its own element. Same light as .hero::before draws elsewhere:
   a spot that follows the pointer across the width, over an even wash along
   the whole bottom edge. It sits under the scrim and under the copy. */
.hero-hex .lamp{position:absolute;left:0;right:0;bottom:0;height:64%;z-index:0;
  pointer-events:none;opacity:0;transition:opacity .12s var(--ease-out)}
.hero-hex:hover .lamp{opacity:1;transition-duration:.55s}
.hero-hex.dark .lamp{background:
  radial-gradient(58% 118% at var(--lx,50%) 100%,
    rgba(160,200,255,.34) 0%,
    rgba(150,193,255,.14) 44%,
    rgba(150,193,255,0) 72%),
  linear-gradient(to top,
    rgba(150,193,255,.20) 0%,
    rgba(140,186,255,.11) 24%,
    rgba(140,186,255,.05) 52%,
    rgba(140,186,255,0) 80%)}
.hero-hex.light .lamp{background:
  radial-gradient(58% 118% at var(--lx,50%) 100%,
    rgba(214,234,255,.92) 0%,
    rgba(218,236,255,.42) 42%,
    rgba(220,237,255,0) 72%),
  linear-gradient(to top,
    rgba(228,241,255,.78) 0%,
    rgba(226,240,255,.44) 22%,
    rgba(224,238,255,.18) 48%,
    rgba(224,238,255,0) 78%)}
@media (hover:none),(pointer:coarse){.hero-hex .lamp{display:none}}

/* dark: the brand blue, lit and hazed */
.hero-hex.dark{background:linear-gradient(180deg,#184A8C 0%,#184A8C 22%,#0E3468 55%,#0A2440 100%);
  color:#fff;border-bottom-color:#0A2440}
.hero-hex.dark::before{
  background:linear-gradient(90deg,rgba(8,26,50,.7),rgba(8,26,50,.35) 34%,rgba(8,26,50,0) 62%),
    linear-gradient(180deg,rgba(6,20,40,0) 55%,rgba(6,20,40,.45))}
@media(max-width:860px){.hero-hex.dark::before{
  background:linear-gradient(180deg,rgba(8,26,50,0) 30%,rgba(8,26,50,.72)),
    linear-gradient(180deg,rgba(6,20,40,0) 55%,rgba(6,20,40,.45))}}
.hero-hex.dark h1{color:#fff}
.hero-hex.dark .lead{color:rgba(255,255,255,.84)}
.hero-hex.dark .hsub{color:rgba(255,255,255,.66)}
.hero-hex.dark .btn{border-color:#fff;color:#fff}
.hero-hex.dark .btn::before{background:#fff}
.hero-hex.dark .btn:hover,.hero-hex.dark .btn:focus-visible{color:var(--blue)}
.hero-hex.dark::after{background:rgba(255,255,255,.3)}
/* The photograph floats above the field, so it carries a shadow at rest as
   well as on hover. */
.hero-hex.dark .hero-art.has-img .tilt{box-shadow:0 30px 60px -32px rgba(2,12,28,.75)}
@media (hover:hover) and (pointer:fine){
  .hero-hex.dark .hero-art.has-img[data-tilt]:hover .tilt{
    box-shadow:0 38px 74px -30px rgba(2,12,28,.85)}
}

/* light: dark line and soft shadow on the site's own ground; the copy keeps
   its colours, so the page stays light */
.hero-hex.light{background:linear-gradient(180deg,#FBFCFD 0%,#FDFDFE 30%,#FFFFFF 100%)}
/* The veil that keeps the copy legible is much lighter here than on the dark
   field, and it has to be: there the copy is white and needs the ground taken
   down, here it is the page's own ink at fourteen to one and needs almost
   nothing. At .8 it was painting the lattice out of the half of the header
   the eye actually spends its time in, which left a field that animates where
   nobody is looking. */
.hero-hex.light::before{
  background:linear-gradient(90deg,rgba(255,255,255,.72),rgba(255,255,255,.3) 38%,rgba(255,255,255,0) 64%),
    linear-gradient(180deg,rgba(255,255,255,0) 60%,rgba(255,255,255,.22))}
@media(max-width:860px){.hero-hex.light::before{
  background:linear-gradient(180deg,rgba(255,255,255,0) 30%,rgba(255,255,255,.6))}}
.hero-hex.light .hero-art.has-img .tilt{box-shadow:0 30px 60px -32px rgba(10,36,64,.35)}

/* ===================== product grid =====================
   Category, brand and toolbox pages all answer the same question — what is
   in this grouping — and a bare text list answered it poorly now that there
   is photography. The card carries the shot, the name and the one line the
   client wrote for it, and nothing else: these pages are a way through to a
   product, not a place to read about one. */

.pgrid{display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));gap:1rem}
@media(max-width:980px){.pgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:600px){.pgrid{grid-template-columns:1fr}}

.pg{display:block;position:relative;border:1px solid var(--rule);background:var(--panel);
  transition:border-color var(--dur-1),transform var(--dur-2) var(--ease),
    box-shadow var(--dur-2) var(--ease)}
.pg:hover,.pg:focus-visible{border-color:var(--blue);transform:translateY(-2px);
  box-shadow:0 14px 30px -20px rgba(10,36,64,.45)}
.pgi{display:block;aspect-ratio:3/2;overflow:hidden;background:var(--grey-bg)}
.pgi img{display:block;width:100%;height:100%;object-fit:cover;
  transition:transform .9s var(--ease)}
.pg:hover .pgi img{transform:scale(1.03)}
.pgi.none{display:block;aspect-ratio:3/2;background:
  repeating-linear-gradient(135deg,var(--grey-bg) 0 8px,var(--panel) 8px 16px)}
.pgt{display:block;font-family:var(--d);font-weight:600;font-size:.98rem;
  padding:.9rem 1.05rem .2rem}
/* A partner product's card carries its brand's mark in place of the words.
   Not cap-height matched the way the heading on the product page is: at this
   size that rule sets a Microlyte mark fifteen pixels tall, which reads as a
   smudge. One height for all three instead -- three marks at one height is
   what makes a row of them look chosen rather than pasted.

   2.25rem, because the PainGuard lockup is three tiers deep and its bottom
   tier ("with Lidocaine") is a quarter of the file: below this it is not
   readable, and at this it is exactly as wide as the card allows. The mark
   takes a line of its own and the leftover word ("SAM") the line under it --
   set beside a mark this size the word looked like a caption that had come
   adrift. */
/* max-height, not height. With a fixed height and max-width:100% the card
   clamped the width and kept the height, so between about 960 and 1100 the
   PainGuard lockup was rendering 185x38 where its own ratio is 6.28:1 -- the
   client's logo, squashed, on their own home page. Both axes are bounds and
   both are auto, so the browser keeps the ratio and the mark simply gets
   smaller where the card is narrower. */
.pgt .wordmark{display:block;height:auto;width:auto;
  max-height:2.25rem;max-width:100%}
.pgt .pgw{display:block;margin-top:.3rem}
.pgd{display:block;font-size:.85rem;color:var(--soft);line-height:1.5;
  padding:0 2.2rem .95rem 1.05rem}
.pga{position:absolute;right:1rem;bottom:.85rem;color:var(--blue);opacity:0;
  transition:opacity var(--dur-1),transform var(--dur-2) var(--ease)}
.pg:hover .pga,.pg:focus-within .pga{opacity:1;transform:translateX(3px)}

/* Same tone as the other footer links: the inherited 50% white plus an extra
   fade fell below WCAG AA contrast on the navy footer. */
.fbase .flegal{color:rgba(255,255,255,.78);text-decoration:none;
  border-bottom:1px solid transparent;transition:color var(--dur-1),border-color var(--dur-1)}
.fbase .flegal:hover,.fbase .flegal:focus-visible{color:#fff;border-bottom-color:currentColor}

/* A partner's own mark, beside the line about them. Their logo, so it is
   shown at its own proportions and never recoloured — height is fixed and
   width follows, which is the opposite of how the product grid works. */
.ptnr{display:flex;gap:clamp(1.2rem,4vw,2.6rem);align-items:center;flex-wrap:wrap}
.ptnr img{width:auto;height:46px;flex:none}
.ptnr p{margin:0;font-size:.95rem;color:var(--soft);max-width:56ch;line-height:1.6}
@media(max-width:620px){.ptnr img{height:38px}}

/* A card that opens a document rather than another page: the arrow turns
   down, and the accent goes orange so it reads as a different kind of exit.
   Not ".doc" — that class is already the licensing document row, and it is a
   grid, which silently relaid the card into a single line. */
a.card.isdoc .cart{background:var(--orange)}
a.card.isdoc:hover,a.card.isdoc:focus-visible{border-color:var(--orange)}
a.card.isdoc .carr{color:var(--orange-ink)}

/* ===================== a panel that follows the pointer =====================
   In follow mode the grid's cards stop lighting up individually and a single
   panel moves behind whichever one the pointer is over. Moving one element
   is the whole point: it reads as one object travelling between cards, which
   is something :hover cannot express, because CSS has no way to animate from
   one element's box to another's.

   The cards keep the fill and border they have everywhere else. The panel is
   drawn --hc-pad larger than the card on every side, so what the pointer
   actually reveals is a band around the card rather than the card's own
   background: the resting state stays intact and the hover adds to it. JS
   reads --hc-pad, so the inset lives here with the rest of the geometry. */

.icgrid.follow{position:relative}
.hcfill{--hc-pad:8px;position:absolute;left:0;top:0;z-index:0;opacity:0;
  pointer-events:none;
  background:var(--blue-bg);
  border-radius:0 calc(var(--card-r) + var(--hc-pad)) 0
                 calc(var(--card-r) + var(--hc-pad));
  transition:transform var(--dur-2) var(--ease),width var(--dur-2) var(--ease),
    height var(--dur-2) var(--ease),opacity var(--dur-1)}
.icgrid.follow[data-on] .hcfill{opacity:1}

/* The card sits over the panel, so it needs a stacking context and an opaque
   fill. It keeps its blue border on hover; only the lift goes, because the
   panel underneath would not follow it. */
.icgrid.follow .iccard{position:relative;z-index:1}
.icgrid.follow .iccard:hover,.icgrid.follow a.iccard:focus-visible{
  transform:none;box-shadow:none}

/* Without a pointer there is nothing to follow. */
@media (hover:none),(pointer:coarse){
  .icgrid.follow .hcfill{display:none}
}
@media (prefers-reduced-motion:reduce){
  .hcfill{transition:opacity var(--dur-1)}
}

/* ---------- the header, floating ----------
   .site.float restyles the header the nav already renders into an island. No
   markup changes, so the menus, the drawer and the keyboard order are the
   ones that were already tested.

   It stays sticky rather than fixed. Sticky keeps the header in the flow, so
   it reserves its own band and nothing below has to be padded down to clear
   it -- with fixed, every page would need a top offset and the breadcrumb bar
   would sit underneath the island. The page still slides beneath it on scroll,
   which is the part that reads as floating.

   The island takes the mark's corner, the same one the buttons and the cards
   carry. */
/* How far the island floats clear of the top. Two things need it — the
   island itself and whatever follows the header — so it is a value rather
   than a number typed twice. */
:root{--float-gap:.7rem}
.site.float{background:none;border-bottom:0;top:var(--float-gap);z-index:20}

.site.float .hdr{
  max-width:min(1240px,calc(100% - 1.6rem));margin:0 auto;
  padding:.72rem clamp(.85rem,2vw,1.3rem);
  background:var(--panel);
  border:1px solid var(--rule);
  border-radius:0 var(--card-r) 0 var(--card-r);
  box-shadow:0 6px 20px -18px rgba(10,36,64,.42);
  transition:padding var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out)}

/* Translucency only where the blur behind it actually works. Without the
   filter a see-through bar would just let the page show through and make the
   type hard to read, so the opaque fill above stays the fallback. */
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  /* Glass rather than a tinted bar. Three things do the work and none of
     them is the opacity on its own:

     the blur is wide enough (26px) that whatever is behind arrives as a
     wash of colour rather than as readable shapes, which is what lets the
     fill come down to the high fifties without the type fighting the page;

     the saturation lift makes that wash carry the colour behind it -- over
     the dark honeycomb the island goes faintly blue, over a photograph it
     takes the photograph's cast -- which is the part that reads as glass
     rather than as translucency;

     and the fill is a gradient, brighter along the top edge, with a white
     hairline inset over it. That is the specular line a pane of glass has
     where it catches the light, and without it a blurred rectangle just
     looks out of focus. The matching dark inset along the bottom gives the
     pane a thickness.

     The floor is set by the logo, not by taste. This ran at 72%-60% for a
     while and the orange half of the wordmark measured 1.09:1 against the
     composite over the home hero -- the brand's own colour dissolving into
     its own header. At 92%-86% it is 2.02:1, which is what it was on the
     flat fill this replaced, and the blur and the saturation still do the
     work: the pane carries the colour behind it, it just no longer gives up
     the mark to do so. Everything else clears where it did before -- ink
     11.4:1, --soft 4.98:1, the button's blue 6.1:1. */
  .site.float .hdr{
    background:linear-gradient(to bottom,
      color-mix(in srgb,var(--panel) 92%,transparent),
      color-mix(in srgb,var(--panel) 86%,transparent));
    border-color:color-mix(in srgb,var(--panel) 55%,transparent);
    -webkit-backdrop-filter:saturate(1.9) blur(26px);
    backdrop-filter:saturate(1.9) blur(26px);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb,#fff 72%,transparent),
      inset 0 -1px 0 color-mix(in srgb,var(--ink) 7%,transparent),
      0 8px 26px -18px rgba(10,36,64,.4)}
  /* The open panel is the same pane hanging below, but a much denser one.
     It was opaque, which put a solid white sheet under a glass bar; at the
     bar's own 60% the page reads through a list of product names as a
     coloured smudge, and the menu's descriptions -- --soft, and small --
     fall to 4.0:1 over the home hero. At 90% the blur still tints it and
     those descriptions measure 5.4:1, better than the 5.0 they had on the
     old flat fill. A bar you see through and a menu you do not is the way
     round these want to be anyway. */
  .site.float .mega{
    background:linear-gradient(to bottom,
      color-mix(in srgb,var(--panel) 94%,transparent),
      color-mix(in srgb,var(--panel) 90%,transparent));
    -webkit-backdrop-filter:saturate(1.9) blur(26px);
    backdrop-filter:saturate(1.9) blur(26px)}

  /* Contact took the ink here and the distributor button was filled, both
     only because the 60% fill had dropped them to 2.7:1 and 3.3:1. At 86%
     they are back to the 4.98 and 6.1 they were designed against, so the
     compensations come out and the bar is its own design again. */
}

/* Once the page is under way the shadow deepens, so the island reads as
   lifted off moving content rather than resting on a static page.

   Only the shadow. A sticky header is still in the flow, so shrinking it on
   scroll shortens the band it reserves and everything below jumps up by that
   much at the moment the threshold is crossed -- a lurch the reader sees, in
   exchange for a few pixels. The island keeps one height. */
.site.float.past .hdr{box-shadow:0 10px 26px -20px rgba(10,36,64,.55)}
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  /* the deepened shadow has to restate the two insets, or scrolling past the
     threshold drops the specular edge */
  .site.float.past .hdr{box-shadow:
    inset 0 1px 0 color-mix(in srgb,#fff 72%,transparent),
    inset 0 -1px 0 color-mix(in srgb,var(--ink) 7%,transparent),
    0 14px 34px -22px rgba(10,36,64,.5)}
}
.site.float .brand{--logo-h:42px}

/* Flush, an opening mega grows the header and pushes the page down. Under an
   island that would tear its bottom edge open, so here the panel leaves the
   flow and hangs below as a second island. */
.site.float .mega{position:absolute;left:0;right:0;
  top:calc(100% + .5rem);
  max-width:min(1240px,calc(100% - 1.6rem));margin:0 auto;
  border-top:0;border-radius:0 var(--card-r) 0 var(--card-r)}
.site.float .mega > .inner{max-width:none}
/* The ring is a shadow rather than a border: a border would still paint its
   two hairlines while the panel is collapsed to nothing. */
.site.float .mega.open{
  box-shadow:0 0 0 1px var(--rule),0 26px 46px -30px rgba(10,36,64,.55)}

/* The breadcrumb bar gives up its own fill and rule and lets the page carry
   it. Written with + first, which matched nothing: the mobile drawer sits
   between the header and the breadcrumbs in the markup, so the two are not
   adjacent siblings. The strip stayed white above a hero on the page's tint
   and drew exactly the seam this rule exists to remove — invisible on the
   one page it was checked against, which has no breadcrumbs at all. */
.site.float ~ .crumbs{background:none;border-bottom:0}

/* A dark header should start at the top of the page, not two thirds of the
   way down it. The breadcrumbs sit between the floating island and the hero,
   so on a dark hero the page began with a strip of the page's own light
   ground, then the crumbs, then the dark -- a seam at about the height of
   the header, behind it.
   
   The crumbs take the hero's own top colour and are pulled up under the
   island, paying the height back as padding so nothing below them moves.
   The hero's gradient starts on that same value and holds it to 22%, so the
   join between the two is a join between one colour and itself. */
@supports selector(:has(*)) {
  /* Both hex grounds, each on its own top value. The light one is only six
     values off the page's own tint, but the join was still a line. */
  .crumbs:has(+ main > .hero.hero-hex){
    margin-top:calc(-1 * (var(--hdr-h,4rem) + var(--float-gap)));
    padding-top:calc(var(--hdr-h,4rem) + var(--float-gap))}
  .crumbs:has(+ main > .hero.hero-hex.light){background:#FBFCFD}
  .crumbs:has(+ main > .hero.hero-hex.dark){background:#184A8C}
}
/* Matching the ground was not enough, because the hero puts a scrim over its
   own ground and the crumbs had none. On a wide screen that scrim is a
   left-to-right wash -- .7 of #081A32 at the left edge -- so the top of the
   hero came out rgb(13,40,77) against crumbs of rgb(24,74,140) directly
   above it. That step, across the left two thirds of the page, is the line.
   The crumbs take the same wash.
   Below the breakpoint the hero's scrim runs top to bottom and is at zero
   alpha where the crumbs meet it, so there it is right to have none. */
@supports selector(:has(*)) {
  @media(min-width:861px){
    .crumbs:has(+ main > .hero.hero-hex.dark){
      background:
        linear-gradient(90deg,rgba(8,26,50,.7),rgba(8,26,50,.35) 34%,rgba(8,26,50,0) 62%),
        #184A8C}
    .crumbs:has(+ main > .hero.hero-hex.light){
      background:
        linear-gradient(90deg,rgba(255,255,255,.72),rgba(255,255,255,.3) 38%,rgba(255,255,255,0) 64%),
        #FBFCFD}
  }
  .crumbs:has(+ main > .hero.hero-hex.dark) a{color:rgba(255,255,255,.72)}
  .crumbs:has(+ main > .hero.hero-hex.dark) a:hover{color:#fff}
  .crumbs:has(+ main > .hero.hero-hex.dark) span{color:rgba(255,255,255,.38)}
  .crumbs:has(+ main > .hero.hero-hex.dark) em{color:rgba(255,255,255,.55)}
}
/* Sticky keeps the header in the flow, but `top` slides what you see down
   by the float gap — so the flow ends higher than the island looks like it
   does, and the breadcrumbs were starting 7.6px behind its bottom edge. The
   padding has to clear that offset before it can be breathing room. */
.site.float ~ .crumbs .wrap{padding-top:calc(var(--float-gap) + 1.3rem)}

@media(max-width:820px){
  /* On the root, not on the header: the hero that runs up under the island
     reads the same value, and scoping it to .site.float would leave the two
     disagreeing by a quarter of a rem on a phone. */
  :root{--float-gap:.45rem}
  .site.float .hdr{max-width:calc(100% - 1rem);padding:.6rem .8rem}
  /* The desktop 42px is 210px of wordmark -- over half a 375px island once
     the padding and the burger have taken their share. */
  .site.float .brand{--logo-h:36px}
}

/* ---------- mobile navigation ----------
   Below 860px the mega panels cannot work: they need hover, and they need
   horizontal room for two panes. They are switched off entirely and replaced
   by a drawer built from the same P / GROUPS data, so the two cannot drift.
   Everything reachable on desktop is reachable here. */
.burger{display:none;margin-left:auto;flex:none;width:44px;height:44px;background:none;border:0;
  cursor:pointer;position:relative;color:var(--ink)}
.burger span{position:absolute;left:11px;width:22px;height:1.5px;background:currentColor;
  transition:transform .3s var(--ease),opacity .2s}
.burger span:nth-child(1){top:15px}
.burger span:nth-child(2){top:21px}
.burger span:nth-child(3){top:27px}
.burger[aria-expanded="true"] span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
.burger:focus-visible{outline:2px solid var(--blue);outline-offset:-4px}

/* The consent banner uses 10000. An opened navigation is the active layer and
   must cover both the page and that banner on small screens. */
.scrim{position:fixed;inset:0;z-index:10010;background:rgba(10,36,64,.5);opacity:0;
  transition:opacity .3s var(--ease)}
.scrim.on{opacity:1}
.drawer{position:fixed;top:0;right:0;bottom:0;z-index:10020;width:min(88vw,380px);
  background:var(--panel);border-left:1px solid var(--rule);display:flex;flex-direction:column;
  transform:translateX(calc(100% + 64px));visibility:hidden;pointer-events:none;
  transition:transform .34s var(--ease),visibility 0s linear .34s;
  box-shadow:-24px 0 60px -30px rgba(10,36,64,.45)}
.drawer.on{transform:none;visibility:visible;pointer-events:auto;transition-delay:0s}
.drawer[hidden]{display:none}
.dtop{display:flex;align-items:center;justify-content:space-between;flex:none;
  padding:1rem 1rem 1rem 1.25rem;border-bottom:1px solid var(--rule)}
.dtop .lbl{font-size:.76rem;letter-spacing:.004em;color:var(--faint)}
.dclose{width:44px;height:44px;background:none;border:0;cursor:pointer;color:var(--ink);
  font-size:1.35rem;line-height:1}
.dclose:focus-visible{outline:2px solid var(--blue);outline-offset:-4px}
.dnav{flex:1 1 auto;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}

.drow{width:100%;display:flex;align-items:center;gap:.6rem;text-align:left;font:inherit;
  background:none;border:0;border-bottom:1px solid var(--rule2);color:var(--ink);cursor:pointer;
  padding:0 1.25rem;min-height:52px}
.drow .t{flex:1 1 auto;font-size:.92rem;letter-spacing:.004em}
.drow .car{flex:none;width:8px;height:8px;border-right:1.5px solid var(--faint);
  border-bottom:1.5px solid var(--faint);transform:rotate(45deg);transition:transform .3s var(--ease)}
.drow[aria-expanded="true"]{color:var(--blue)}
.drow[aria-expanded="true"] .car{transform:rotate(-135deg);border-color:var(--blue)}
.drow:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
.dsub{background:var(--paper);border-bottom:1px solid var(--rule2)}
.dgo,.dleaf{width:100%;text-align:left;font:inherit;background:none;border:0;cursor:pointer;
  color:var(--soft);padding:.72rem 1.25rem .72rem 1.6rem;min-height:44px;display:block;font-size:.88rem}
.dgo{color:var(--blue);font-weight:600;border-bottom:1px solid var(--rule2)}
.dleaf .d{display:block;font-size:.76rem;color:var(--faint);margin-top:.12rem;line-height:1.45}
.dgo:focus-visible,.dleaf:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
/* second level — Products' four browse paths */
.dpath > .drow{padding-left:1.6rem;min-height:46px;border-bottom:1px solid var(--rule2)}
.dpath > .drow .t{font-size:.7rem;letter-spacing:.13em;color:var(--soft)}
.dpath .dleaf{padding-left:2.2rem}
.dfoot{flex:none;border-top:1px solid var(--rule);padding:1rem 1.25rem 1.25rem;
  display:grid;gap:.55rem;background:var(--panel)}
.dfoot .portal{border:1px solid var(--blue);color:var(--blue);background:none;font:inherit;
  font-size:.82rem;letter-spacing:.004em;padding:.7rem;cursor:pointer;
  min-height:44px}
.dfoot .plain{background:none;border:0;font:inherit;font-size:.86rem;letter-spacing:.004em;
  color:var(--soft);cursor:pointer;padding:.5rem 0;text-align:left;
  min-height:44px}
/* 44px minimum — these are tap targets on a phone, not desktop footnotes. */
.dfoot a{font-size:.8rem;color:var(--soft);text-decoration:none;display:flex;align-items:center;
  min-height:44px;border-top:1px solid var(--rule2)}
.dfoot a:hover{color:var(--blue)}

/* 1080, not 860. The horizontal nav does not shrink -- it wraps -- so the
   only widths it may appear at are the widths it fits on one row. With four
   items it needed 1024 and was already dropping "Reimbursement" onto a second
   row below that; the fifth item the client asked for ("Add Clinical Studies
   to the main navigation bar") pushes the requirement to 1055. Measured, not
   guessed: one row from 1060 up, two rows at 1050. 1080 is that number with
   room for a label to grow.

   Between 861 and 1080 the header was therefore two rows tall with one
   orphaned item centred under the others, which is what this fixes as well
   as making room for the new item. */
@media(max-width:1080px){
  .mainnav,.util{display:none}
  .mega{display:none}
  .burger{display:block}
  .hdr{gap:.5rem;padding-top:.85rem;padding-bottom:.85rem}
}
@media(min-width:1081px){
  .drawer,.scrim{display:none}
}
/* Landscape phones and short windows: the pinned footer would crowd out the
   navigation, which is the point of the drawer. Drop the contact lines — they
   are on the Contact page — and keep the two buttons. */
@media(max-height:560px){
  .dfoot a{display:none}
  .dfoot{padding-bottom:.75rem}
}
body.locked{overflow:hidden}

/* Reduced motion: the guard has to cover animation as well as transition,
   because the motion layer in build-site.py uses keyframes for the hero.
   Those animations end at the element's natural resting state, so switching
   them off leaves the page correct rather than blank. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    transition:none!important;
    animation:none!important;
    scroll-behavior:auto!important}
}


/* ---------- typeface assignment ----------
   Display cut for headings, eyebrows and navigation labels; the Text cut is
   the body default. This block sits last on purpose: the button rules above
   use `font:inherit`, which resets font-family, so an earlier declaration
   would lose the cascade even at equal specificity.

   Every uppercase, letterspaced control takes the Display cut — the main nav
   already did, so the "Go to" buttons, the portal buttons and the menu CTAs
   had to as well. They were split between the two faces: .prail button was
   meant for the tabs but also caught .fbtn, so the Products button used
   Display while the identical buttons in the other three menus used Text. */
h1,h3,.gl,.children h3,
.mainnav > a,.util a,.crumb,.crumb button,
.drow .t,.dgo,.dclose,.dtop .lbl,.dfoot .portal,.dfoot .plain,
.kid .t,.row .nm,.row .kind,.step .n,
.ptab,.tn,.fbtn,.ppane .ph,.phgo,
.pfoot .fl,.pfoot .cta,.themesw button{font-family:var(--d)}

/* The logo's cross, rebuilt symmetric — see logoparts.py. Links take
   a ringed variant so the affordance the pointer hand carries is not
   simply thrown away, and text fields keep the native I-beam. */
body{cursor:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2226%22%20height%3D%2216%22%20viewBox%3D%22-19.63%20-11.91%2039.26%2023.82%22%3E%3Cpath%20d%3D%22M-3.665%2C-10.510%20h7.330%20v6.845%20h14.565%20v7.330%20h-14.565%20v6.845%20h-7.330%20v-6.845%20h-14.565%20v-7.330%20h14.565%20z%22%20fill%3D%22%23f27f24%22%2F%3E%3C%2Fsvg%3E") 13 8,auto}
a,button,summary,label,.btn,[role="button"]{cursor:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%22-6.27%20-6.27%2012.53%2012.53%22%3E%3Crect%20x%3D%22-3.67%22%20y%3D%22-3.67%22%20width%3D%227.33%22%20height%3D%227.33%22%20fill%3D%22%23f27f24%22%2F%3E%3C%2Fsvg%3E") 6 6,pointer}
input,textarea,select,[contenteditable]{cursor:auto}
input[type="text"],input[type="email"],input[type="tel"],input:not([type]),textarea{cursor:text}
@media (hover:none),(pointer:coarse){
  body,a,button,summary,label,.btn,[role="button"]{cursor:auto}
}


/* ===================== hero honeycomb =====================
   The lattice sits between the hero's panel and its copy: absolutely
   positioned, inert to the pointer, and masked away before it reaches the
   headline. Everything that moves is a transform or an opacity, so nothing
   here forces layout.

   Two stacked <svg> copies rather than one: the resting lattice, and a
   saturated one revealed through a radial mask that follows the pointer.
   The mask sits on the <svg> box, where a CSS pixel is a CSS pixel, while
   the parallax sits on the <g> inside it — so the highlight tracks the
   cursor exactly instead of dragging along with the plane. */
.hc{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0;
  -webkit-mask-image:linear-gradient(to top,#000 0 44%,rgba(0,0,0,.72) 74%,transparent 99%);
  mask-image:linear-gradient(to top,#000 0 44%,rgba(0,0,0,.72) 74%,transparent 99%)}
.hero-in{position:relative;z-index:1}

/* The copy sits in a clearing. Body text over a lattice measures fine on
   average and fails where a line crosses a glyph, which is the measurement
   that matters — so the ground under the copy is lifted back towards white.
   The gradient is deliberately enormous and soft-edged, and runs off the left
   of the hero: an earlier, tighter version lit a visible blob behind the
   headline, which read as a smudge rather than as light.

   EVERY ONE OF THESE GRADIENTS MUST REACH ZERO INSIDE ITS OWN BOX. A radial
   gradient's vertical radius is a percentage of the box's height, so an
   `ellipse 64% 80%` is already past the box's top and bottom edge at
   0.5/0.80 = 62.5% of its radius -- and a stop list still at .29 alpha there
   gets cut off dead straight by that edge. On a resting hero nothing shows
   it. The moment the pointer lights the lattice underneath, the cut reads as
   a band ruled across the width of the page. So the last stop of each of
   these sits at or inside 0.5 / (the vertical radius), and that is the
   number to keep true if any of them is ever retuned. */
.hero.has-bg .hero-txt{position:relative}
.hero.has-bg .hero-txt::before{content:"";position:absolute;z-index:-1;
  inset:-5rem -9rem -5rem -60vw;pointer-events:none;
  background:radial-gradient(ellipse 60% 76% at 38% 50%,
    #fff 0 14%,rgba(255,255,255,.93) 36%,rgba(255,255,255,.55) 50%,
    rgba(255,255,255,0) 65%)}

.hc-layer{position:absolute;inset:0;width:100%;height:100%;display:block}
.hc-base use{stroke:url(#hc-ink)}
.hc-glow use{stroke:url(#hc-lit)}

/* the plane drifts a few units against the pointer — enough to feel like
   depth, not enough to notice as movement */
.hc-plane{transform:translate(var(--px,0px),var(--py,0px));
  transition:transform 1.2s var(--ease-out)}
.hc.lit .hc-plane{transition-duration:.35s}

.hc-glow{opacity:0;transition:opacity .55s var(--ease-out);
  -webkit-mask-image:radial-gradient(circle 300px at var(--hx,50%) var(--hy,60%),
    #000 0 34%,rgba(0,0,0,.55) 62%,transparent 88%);
  mask-image:radial-gradient(circle 300px at var(--hx,50%) var(--hy,60%),
    #000 0 34%,rgba(0,0,0,.55) 62%,transparent 88%)}
.hc.lit .hc-glow{opacity:1;transition-duration:.3s}

/* A pool of light under the mesh. The lattice on its own cannot signal "lit"
   on a white page — a darker line is the only lever an outline has there, and
   by itself it reads as a printing fault rather than as light. The wash gives
   the darker cells somewhere to sit. ::before is the first child in the box
   tree, so it lands under both lattices without needing a z-index. */
.hc::before{content:"";position:absolute;inset:0;opacity:0;
  transition:opacity .55s var(--ease-out);
  background:radial-gradient(circle 340px at var(--hx,50%) var(--hy,60%),
    rgba(13,78,159,.13) 0,rgba(13,78,159,.06) 46%,transparent 78%)}
.hc.lit::before{opacity:1;transition-duration:.3s}

/* cells breathing, and particulate catching the light */
.hc-cells polygon{fill:var(--blue);opacity:0;
  animation:hc-breathe var(--d,20s) ease-in-out var(--t,0s) infinite}
.hc-cells polygon.o{fill:var(--orange)}
.hc-dots circle{fill:var(--ink);opacity:.18}
.hc-dots circle.t{animation:hc-twinkle 9s ease-in-out var(--t,0s) infinite}
@keyframes hc-breathe{0%,100%{opacity:0}48%{opacity:.10}}
@keyframes hc-twinkle{0%,100%{opacity:.09}50%{opacity:.46}}

/* On a phone the hero stacks and `slice` crops the plane hard, which
   magnifies it; back it off so it stays a texture. */
@media(max-width:860px){
  .hc{-webkit-mask-image:linear-gradient(to top,#000 0 26%,transparent 84%);
    mask-image:linear-gradient(to top,#000 0 26%,transparent 84%);opacity:.6}
  .hero.has-bg .hero-txt::before{inset:-3rem -50vw;
    background:radial-gradient(ellipse 70% 62% at 50% 50%,
      rgba(255,255,255,.92) 0,rgba(255,255,255,.72) 50%,rgba(255,255,255,0) 79%)}
}

@media(prefers-reduced-motion:reduce){
  .hc-cells polygon,.hc-dots circle.t{animation:none}
  .hc-cells polygon{opacity:.05}
  .hc-plane{transition:none}
}

/* ===================== the lattice on ink =====================
   The same plane on the footer's own colour, so the page is held between two
   ends of one ground instead of running off the bottom of a white sheet.

   Everything below is an override of a value the light version sets. The
   geometry, the mask, the parallax, the breathing cells and the script are
   untouched: this is the figure inverted, not a second figure. */
.hero.has-bg.onink{background:var(--ink);color:#fff;border-bottom-color:var(--ink)}
.hero.has-bg.onink h1{color:#fff}
.hero.has-bg.onink .lead{color:rgba(255,255,255,.82)}
.hero.has-bg.onink .btn{border-color:#fff;color:#fff}
.hero.has-bg.onink .btn::before{background:#fff}
.hero.has-bg.onink .btn:hover,.hero.has-bg.onink .btn:focus-visible{color:var(--blue)}

/* A flat light stroke rather than the two-colour gradient. On ink the blue
   end of that gradient falls to nothing while the orange end survives, which
   tips the whole plane orange -- the gradient reads as colour on white and as
   a fault on navy. The lit lattice keeps the brand pair, since it only ever
   appears inside the pointer's mask where it has the contrast to carry it. */
.onink .hc-base use{stroke:rgba(255,255,255,.20)}
.onink .hc-dots circle{fill:#fff;opacity:.24}

/* The clearing under the copy is a pool of the ground, not of white. Same
   shape, same softness, inverted value. */
.hero.has-bg.onink .hero-txt::before{
  background:radial-gradient(ellipse 60% 76% at 38% 50%,
    #0A2440 0 14%,rgba(10,36,64,.93) 36%,rgba(10,36,64,.55) 50%,
    rgba(10,36,64,0) 65%)}
/* Centred, the pool has to be centred too. It is struck at 38% and runs
   60vw off the left edge, which is right under a left-hand column of copy
   and wrong under a centred one: solid ink over a lit mesh, hard against
   the left of the hero, reading as a dark blotch rather than as a clearing.
   Here it sits under the middle, stays inside the hero, and is a veil
   rather than a fill -- white type on the mesh does not need an opaque
   ground behind it, only a quieter one. */
.hero.has-bg.onink.mid .hero-txt::before{
  inset:-3.5rem -6rem -3.5rem -6rem;
  background:radial-gradient(ellipse 64% 80% at 50% 50%,
    rgba(10,36,64,.70) 0 18%,rgba(10,36,64,.46) 38%,
    rgba(10,36,64,.20) 50%,rgba(10,36,64,0) 62%)}
/* The pool of light that sits under the mesh goes from ink-blue to a lift:
   on navy, light is the only lever an outline has. */
.onink .hc::before{
  background:radial-gradient(circle 340px at var(--hx,50%) var(--hy,60%),
    rgba(140,186,255,.17) 0,rgba(140,186,255,.07) 46%,transparent 78%)}
.onink .hc-cells polygon{fill:#8CBAFF}

/* The island floats on the hero rather than on a white shelf above it: the
   hero is pulled up under the header and pays the height back as padding, so
   nothing below it moves. The header is sticky and keeps its own stacking
   order, so it stays over the top.

   --hdr-h is published by the script, because the header's height is the sum
   of a logo, two paddings and a border and any of the three can change. The
   fallback is the height it has today, so the page is right before the
   script runs and stays right if it never does. */
.hero.has-bg.onink{
  margin-top:calc(-1 * (var(--hdr-h,4rem) + var(--float-gap,.7rem)));
  padding-top:calc(var(--hdr-h,4rem) + var(--float-gap,.7rem)
    + clamp(2.6rem,6vw,4.6rem))}

@media(max-width:860px){
  /* the gap itself changes at this width; the sum does not need to */
  .hero.has-bg.onink{margin-top:calc(-1 * (var(--hdr-h,4rem) + var(--float-gap,.45rem)));
    padding-top:calc(var(--hdr-h,4rem) + var(--float-gap,.45rem)
      + clamp(2.6rem,6vw,4.6rem))}
  .hero.has-bg.onink .hero-txt::before{inset:-3rem -50vw;
    background:radial-gradient(ellipse 70% 62% at 50% 50%,
      rgba(10,36,64,.94) 0,rgba(10,36,64,.74) 50%,rgba(10,36,64,0) 79%)}
}


/* ---- the hex world map, on Why EmeraNova ------------------------------- */
.wmap{margin:2.6rem 0 0}
.wmap svg{display:block;width:100%;height:auto}
.wm-land use{fill:var(--blue);opacity:.13}
.wm-lit use{fill:var(--orange);opacity:0;
  animation:wmpulse 9s var(--ease) infinite;animation-delay:var(--t)}
@keyframes wmpulse{
  0%,100%{opacity:0}
  8%{opacity:.9}
  26%{opacity:.18}
  40%{opacity:0}
}
:root[data-theme="dark"] .wm-land use{opacity:.22}
@media (prefers-reduced-motion:reduce){
  .wm-lit use{animation:none;opacity:.55}
}


/* ---- the stand, on a meeting page ------------------------------------- */
.booth{margin:2.4rem 0 0;position:relative;overflow:hidden;
  border:1px solid var(--rule);background:var(--panel);
  aspect-ratio:16/9}
section.band.alt .booth{background:var(--paper)}
.booth svg{display:block;width:100%;height:100%}
/* Every layer dollies forward from the vanishing point, the near ones
   further than the far ones, which is what a step into the room does to
   what you are looking at. */
.bth-far,.bth-mid,.bth-near{transform-origin:50% 48.5%;
  transform:translate(var(--bx,0px),var(--by,0px)) scale(var(--s,1));
  transition:transform .9s var(--ease-out)}
.bth-far{--s:1;animation:bth-dolly 22s ease-in-out infinite}
.bth-mid{--s:1;animation:bth-dolly-m 22s ease-in-out infinite}
.bth-near{--s:1;animation:bth-dolly-n 22s ease-in-out infinite}
@keyframes bth-dolly{0%,100%{--s:1}50%{--s:1.035}}
@keyframes bth-dolly-m{0%,100%{--s:1}50%{--s:1.06}}
@keyframes bth-dolly-n{0%,100%{--s:1}50%{--s:1.10}}
/* the room */
/* Opaque, all of it. Translucent volumes in a perspective drawing read as
   an x-ray of a room rather than as a room. */
.bth-w{fill:var(--rule2);stroke:var(--rule);stroke-width:1}
.bth-f{fill:var(--blue-bg);stroke:var(--rule);stroke-width:1}
.bth-s{fill:var(--panel);stroke:var(--rule);stroke-width:1}
.bth-l{stroke:color-mix(in srgb,var(--blue) 17%,transparent);stroke-width:1;fill:none}
.bth-t{stroke:color-mix(in srgb,var(--blue) 30%,transparent);stroke-width:1.4;fill:none}
.bth-h{fill:none;stroke:var(--blue);stroke-width:.9;opacity:.17}
.bth-screen{fill:color-mix(in srgb,var(--blue) 22%,var(--panel));
  stroke:var(--blue);stroke-width:1.2}
.bth-mk{opacity:.9}
.bth-sd{fill:var(--panel);opacity:.25;
  animation:bth-scr 6s ease-in-out infinite;animation-delay:var(--t)}
@keyframes bth-scr{0%,100%{opacity:.12}50%{opacity:.62}}
/* the furniture: a lit top, a face in shadow, a side between the two */
.bth-top{fill:var(--panel);stroke:var(--blue);stroke-width:1.1}
.bth-front{fill:var(--blue-bg);stroke:var(--blue);stroke-width:1.1}
.bth-side{fill:color-mix(in srgb,var(--blue-bg) 62%,var(--panel));
  stroke:var(--blue);stroke-width:1}
.bth-o.bth-top{fill:color-mix(in srgb,var(--orange) 26%,var(--panel))}
.bth-o.bth-front{fill:color-mix(in srgb,var(--orange) 42%,var(--panel))}
.bth-o.bth-side{fill:color-mix(in srgb,var(--orange) 32%,var(--panel))}
.bth-o polygon{stroke:var(--orange-ink);stroke-width:1}
/* the session: seats, a speaker, and a chart on the screen */
.bth-seat.bth-top{fill:color-mix(in srgb,var(--blue-bg) 70%,var(--panel))}
.bth-seat.bth-front{fill:color-mix(in srgb,var(--blue-bg) 88%,var(--panel))}
.bth-seat.bth-side{fill:color-mix(in srgb,var(--blue-bg) 50%,var(--panel))}
.bth-seat polygon{stroke:color-mix(in srgb,var(--blue) 42%,transparent);stroke-width:.9}
.bth-fig{fill:var(--orange);opacity:.55;stroke:var(--orange-ink);stroke-width:1}
.bth-chart{fill:none;stroke:var(--panel);stroke-width:2.2;opacity:.85;
  stroke-linecap:round;stroke-linejoin:round}
@media (prefers-reduced-motion:reduce){
  .bth-far,.bth-mid,.bth-near,.bth-sd{animation:none;transition:none}
}


/* ---- hero art: the membrane specimen ---- */
.ha{display:block;width:100%;height:100%}
/* the art slot when it holds a drawing rather than a photograph:
   no frame, no plate, no orange rule under it — those belong to the
   photograph and read as a stray border around a figure */
.hero-art.art{aspect-ratio:4/3;border:none;background:none;padding:0;
  display:block;position:relative}
/* the placeholder's dashed rule is excluded for .art in build_site.PAGE_CSS,
   where the rest of that condition lives; cancelling it from here lost on
   specificity */
@media(max-width:860px){.hero-art.art{aspect-ratio:16/10}}
.ha-sheet{stroke:none}
.ha-cast{fill:#0A2440;opacity:.30}
.ha-sheen{stroke:none;pointer-events:none}
.ha-hem{fill:none;stroke:#0A2440;stroke-width:1.6;opacity:.55}
.ha-thread path{fill:none;stroke:#0A2440;vector-effect:non-scaling-stroke}
.ha-dot circle{fill:#0A2440}
.ha-cone{fill:#0D4E9F;opacity:.10}
.ha-spot{fill:none;stroke:#0D4E9F;stroke-width:1.4;opacity:.75}
.ha-ring{fill:none;stroke:#0D4E9F;stroke-width:2;opacity:.7}

/* ---- hero art: the carton ----
   Everything is in the SVG's own coordinates, so the box and what is in it
   scale as one object however the slot is shaped. Stacking order is document
   order: flaps and interior, then the photographs, then the face over them. */
.bx{position:absolute;inset:0;perspective:900px}
/* The whole drawing turns as one piece. It is already in a three-quarter
   projection, so the pointer only nudges it — a wide swing would fight the
   perspective that is drawn into the geometry and the box would appear to
   change shape rather than to turn. */
.bx-stage{width:100%;height:100%;
  transform:rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));
  transition:transform .9s var(--ease-out)}
.bx.live .bx-stage{transition-duration:.12s}
.bx svg{width:100%;height:100%;display:block;overflow:visible}
/* Faces take their gradients from the markup, where the geometry is; what is
   left here is the board's cut edge, which is one value everywhere it shows,
   and the white frame round a photograph. */
.bx-edge{fill:#3E93DD}
.bx-crease{fill:#0A3A6E;opacity:.55}
.bx-rim{fill:#2D7FCB}
.bx-fr{fill:#fff}
/* 4.6 units came out at about 11px on the page, which is small type set in
   SVG -- no hinting, grey antialiasing -- and it read soft next to the HTML
   around it. The frame is 68 units wide and the longest name, Membrane
   Wrap(TM), measured 40.3 at 4.6, so there was room to go up. At 5.6 it is
   about 13.5px and 49 units wide, still well inside the card, and the
   negative letter-spacing that was squeezing it can go. */
.bx-cap{fill:#0A2440;font-family:var(--d);font-size:5.6px;font-weight:600;
  text-anchor:middle;opacity:0;
  transition:opacity .3s var(--ease-out)}
.bx:hover .bx-cap{opacity:1;transition-delay:var(--d)}

/* transform-box keeps each card turning about its own middle rather than the
   SVG's origin, which is the difference between a fan and a slingshot. */
.bx-card{transform-box:fill-box;transform-origin:center;
  transform:translate(var(--rx),var(--ry)) scale(.9);
  /* The shadow belongs to a card that is out of the box: painted at rest it
     would be the one part of a hidden card that is not hidden, because a
     filter draws outside its element and three shadows pooled under the
     carton's bottom edge.
     So the filter is carried at rest and the shadow's colour is transparent.
     Nothing is painted, and the browser has the filter surface ready before
     the card moves. Adding the filter on hover instead meant building that
     surface for a group holding a photograph and a line of text at the exact
     moment both started moving, and for one frame they were drawn from a
     half-made raster -- the flicker Stacy saw on the products page. */
  transition:transform .62s var(--ease-out) var(--d),
             filter .62s var(--ease-out) var(--d)}
.bx-shade{filter:drop-shadow(0 6px 10px rgba(2,10,24,0))}
.bx:hover .bx-card{transform:translate(0,0) rotate(var(--r))}
.bx:hover .bx-shade{filter:drop-shadow(0 6px 10px rgba(2,10,24,.55))}

/* Without a pointer nothing can hover, so the box is simply open. */
@media (hover:none),(pointer:coarse){
  .bx-card{transform:translate(0,0) rotate(var(--r))}
  .bx-shade{filter:drop-shadow(0 6px 10px rgba(2,10,24,.55))}
  .bx-cap{opacity:1}
}
@media (prefers-reduced-motion:reduce){
  .bx-card{transform:translate(0,0) rotate(var(--r))}
  .bx-shade{filter:drop-shadow(0 6px 10px rgba(2,10,24,.55))}
  .bx-cap{opacity:1}
}

/* ---- hero art: the mark in depth ---- */
.ha-ch{display:grid;place-items:center;perspective:820px}
.ha-stage{position:relative;width:76%;aspect-ratio:1.45;transform-style:preserve-3d;
  transform:rotateX(var(--rx,9deg)) rotateY(var(--ry,-17deg));
  transition:transform .9s var(--ease-out)}
.ha-ch.live .ha-stage{transition-duration:.12s}
.ha-link,.ha-cross{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.ha-link{transform:translateZ(calc(var(--i) * 32px));
  filter:drop-shadow(-5px 4px 6px rgba(10,36,64,.26))}
.ha-cross{transform:translateZ(72px)}
@media(prefers-reduced-motion:reduce){.ha-stage{transition:none}}

/* On the dark hero the chain is the reversed mark: the links go white, the
   way the header's own lockup does, because the brand blue on the brand navy
   is two values of one hue and the links stop reading as shapes. The cross
   keeps the orange — it is the only warm thing on that ground and it carries
   the whole figure. A fill in CSS beats the one in the markup, so nothing
   here has to be threaded through the renderer.

   The drop shadow goes the other way too: a dark shadow under a light object
   on a dark ground does nothing, so the links throw a darker navy instead. */
.onink .ha-link path{fill:#fff}
.onink .ha-link{filter:drop-shadow(-5px 4px 7px rgba(3,14,30,.55))}
.onink .ha-cone{fill:#8CBAFF;opacity:.14}
.onink .ha-spot,.onink .ha-ring{stroke:#8CBAFF}


/* ===================== Display labels at 500 =====================
   The small interface labels set in the Display cut — navigation, buttons,
   breadcrumbs, the mega menu and the drawer — carry 500. 600 was
   tried first and read too heavy in the header at these sizes; 500 is the
   Medium cut, and both faces in the kit have it, so nothing here can fall
   back the way a missing weight would.

   Headings are deliberately not in this list. h1 is set at 400 with a 700
   span inside it, and that pairing is the headline treatment on every page —
   lifting the base to 600 would leave six points of difference against the
   700 and the emphasis would stop reading as emphasis.

   This block is appended last. The nav's controls use `font:inherit`, which
   resets weight along with family, so the same reasoning that puts the
   typeface assignment at the end applies here: an earlier declaration would
   lose the cascade at equal specificity.

   `.plain` is scoped to `.dfoot` and not listed bare: the icon grid's own
   modifier is also called `plain`, and an unscoped rule set the weight on
   that whole grid, which then inherited down onto card text set in the Text
   cut — a face with no 600 at all. */
.mainnav > a,.util a,.crumb,.crumb a,
.drow .t,.dgo,.dtop .lbl,.dfoot .portal,.dfoot .plain,
.kid .t,.row .nm,.row .kind,.step .n,
.ptab,.tn,.fbtn,.ppane .ph,.phgo,
.pfoot .fl,.pfoot .cta,.themesw button,
.btn,.cta,.portal,.sn,.tc{font-weight:500}
