/* Tigremed Pharma
   One family (Hanken Grotesk, variable weight) throughout the site.
   Red is always the logo red: brand surfaces (top bar, reach map) and actions. */

:root {
  --paper: #ffffff;
  --shelf: #f1f2f4;
  --rule: #dadde2;
  --ink: #231f20;
  --slate: #59616b;
  --red: #cd202d; /* the logo red, from Tigremed_final_logo.svg; the only red on the page */
  --on-red: #ffffff;
  --on-red-muted: #fbe8e9; /* 4.6:1 on --red */
  --on-red-rule: rgba(255, 255, 255, 0.3);

  --font: "Hanken Grotesk", "Helvetica Neue", Arial, sans-serif;

  /* Type weights. Every font-weight in this file reads one of these tokens, named
     for the weight it carries today, so the whole site can change weight from one
     place. The light set below is the J&J look: regular-weight headlines and
     medium-weight labels. It applies when the page carries data-type="light",
     which build.mjs writes from jnjLight in src/_data/site.mjs. */
  --fw-800: 800;
  --fw-700: 700;
  --fw-650: 650;
  --fw-620: 620;
  --fw-600: 600;
  --fw-580: 580;
  --fw-560: 560;
  --fw-550: 550;
  --fw-500: 500;
  --fw-400: 400;

  /* Bold Hanken Grotesk sets "Powering life together." 10.15 times its font size
     wide. At 0.0965 of the logo's width the tagline falls about 2% short of it,
     and justification spreads it the rest of the way. Re-measure this if the
     typeface changes: it is the one number that depends on the face's metrics. */
  --tagline-scale: 0.0965;

  --container: 1240px;
  --gutter: clamp(16px, 4vw, 40px);
  --col-gap: clamp(1.25rem, 3vw, 2.5rem);
  --section: clamp(4.5rem, 3rem + 6vw, 8.5rem);
  --header-h: 152px;
}

/* The J&J-style weights. Same families, same sizes: only the weights move, and
   only the headline and label weights move far. Tune the right-hand values to
   taste; the token names stay as they are. */
:root[data-type="light"] {
  --fw-800: 400;
  --fw-700: 500;
  --fw-650: 500;
  --fw-620: 500;
  --fw-600: 500;
  --fw-580: 450;
  --fw-560: 400;
  --fw-550: 400;
  --fw-500: 400;
  --fw-400: 400;
}

/* ---------- Base ---------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 16px);
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

figure {
  margin: 0;
}

/* Headings share the slate grey the "We distribute" heading uses. Sections with
   their own colour for a heading (white on the red and photo bands, red labels)
   set it on a more specific selector and are unaffected. */
h1,
h2,
h3 {
  margin: 0;
  color: var(--slate);
  text-wrap: balance;
}

p {
  margin: 0 0 1rem;
  text-wrap: pretty;
}

p:last-child {
  margin-bottom: 0;
}

a {
  color: inherit;
}

address {
  font-style: normal;
}

:focus-visible {
  outline: 3px solid var(--red);
  outline-offset: 3px;
  border-radius: 4px;
}

.topbar :focus-visible,
.footer :focus-visible {
  outline-color: #fff;
}

.wrap {
  width: min(100% - 2 * var(--gutter), var(--container));
  margin-inline: auto;
}

.defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.skip {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 100;
  padding: 0.75rem 1.25rem;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-weight: var(--fw-600);
  text-decoration: none;
}

.skip:focus {
  top: 1rem;
}

/* Available to screen readers, invisible on screen. Used where a page repeats an
   h1 in its own title, so the section still needs a heading for its landmark. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Type ---------- */

h2 {
  font-size: clamp(2.375rem, 1.45rem + 3.1vw, 4.125rem);
  font-weight: var(--fw-800);
  line-height: 0.96;
  letter-spacing: -0.005em;
}

h3 {
  font-size: 1.375rem;
  font-weight: var(--fw-700);
  line-height: 1.2;
}

.lead {
  font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.375rem);
  line-height: 1.5;
  max-width: 34em;
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 0 1.6rem;
  border: 1.5px solid transparent;
  border-radius: 999px;
  /* Inherited explicitly for the one .btn that is a <button> (the contact
     form's send): form controls take the system font, not the page's. */
  font-family: inherit;
  font-size: 1rem;
  font-weight: var(--fw-620);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s, border-color 0.2s;
}

.btn--sm {
  min-height: 44px;
  padding: 0 1.25rem;
  font-size: 0.9375rem;
}

.btn--red {
  background: var(--red);
  color: #fff;
}

.btn--red:hover {
  background: var(--ink);
}

.btn--line {
  border-color: var(--ink);
  color: var(--ink);
}

.btn--line:hover {
  background: var(--ink);
  color: #fff;
}

/* ---------- Top bar ---------- */

.topbar {
  background: var(--red);
  color: var(--on-red);
}

.topbar__inner {
  width: min(100% - 2 * var(--gutter), 1760px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  min-height: 64px;
  padding-block: 10px;
}

.topbar__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.topbar__list li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.topbar__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.22);
}

.topbar__icon svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

.topbar__copy {
  display: flex;
  flex-direction: column;
  line-height: 1.25;
  white-space: nowrap;
}

.topbar__label {
  color: var(--on-red-muted);
  font-size: 0.75rem;
  font-weight: var(--fw-650);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.topbar a {
  color: #fff;
  font-size: 0.9375rem;
  font-weight: var(--fw-600);
  text-decoration: none;
}

.topbar a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.topbar__address {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: var(--fw-560);
  white-space: nowrap;
}

/* ---------- Header ---------- */

/* Opaque, not translucent. A 6%-alpha background under a 12px blur meant the
   page showed through the header, so the rules between menu links bled and text
   edges ghosted whenever the panel grew the header. A solid surface also gives
   the sticky bar a clean edge over scrolling content. */
.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}

/* Two rows above 1100px, like a shop front: the logo, the search field and the
   actions on the first, the nav on a row of its own beneath them. The nav-panel
   wrapper is display:contents there, so the nav is a grid item in its own right.
   The search field takes whatever width the logo and the buttons leave. Below
   1100px this becomes a wrapping flex row (see Responsive). */
.header__inner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "brand search actions"
    "nav nav nav";
  align-items: center;
  column-gap: clamp(1.5rem, 0.5rem + 3vw, 3rem);
  padding-top: 10px;
}

.header__inner > .brand {
  grid-area: brand;
}

/* The tagline is live text under the figure and wordmark rather than part of
   the artwork, so it stays sharp and legible at sizes where the drawn version
   shrank to a smudge. --logo-w sets the whole lockup: the tagline takes both its
   width and its type size from it.

   At 130px wide, logo, gap and tagline together come to about 82px, which is the
   height of the header's first row (logo, search, buttons) less its padding: any
   larger and the two-row header, which is sticky, starts costing too much of the
   screen. */
.brand {
  --logo-w: 130px;
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  border-radius: 6px;
  color: var(--ink);
  text-decoration: none;
}

.brand img {
  display: block;
  width: var(--logo-w);
  height: auto;
}

/* Flush with both ends of the wordmark, in the header and the footer alike.
   Inline-size containment means the text adds nothing to the lockup's width, so
   the logo alone sets it and the tagline stretches to match. The type is sized
   to fall just short (see --tagline-scale), and justifying the single line
   closes the gap: between letters where text-justify is supported, between the
   words elsewhere. No-wrap is the guard for a fallback face that sets wider:
   the line overhangs a little rather than breaking in two. */
.brand__tagline,
.footer__tagline {
  contain: inline-size;
  align-self: stretch;
  font-size: calc(var(--logo-w) * var(--tagline-scale));
  /* Pinned, not themed: the width above was measured at 700. */
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
  text-align: justify;
  text-align-last: justify;
  text-justify: inter-character;
}

.header__actions {
  grid-area: actions;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex: none;
}

/* ---------- Header search ---------- */

/* The field and its button as one pill, in the header on every page. The ring is
   on the pill, not the input, so the whole thing lights up with focus. The words
   cycling through the categories are an overlay (.hsearch__hint), not a
   placeholder: a placeholder cannot be animated. The script turns the overlay on
   (.is-cycling); without it the real placeholder shows and nothing else changes. */
.hsearch {
  position: relative;
  grid-area: search;
  justify-self: center;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  max-width: 44rem;
  padding: 0.25rem 0.25rem 0.25rem 1.4rem;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  background: var(--paper);
  transition: border-color 0.2s, box-shadow 0.2s;
}

.hsearch:focus-within {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(205, 32, 45, 0.16);
}

.hsearch__field {
  position: relative;
  display: flex;
  flex: 1;
  min-width: 0;
}

.hsearch__input {
  width: 100%;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
  outline: 0;
}

.hsearch__input::placeholder {
  color: var(--slate);
}

/* The browser's own clear button reads as a second control next to ours. */
.hsearch__input::-webkit-search-cancel-button {
  display: none;
}

.hsearch__hint {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  overflow: hidden;
  color: var(--slate);
  font-size: 1rem;
  white-space: nowrap;
  pointer-events: none;
}

.hsearch.is-cycling .hsearch__hint {
  display: flex;
}

.hsearch.has-value .hsearch__hint {
  display: none;
}

/* The category is the part that changes, so it is the part picked out in red. */
.hsearch__word {
  display: inline-block;
  margin-inline: 0.3em 0.05em;
  color: var(--red);
  font-weight: var(--fw-650);
}

@media (prefers-reduced-motion: no-preference) {
  .hsearch__word {
    transition: transform 0.22s ease, opacity 0.22s ease;
  }

  /* Out through the top, in from the bottom: the list rolls upward. The entering
     state is applied with its transition off, so the word is already waiting
     below when the transition comes back on and carries it up into place. */
  .hsearch__word.is-leaving {
    opacity: 0;
    transform: translateY(-45%);
  }

  .hsearch__word.is-entering {
    opacity: 0;
    transform: translateY(45%);
    transition: none;
  }
}

.hsearch__submit {
  display: grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  cursor: pointer;
  transition: background-color 0.2s;
}

.hsearch__submit:hover {
  background: var(--ink);
}

.hsearch__submit svg {
  width: 20px;
  height: 20px;
}

/* The dropdown hangs under the field and is as wide as it. It scrolls inside
   itself, so a broad search (a single letter) never pushes the page around. */
.hsearch__panel {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  right: 0;
  z-index: 60;
  max-height: min(70vh, 30rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.5rem;
  border: 1px solid var(--rule);
  border-radius: 20px;
  background: var(--paper);
  box-shadow: 0 16px 36px rgba(35, 31, 32, 0.16);
}

/* display above would otherwise beat the hidden attribute. */
.hsearch__panel[hidden],
.hsearch__browse[hidden] {
  display: none;
}

.hsearch__status {
  margin: 0;
  padding: 0.6rem 0.9rem 0.35rem;
  color: var(--slate);
  font-size: 0.875rem;
  font-weight: var(--fw-600);
}

.hsearch__status:empty {
  display: none;
}

.hsearch__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.hresult__link {
  display: grid;
  gap: 0.1rem;
  padding: 0.65rem 0.9rem;
  border-radius: 12px;
  color: inherit;
  text-decoration: none;
}

.hresult__link:hover,
.hresult[aria-selected="true"] .hresult__link {
  background: var(--shelf);
}

.hresult__meta {
  color: var(--red);
  font-size: 0.6875rem;
  font-weight: var(--fw-700);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hresult__name {
  color: var(--ink);
  font-size: 1rem;
  font-weight: var(--fw-700);
  line-height: 1.25;
}

.hresult__snippet {
  overflow: hidden;
  color: var(--slate);
  font-size: 0.8125rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The words the visitor typed, on a soft red wash rather than the browser's yellow. */
.hresult mark {
  background: rgba(205, 32, 45, 0.12);
  color: inherit;
  border-radius: 3px;
}

.hsearch__browse {
  padding: 0.5rem 0.9rem 0.75rem;
}

.hsearch__label {
  margin: 0 0 0.5rem;
  color: var(--slate);
  font-size: 0.75rem;
  font-weight: var(--fw-700);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hsearch__cats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.hsearch__cats a {
  display: block;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: var(--ink);
  font-size: 0.875rem;
  font-weight: var(--fw-650);
  text-decoration: none;
  transition: background-color 0.2s, border-color 0.2s;
}

.hsearch__cats a:hover {
  border-color: var(--ink);
  background: var(--shelf);
}

/* Above 1100px the panel dissolves, so the nav and the actions become flex items
   of the header row in their own right. Below it, the panel is the menu that
   hides behind the toggle. One set of links at every width. */
.nav-panel {
  display: contents;
}

.nav-panel__actions {
  display: none;
}

/* The toggle only exists on small screens. */
.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  flex: none;
  margin-left: auto;
  padding: 0;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  background: none;
  color: var(--ink);
  cursor: pointer;
}

.nav-toggle__bars {
  position: relative;
  display: block;
  width: 20px;
  height: 2px;
  margin-inline: auto;
  background: var(--ink);
  transition: background-color 0.2s;
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--ink);
  transition: transform 0.2s;
}

.nav-toggle__bars::before {
  top: -6px;
}

.nav-toggle__bars::after {
  top: 6px;
}

/* Open: the middle bar fades out and the outer two cross into an X. */
.nav-toggle[aria-expanded="true"] .nav-toggle__bars {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before {
  transform: translateY(6px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after {
  transform: translateY(-6px) rotate(-45deg);
}

@media (prefers-reduced-motion: no-preference) {
  .nav-toggle__bars,
  .nav-toggle__bars::before,
  .nav-toggle__bars::after {
    transition: transform 0.2s, background-color 0.2s;
  }
}

/* The second header row: centred under the logo and search, divided from them by a
   hairline. */
.nav {
  grid-area: nav;
  display: flex;
  justify-content: center;
  gap: clamp(1.25rem, 2.8vw, 2.75rem);
  margin-top: 8px;
  padding-block: 6px 4px;
  border-top: 1px solid var(--rule);
}

.nav a {
  padding-block: 0.4rem;
  background: linear-gradient(var(--red), var(--red)) 0 100% / 0 2px no-repeat;
  font-size: 0.96875rem;
  font-weight: var(--fw-560);
  text-decoration: none;
  white-space: nowrap;
  transition: background-size 0.25s ease;
}

.nav a:hover {
  background-size: 100% 2px;
}

/* On a section's own page, the link points at the current page: reuse the hover underline. */
.nav a[aria-current="page"] {
  background-size: 100% 2px;
}

/* "Who we are" is a group, not a page: it opens to Leadership and Our story. The
   trigger is dressed as a nav link so the row reads as one set of links, and it
   takes the current-page underline when either of its children is the page. */
.nav__group {
  position: relative;
}

.nav__trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0;
  border: 0;
  background: linear-gradient(var(--red), var(--red)) 0 100% / 0 2px no-repeat;
  color: inherit;
  font: inherit;
  font-size: 0.96875rem;
  font-weight: var(--fw-560);
  white-space: nowrap;
  cursor: pointer;
  transition: background-size 0.25s ease;
}

.nav__trigger::after,
.nav__chevron::after {
  content: "";
  width: 0.45em;
  height: 0.45em;
  margin-top: -0.2em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.2s;
}

.nav__trigger:hover,
.nav__trigger[aria-expanded="true"],
.nav__group:has([aria-current="page"]) > .nav__trigger {
  background-size: 100% 2px;
}

.nav__trigger[aria-expanded="true"]::after,
.nav__chevron[aria-expanded="true"]::after {
  margin-top: 0.2em;
  transform: rotate(-135deg);
}

/* Products is a page and a group at once. The label is an ordinary nav link; the
   chevron beside it is a bare button that opens the categories, so it carries no
   underline of its own. */
.nav__group--split {
  display: flex;
  align-items: center;
}

.nav__chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.4rem 0 0.4rem 0.45rem;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.nav__sub {
  position: absolute;
  top: calc(100% + 0.6rem);
  left: -1rem;
  z-index: 10;
  display: grid;
  min-width: 12rem;
  padding: 0.5rem;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  box-shadow: 0 12px 28px rgba(35, 31, 32, 0.12);
}

/* display above would otherwise beat the hidden attribute. */
.nav__sub[hidden] {
  display: none;
}

@media (min-width: 1101px) {
  /* Bridge the visual gap so the menu stays open while the mouse enters it. */
  .nav__sub::before {
    content: "";
    position: absolute;
    inset: -0.7rem 0 auto;
    height: 0.7rem;
  }
}

.nav .nav__sub a {
  padding: 0.65rem 0.9rem;
  border-radius: 8px;
  background: none;
}

.nav .nav__sub a:hover,
.nav .nav__sub a[aria-current="page"] {
  background: var(--shelf);
}

/* Keeps a hyphenated word on one line. */
.nowrap {
  white-space: nowrap;
}

/* One menu item picked out in the brand red (Leadership). */
.nav .nav__accent {
  color: var(--red);
}

/* ---------- Hero ---------- */

/* The hero is a photograph with the copy laid over it, edge to edge. The
   photograph and the scrim are both absolutely positioned so the copy is the
   only thing that contributes height, which is what lets the block be as tall
   as it likes without the image's own aspect ratio dictating it. */
.hero {
  position: relative;
  display: grid;
  /* Two rows: the headline takes the space that is left and centres in it, the
     action bar sits on its own line at the foot. Stacking them in one centred
     cell is what left the buttons stranded in the middle of the photograph. */
  grid-template-rows: 1fr auto;
  align-items: center;
  min-height: clamp(480px, 78vh, 820px);
  padding-block: clamp(3rem, 1.5rem + 5vw, 5rem);
  overflow: hidden;
  background: var(--ink);
}

/* The hero's content runs wider than the rest of the page, so the button bar and
   the arrows sit nearer the edges of the frame and crowd the picture less. The
   copy shares the same wrap, which is what keeps its left edge on the
   "Explore Our Products" button's edge (and the pharmacist's right edge on the
   arrows') whatever the screen width. */
.hero .wrap {
  width: min(100% - 2 * var(--gutter), 1760px);
}

/* Less room under the bar than above the copy: the buttons hug the bottom edge. */
.hero {
  padding-bottom: clamp(1rem, 0.6rem + 1.2vw, 1.5rem);
}

.hero__foot {
  grid-row: 2;
  /* The same stacking the copy gets, and for the same reason: the two scrim
     pseudo-elements sit at z-index 1 across the full section, so anything in
     the hero without this is painted under them. That dims the buttons and,
     worse, the overlay takes the clicks instead of them. */
  position: relative;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 1.5rem;
  margin-top: clamp(2rem, 1.5rem + 2vw, 3rem);
}

/* Inset above and below the hero by 12%, which is the slack the scroll parallax
   spends: the media box is taller than the section, so shifting it up or down
   never exposes an edge. The hero clips whatever overshoots. */
.hero__media {
  position: absolute;
  inset: -12% 0;
  z-index: 0;
  container-type: size;
  transform: translate3d(0, var(--hero-shift, 0px), 0);
}

/* The slides are stacked in the same box and cross-faded, so only the copy is
   ever laid out and the section cannot change height when the slide changes.
   Absolute positioning is what keeps the second image from adding a second
   full-height block underneath the first. */
.hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
}

.hero__img.is-active {
  opacity: 1;
}

/* The pill holds the right of the frame and dissolves into the light field on
   the left, where the copy sits.
   Positioned by the pill's own centre (50.7% / 53.1% of the source) rather than
   by cover, so it keeps its place in the left third at every aspect ratio. */
.hero__img--pill {
  inset: auto;
  left: 66%;
  top: 50%;
  /* Wider than the frame on purpose: it is what makes the pill large enough to
     own the left two thirds rather than sit in it. */
  width: max(118%, calc(100cqh * 643 / 360));
  max-width: none;
  height: auto;
  translate: -50.7% -53.1%;
  transform-origin: 50.7% 53.1%;
  -webkit-mask-image: linear-gradient(to right, transparent 16%, rgba(0, 0, 0, 0.05) 22%, rgba(0, 0, 0, 0.2) 28%, rgba(0, 0, 0, 0.5) 35%, rgba(0, 0, 0, 0.8) 42%, #000 48%);
  mask-image: linear-gradient(to right, transparent 16%, rgba(0, 0, 0, 0.05) 22%, rgba(0, 0, 0, 0.2) 28%, rgba(0, 0, 0, 0.5) 35%, rgba(0, 0, 0, 0.8) 42%, #000 48%);
}

.hero__img--pharmacist {
  object-position: center 22%;
  -webkit-mask-image: linear-gradient(to right, transparent 30%, rgba(0, 0, 0, 0.05) 42%, rgba(0, 0, 0, 0.2) 52%, rgba(0, 0, 0, 0.5) 64%, rgba(0, 0, 0, 0.8) 76%, #000 88%);
  mask-image: linear-gradient(to right, transparent 30%, rgba(0, 0, 0, 0.05) 42%, rgba(0, 0, 0, 0.2) 52%, rgba(0, 0, 0, 0.5) 64%, rgba(0, 0, 0, 0.8) 76%, #000 88%);
}

/* Desktop: the pharmacist stands on the left and the copy takes the right. The
   photograph is not mirrored (the Tigremed mark on her coat must read the right
   way round) and not re-cropped: it is drawn at exactly the size "cover" gave it
   and slid left until she, at about 72% across the picture, sits at 28% of the
   frame. The vertical position is the same 22% as before. The right of the
   picture dissolves into the light field behind the copy. */
@media (min-width: 901px) {
  .hero__img--pharmacist {
    inset: auto;
    left: 28%;
    top: 22%;
    width: max(100cqw, calc(100cqh * 900 / 421));
    max-width: none;
    height: auto;
    translate: -72% -22%;
    -webkit-mask-image: linear-gradient(to right, #000 82%, rgba(0, 0, 0, 0.7) 88%, rgba(0, 0, 0, 0.35) 93%, rgba(0, 0, 0, 0.1) 97%, transparent 100%);
    mask-image: linear-gradient(to right, #000 82%, rgba(0, 0, 0, 0.7) 88%, rgba(0, 0, 0, 0.35) 93%, rgba(0, 0, 0, 0.1) 97%, transparent 100%);
  }
}

/* The pharmacist and pill slides fade into a light field behind their copy. */
.hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active) {
  background: var(--paper);
}

.hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active)::before,
.hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active)::after {
  opacity: 0;
}


/* ---------- Hero navigation ---------- */

.hero__nav {
  display: flex;
  gap: 0.75rem;
}

.hero__arrow {
  display: grid;
  place-items: center;
  /* The same height as the two buttons beside them, so the row sits on one line. */
  width: 40px;
  height: 40px;
  border: 1.5px solid #fff;
  border-radius: 999px;
  background: #fff;
  color: var(--ink);
  cursor: pointer;
  transition:
    background-color 0.2s,
    border-color 0.2s,
    color 0.2s;
}

/* Solid at rest, like the "Explore Our Products" button, so the hover only has to
   change the colour. It is gated on a real pointer: a tap fires :hover on a touch
   screen and then leaves it applied, which would leave the button stuck in its
   hover colour for the rest of the session. */
@media (hover: hover) {
  .hero__arrow:hover {
    background: var(--rule);
    border-color: var(--rule);
    color: var(--ink);
  }
}

.hero__arrow svg {
  width: 18px;
  height: 18px;
}

/* Two scrims, not one. The flat wash keeps white type legible over whatever the
   photograph happens to be doing at that point in the frame; the gradient adds
   extra weight behind the copy so the headline never has to compete with a
   bright patch of road or a pale sky. */
.hero::before,
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.hero::before {
  background: rgba(35, 31, 32, 0.55);
}

.hero::after {
  background: linear-gradient(
    180deg,
    rgba(35, 31, 32, 0.5) 0%,
    rgba(35, 31, 32, 0.18) 38%,
    rgba(35, 31, 32, 0.62) 100%
  );
}

.hero__copy {
  position: relative;
  z-index: 2;
  /* Start of its row, not centred in it. The row is 1fr, so it absorbs all the
     space above the action bar; centring the headline in that put it in the
     middle of the photograph with equal dead air above and below. Sitting at
     the top instead lets the headline lead and leaves the space underneath as
     breathing room in front of the buttons. */
  align-self: start;
  margin-inline: auto;
  text-align: center;
  /* One cell, both blocks in it, so the taller block sets the height and the
     hero cannot jump when the slide changes. Same reason the photographs are
     stacked rather than appended.

     No measure of its own: it runs the full wrap, which is what puts the
     left-set slide's headline on the same left edge as the button in the foot
     below it. The measure lives on the headline instead. */
  display: grid;
}

/* The headline that goes with each slide, faded in step with its photograph —
   same 1.4s dissolve as .hero__img, so the words change as the picture does
   rather than after it.

   visibility rather than opacity alone: an invisible block still takes clicks,
   and in the hero the links and arrows sit within reach of the copy. The
   delay is what keeps the outgoing block hoverable for the length of its own
   fade and no longer; without it, visibility flips to hidden the moment the
   class changes and the text would simply blink out. */
.hero__slide-copy {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 1.4s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 1.4s;
}

.hero__slide-copy.is-active {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

/* The two light slides keep their photograph on the right and their copy on the
   left edge of the wrap, level with the "Explore Our Products" button below it
   and clear of the picture. */
.hero__slide-copy--start {
  justify-self: start;
  width: min(100%, 44rem);
  text-align: left;
}

/* The pill slide's headline is a single line of copy now, so it runs at the same
   size as the other two slides rather than the reduced size it needed when a
   second line sat under it. Only the measure is its own: a little wider than the
   pharmacist's, so the headline sets in three lines. */
.hero__slide-copy--start .hero__title--expertise {
  max-width: none;
}

/* The campaign slide's question and its link share one left edge, level with
   the buttons below, rather than the title centring itself over a link that
   cannot. */
.hero__slide-copy--science {
  justify-self: start;
  width: min(100%, 46rem);
  text-align: left;
}

.hero__slide-copy--science .hero__title {
  margin-inline: 0;
}

.hero__slide-copy--left {
  justify-self: end;
  width: min(100%, 36rem);
  text-align: left;
}

/* Cancels the auto inline margin that centres the measure inside the wrap,
   which would otherwise pull this line back to the middle it is deliberately
   leaving. */
.hero__slide-copy--start .hero__title,
.hero__slide-copy--left .hero__title {
  margin-inline: 0;
}

/* The headline measure centres the welcome slide; the partner slide cancels
   its auto margin to keep the lockup aligned with the left edge of the wrap. */
.hero__title {
  max-width: 60rem;
  margin-inline: auto;
  color: #fff;
  font-size: clamp(2.75rem, 1rem + 5.5vw, 7rem);
  font-weight: var(--fw-800);
  line-height: 0.88;
  letter-spacing: -0.005em;
  text-shadow: 0 1px 24px rgba(35, 31, 32, 0.35);
}

/* Each line is a mask so the words can rise into place on load. The extra
   bottom padding keeps descenders (y, p) from being clipped. */
.hero__title .line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}

.hero__title .line > span {
  display: block;
}

/* Give the pharmacist's expertise message room to wrap on small screens. */
.hero__title--expertise {
  max-width: 36rem;
  color: var(--slate);
  font-size: clamp(2rem, 1.25rem + 2.75vw, 3.75rem);
  line-height: 1.05;
  text-shadow: none;
}

.hero__title--science {
  max-width: 22ch;
  font-size: clamp(2rem, 1rem + 3.6vw, 4.5rem);
  line-height: 1.1;
  text-shadow: none;
}

/* ---------- The manufacturer slide: a split ---------- */

/* This slide is the odd one out. The other two lay their copy over a photograph
   that runs the whole frame; here the photograph takes the right half and the
   question sits on white beside it, so the frame divides in two.

   It is stated after the slide's own rules above rather than beside the rest of
   the hero, because every one of these has to beat an earlier rule of the same
   weight, and the split is the more specific case.

   Below 901px there is no room for two columns, so it falls back to the
   full-bleed photograph with white copy that the other dark slide uses — which
   is why the whole block lives in this query. */
@media (min-width: 901px) {
  .hero:has(.hero__img--counter.is-active) {
    background: var(--paper);
  }

  /* The two scrims exist to hold white type off a photograph. The type here is
     on white already, so all they would do is grey the picture down. */
  .hero:has(.hero__img--counter.is-active)::before,
  .hero:has(.hero__img--counter.is-active)::after {
    opacity: 0;
  }

  /* The 16:9 original is cropped to a half-width panel, and the panel's aspect
     ratio changes with the viewport while the photograph's does not — so the
     crop has to be chosen for the narrowest and the widest case at once. At 60%
     the logo wall sits whole in both, with the counter and two staff behind it;
     going any further right pulls the "over the counter" shelf unit far enough
     into frame to leave a cut wedge of red type at the edge, and going left
     cuts the wordmark. */
  .hero__img--counter {
    inset: 0 0 0 auto;
    width: 50%;
    object-position: 60% 50%;
    /* The copy for this slide sits on the left, so the photograph has to leave
       the same way the pill does rather than start at a straight vertical edge
       beside the text. The ramp is stops rather than two points because a
       linear fade spread across a half-width panel thins the picture out too
       far to read as a dissolve; this keeps the wall and the counter at full
       strength from about a fifth of the way in. */
    -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0, 0, 0, 0.1) 5%, rgba(0, 0, 0, 0.4) 11%, rgba(0, 0, 0, 0.75) 16%, #000 23%);
    mask-image: linear-gradient(to right, transparent 0, rgba(0, 0, 0, 0.1) 5%, rgba(0, 0, 0, 0.4) 11%, rgba(0, 0, 0, 0.75) 16%, #000 23%);
  }

  /* Held clear of the photograph rather than given the wrap's full width, and
     set smaller than the other two slides: theirs carry three or four words,
     this one carries eleven and would otherwise wrap down into a stack of
     single words. */
  .hero__slide-copy--science {
    width: min(34rem, calc(50vw - 4rem));
  }

  .hero__slide-copy--science .hero__title {
    color: var(--ink);
  }

  .hero__title--science {
    max-width: none;
    font-size: clamp(1.75rem, 1.2rem + 2.1vw, 3.25rem);
    line-height: 1.06;
  }

  .hero__slide-copy--science .hero__textlink {
    color: var(--ink);
  }

  /* Ink on paper, the same fill the light slides give the primary pair, since
     with the scrim gone a white outline button has nothing to sit against. The
     arrows are left alone: they sit on the right of the row, over the
     photograph rather than over the paper, so they keep the white fill they
     carry on the dark slides. */
  .hero:has(.hero__img--counter.is-active) .btn--line {
    border-color: var(--ink);
    background: var(--ink);
    color: var(--paper);
  }
}

@media (hover: hover) and (min-width: 901px) {
  .hero:has(.hero__img--counter.is-active) .btn--line:hover {
    border-color: var(--slate);
    background: var(--slate);
  }
}

/* The link under the campaign question. Plain text with an arrow rather than a
   button: the buttons in the hero's foot are the primary actions, and this is
   the slide's own pointer to the same contact page. */
.hero__textlink {
  display: inline-block;
  margin-top: 1.5rem;
  color: #fff;
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  font-weight: var(--fw-700);
  text-decoration: underline;
  text-underline-offset: 0.3em;
  text-decoration-thickness: 2px;
}

.hero__textlink:hover {
  text-decoration-color: transparent;
}

.hero__title .line--expertise-detail {
  margin-top: 0.18em;
}

.hero__title .line--expertise-detail > span {
  font-size: 1em;
  font-weight: var(--fw-500);
  line-height: inherit;
}

/* The campaign headline is a <p>, and the global p rule adds a bottom margin
   that is currently cancelled only by it happening to be the last child of its
   block. Stated here instead, so rewrapping the block cannot leave a stray
   1rem under the lockup. Block-direction only, so the auto inline margin that
   centres this measure survives untouched. */
.hero__slide-copy > p.hero__title {
  margin-block: 0;
}

.hero__lead {
  max-width: 24ch;
  margin-top: 1.75rem;
  color: var(--slate);
  font-size: clamp(1.25rem, 1.05rem + 0.7vw, 1.5rem);
  line-height: 1.4;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* Smaller than the site's small button (44px): over a photograph with a headline
   on it, the full-size pair outweighed everything else in the frame. */
.hero .btn--sm {
  min-height: 40px;
  padding-inline: 1.1rem;
  font-size: 0.875rem;
}

/* The outline button is ink-on-white everywhere else on the site, which is
   invisible over a dark photograph. Scoped to the hero rather than changed on
   .btn--line itself, so every other use of the outline button — the contact
   page's profile download, for one — keeps its existing treatment. */
.hero .btn--line {
  border-color: #fff;
  background: #fff;
  color: var(--ink);
}

/* Hover gated on a real pointer for the same reason the arrows' is: a tap
   would leave the button inverted to a filled white disc for the rest of the
   session. */
/* Solid at rest, so the hover only has to change its colour. */
@media (hover: hover) {
  .hero .btn--line:hover {
    border-color: var(--rule);
    background: var(--rule);
    color: var(--ink);
  }
}

/* The red button keeps its fill on every slide; only the hover is the hero's own,
   because the site-wide ink hover disappears into the dark third slide. */
@media (hover: hover) {
  .hero .btn--red:hover {
    background: var(--red);
    filter: brightness(0.85);
  }
}

.hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active) .btn--line {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}

.hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active) .hero__arrow {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}

@media (hover: hover) {
  .hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active) .btn--line:hover {
    border-color: var(--slate);
    background: var(--slate);
    color: var(--paper);
  }

  .hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active) .hero__arrow:hover {
    border-color: var(--slate);
    background: var(--slate);
    color: var(--paper);
  }
}

@media (max-width: 900px) {
  .hero__img--pharmacist {
    height: 65%;
    object-position: 75% 22%;
    -webkit-mask-image: linear-gradient(to bottom, #000 35%, rgba(0, 0, 0, 0.8) 52%, rgba(0, 0, 0, 0.4) 70%, transparent 95%);
    mask-image: linear-gradient(to bottom, #000 35%, rgba(0, 0, 0, 0.8) 52%, rgba(0, 0, 0, 0.4) 70%, transparent 95%);
  }

  /* Stacked: the pill sits over the top of the frame and dissolves downward
     into the copy, the same arrangement the pharmacist uses. */
  .hero__img--pill {
    left: 50%;
    top: 0;
    width: max(100%, calc(65cqh * 643 / 360));
    translate: -50.7% 0;
    transform-origin: 50.7% 53.1%;
    -webkit-mask-image: linear-gradient(to bottom, #000 35%, rgba(0, 0, 0, 0.8) 52%, rgba(0, 0, 0, 0.4) 70%, transparent 95%);
    mask-image: linear-gradient(to bottom, #000 35%, rgba(0, 0, 0, 0.8) 52%, rgba(0, 0, 0, 0.4) 70%, transparent 95%);
  }

  .hero:has(.hero__img--pharmacist.is-active, .hero__img--pill.is-active) .hero__copy {
    align-self: end;
  }

  /* Stacked, both blocks run the width of the wrap, level with the button
     underneath. */
  .hero__slide-copy--start,
  .hero__slide-copy--left {
    justify-self: start;
    width: 100%;
  }
}

/* Phones: the title, paragraph, two stacked buttons and the arrows leave little
   height over the picture, so the pill shrinks and the copy tightens to keep the
   title clear of it. The hero's own height is left alone: it is what lets the buttons
   fit on the first screen. */
@media (max-width: 600px) {
  .hero__img--pill {
    top: -6%;
    width: max(100%, calc(44cqh * 643 / 360));
  }

  .hero__foot {
    margin-top: 1.25rem;
  }

  .hero .btn--sm {
    min-height: 42px;
  }
}

/* ---------- Hero motion ---------- */

.hero {
  transition: background-color 1.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.hero::before,
.hero::after {
  transition: opacity 1.4s cubic-bezier(0.22, 1, 0.36, 1);
}

/* The slideshow's own motion is deliberately NOT inside the reduced-motion
   gate, unlike the entrance animations below. A cross-fade between two
   photographs carries no vestibular risk the way travel and zoom do, and the
   brief was to keep it running for everyone. Removing it here would leave
   reduced-motion visitors with a hard cut every six seconds, which reads as
   broken rather than as considered.

   The cross-fade is slow on purpose. A fast dissolve reads as a slideshow
   transition; at 1.4s it reads as one photograph giving way to another, which
   is the effect worth having under a headline.

   Both slides run the same 14-second alternate cycle, started at the same
   moment, so they stay in lockstep. Two things fall out of that. The swap is
   seamless, because the outgoing and incoming photographs are at the same
   scale as they change places. And neither slide snaps when it loses
   .is-active, because the animation was never tied to that class — an
   animation that started and stopped with the class would jump from wherever
   it had got to back to no transform, on a photograph still half visible. */
.hero__img {
  transition: opacity 1.4s cubic-bezier(0.22, 1, 0.36, 1);
  animation: hero-zoom 14s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}

@media (prefers-reduced-motion: no-preference) {
  .hero__title .line > span {
    animation: line-rise 0.95s cubic-bezier(0.16, 0.84, 0.3, 1) both;
  }

  .hero__title .line:nth-child(2) > span {
    animation-delay: 0.09s;
  }

  .hero__actions {
    animation: fade-up 0.8s cubic-bezier(0.2, 0.7, 0.2, 1) both;
    animation-delay: 0.28s;
  }

  /* The parallax handler writes this transform on every scroll frame, so the
     layer is promoted up front rather than being discovered mid-scroll and
     flickering into place. */
  .hero__media {
    will-change: transform;
  }
}

@keyframes line-rise {
  from {
    transform: translateY(105%);
  }
}

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}

/* Ken Burns lives on the image while the scroll parallax lives on .hero__media
   above it, so the two transforms never compete for the same property. */
@keyframes hero-zoom {
  from {
    transform: scale(1);
  }

  to {
    transform: scale(1.09);
  }
}

/* ---------- Hero stats ---------- */

/* The three trust markers, directly under the hero, as a band of their own. The
   pale grey is what separates them from the white "We are Tigremed" section
   below, so the page does not read as one long white sheet. */
.hero-stats {
  padding-block: clamp(3rem, 2rem + 4vw, 5.5rem);
  background: var(--shelf);
}

/* The hero pays the same padding above and below on purpose: it is full-bleed
   now, so the copy centres in a box with even space top and bottom. An earlier
   rule trimmed the bottom padding away to close a gap against the stats band,
   which was the right call when the hero was a white section sitting on a white
   page — but against a photograph it just pushed the centred copy down. The
   band below brings its own top padding and a hairline, which is enough
   separation on its own. */

/* The band's own title, above the three markers, in ink rather than the heading
   slate. It is a label for the row beneath it, not a section opener, so it sits
   well under the site's h2 size (which put it at 66px, bigger than the stat
   titles it introduces by a factor of three) and a notch under the section
   headings further down the page. */
.hero-stats__title {
  margin-bottom: clamp(1.75rem, 1.25rem + 2vw, 2.75rem);
  color: var(--ink);
  font-size: clamp(1.625rem, 1.25rem + 1.3vw, 2.25rem);
  line-height: 1.05;
}

.hero-stats__row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--col-gap);
}

/* The icon sits in a row with the title-and-description column, which is why
   this is a two-track grid rather than the icon being a background or a list
   bullet. align-items: start keeps the icon on the title's cap line rather than
   floating to the vertical centre of a description that may wrap to three
   lines — a centred icon beside a tall column reads as detached from it. */
.hero-stat {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: clamp(0.625rem, 0.5rem + 0.3vw, 0.875rem);
}

/* The browser indents a <dd> by 40px, which here only pushed the words away
   from their marker. The grid gap above is the whole of the spacing. */
.hero-stat dd {
  margin: 0;
}

/* The whole item is the tap target, not just the title: the title is the link,
   and its ::after is stretched over the item (position: relative here). That
   keeps one link per item for screen readers and the keyboard, while a finger
   or cursor anywhere on the icon, title or description follows it. */
.hero-stat {
  position: relative;
}

.hero-stat__title::after {
  content: "";
  position: absolute;
  inset: 0;
}

a.hero-stat__title {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s;
}

.hero-stat:hover a.hero-stat__title,
a.hero-stat__title:focus-visible {
  color: var(--red);
}

/* The ring goes around the whole item, since that is what the link covers. */
a.hero-stat__title:focus-visible {
  outline: none;
}

.hero-stat:has(a.hero-stat__title:focus-visible) {
  outline: 3px solid var(--red);
  outline-offset: 6px;
  border-radius: 8px;
}

/* Sized against the title rather than picked: at 2rem the condensed display
   line is about 32px, so an icon much past this starts reading as the subject
   of the item rather than as its marker. The marker is the figure from the
   logo, in the logo's own red. */
/* The Tigremed figure, in white on a red disc, like an avatar. The figure keeps
   its own size (--stat-figure); the disc is just that plus a little margin. */
.hero-stat__icon {
  --stat-figure: clamp(27.8px, 23.2px + 0.7vw, 34.8px);
  display: grid;
  place-items: center;
  width: calc(var(--stat-figure) * 1.38);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
}

.hero-stat__icon svg {
  display: block;
  width: var(--stat-figure);
  height: auto;
}

/* The condensed display treatment the headlines use, at a size the longest of
   the three titles can carry without wrapping to three lines. */
.hero-stat__title {
  display: block;
  font-size: clamp(1.125rem, 0.95rem + 0.5vw, 1.5rem);
  font-weight: var(--fw-800);
  line-height: 1.05;
  text-wrap: balance;
}

.hero-stat__desc {
  display: block;
  max-width: 26em;
  margin-top: 0.4rem;
  color: var(--slate);
  font-size: 0.9375rem;
  line-height: 1.45;
}

/* ---------- The Tigremed Difference ---------- */

/* Held to the hero line's size rather than the site's h2 size, so the heading
   and the motto at the foot of the section sit at one scale. */
.why__title {
  color: var(--ink);
  font-size: clamp(2rem, 1.25rem + 2.75vw, 3.75rem);
}

.why__lead {
  max-width: 44em;
  margin-top: clamp(1.25rem, 1rem + 1vw, 2rem);
  color: var(--slate);
}

/* The sentence the paragraph turns on, set in the logo red. A mark element keeps
   it meaningful to assistive tech; its default yellow background is cleared. */
.why__mark {
  background: none;
  color: var(--red);
  font-weight: var(--fw-650);
}

/* Three circles on one arrow: the manufacturer, Tigremed, and the patient. Tigremed
   is what connects the other two, so its circle sits on the arrow with the arrow
   running behind it. The sizes are ordered: the manufacturer is the smallest, the
   patient the largest because the patient is the point of it all, and Tigremed is
   exactly halfway between, so it can never drift out of order. The middle column
   takes whatever width the circles leave, but never less than the hub plus a
   stub of arrow either side. */
.flow {
  --flow-from: clamp(9rem, 4rem + 10vw, 13rem);
  --flow-to: clamp(15rem, 6rem + 24vw, 26rem);
  --flow-mid: calc((var(--flow-from) + var(--flow-to)) / 2);
  display: grid;
  grid-template-columns: var(--flow-from) minmax(calc(var(--flow-mid) + 5rem), 1fr) var(--flow-to);
  align-items: center;
  margin: clamp(3rem, 2rem + 4vw, 5.5rem) 0 0;
  padding: 0;
  list-style: none;
}

.flow__step {
  width: var(--flow-from);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  padding: 1rem;
  border-radius: 50%;
  background: var(--shelf);
  text-align: center;
}

/* The manufacturer circle is the small one, so its name is set a size down. */
.flow__from .flow__name {
  font-size: clamp(1rem, 0.6rem + 0.8vw, 1.25rem);
}

/* The two outer columns share one layout: the circle in the middle row, with an
   equal 1fr row above and below it. That is what keeps every circle on the same
   centre line, whatever each column is made of. */
.flow__from,
.flow__link {
  align-self: stretch;
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  justify-items: center;
  min-width: 0;
}

.flow__from > .flow__step {
  grid-row: 2;
}

.flow__link {
  padding-inline: clamp(1rem, 0.25rem + 2.5vw, 2.5rem);
}

/* The Tigremed circle: white with a red ring, between the grey manufacturer and
   the solid red patient. It is opaque and carries a halo in the page colour, so the
   arrow behind it stops short of the ring instead of touching it. */
.flow__hub {
  grid-area: 2 / 1;
  z-index: 1;
  /* The logo, then the people Tigremed serves, stacked and centred in the circle.
     Container-typed so the list sets its type against the circle's own width
     (cqw): the circle shrinks with the viewport and the text has to shrink with it
     or the longest line meets the rim. */
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: var(--flow-mid);
  aspect-ratio: 1;
  border: 3px solid var(--red);
  border-radius: 50%;
  background: var(--paper);
  box-shadow: 0 0 0 0.6rem var(--paper);
  text-align: center;
}

/* Everything below is spaced in cqw, which resolves against the nearest container
   *above* the element. That is why the spacing is on the children and not on the
   hub itself: on the hub, cqw would reach past it to the page. */
.flow__logo {
  width: 44%;
  height: auto;
  margin-bottom: 6cqw;
}

.flow__serve {
  display: grid;
  justify-items: center;
  gap: 2.5cqw;
}

.flow__serve .flow__tag {
  font-size: clamp(0.625rem, 3.6cqw, 0.8125rem);
}

.flow__audiences {
  display: grid;
  gap: 1cqw;
  margin: 0;
  padding: 0;
  list-style: none;
}

.flow__audiences li {
  color: var(--ink);
  font-size: clamp(0.7rem, 5cqw, 1rem);
  font-weight: var(--fw-650);
  line-height: 1.3;
  white-space: nowrap;
}

/* A line of dots rather than a solid rule; the head stays solid so it still reads
   as an arrow. */
.flow__arrow {
  position: relative;
  grid-area: 2 / 1;
  align-self: center;
  width: 100%;
  height: 4px;
}

/* The dots are a layer of their own, not the arrow's background: the entrance
   scales this layer along the line, and scaling the arrow itself would squash its
   head with it. */
.flow__arrow::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle, var(--slate) 1.2px, transparent 1.5px) 0 50% / 9px 4px repeat-x;
  transform-origin: left center;
}

.flow__arrow::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 0;
  width: 0.75rem;
  height: 0.75rem;
  border-top: 1.5px solid var(--slate);
  border-right: 1.5px solid var(--slate);
  transform: translate(-0.1rem, -50%) rotate(45deg);
}

.flow__tag {
  color: var(--red);
  font-size: clamp(0.6875rem, 0.6rem + 0.3vw, 0.8125rem);
  font-weight: var(--fw-700);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.flow__name {
  margin-top: 0.4em;
  color: var(--ink);
  font-size: clamp(0.9375rem, 0.35rem + 1.15vw, 1.5rem);
  font-weight: var(--fw-700);
  line-height: 1.15;
}

/* The patient is where the chain ends, so it is the one filled circle. */
.flow__step--end {
  width: var(--flow-to);
  background: var(--red);
  box-shadow: 0 1.5rem 3rem -1.25rem rgba(205, 32, 45, 0.55);
}

/* With "People" gone the tag is the circle's only label, so it is set larger. */
.flow__step--end .flow__tag {
  color: var(--on-red);
  font-size: clamp(1rem, 0.6rem + 1.3vw, 1.75rem);
}

.flow__step--end .flow__name {
  color: var(--on-red);
}

.why__ambition {
  max-width: 46em;
  margin: clamp(3rem, 2rem + 4vw, 5.5rem) 0 0;
  padding-top: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
  border-top: 1px solid var(--rule);
  color: var(--slate);
  font-size: clamp(1.1875rem, 1rem + 0.7vw, 1.625rem);
  font-weight: var(--fw-500);
  line-height: 1.45;
}

.why__ambition strong {
  color: var(--ink);
  font-weight: var(--fw-700);
}

/* The sign-off: the ambition boiled down to four words. */
.why__motto {
  margin: clamp(1.25rem, 1rem + 1vw, 2rem) 0 0;
  color: var(--ink);
  font-size: clamp(2rem, 1.25rem + 2.75vw, 3.75rem);
  font-weight: var(--fw-800);
  line-height: 1.05;
  letter-spacing: -0.005em;
}

.why__motto span {
  color: var(--red);
}

/* Narrow screens: the row becomes a column. The arrow can no longer run behind the
   hub, so it becomes two stubs: one leading into the Tigremed circle and one
   leading out of its audiences to the patients. */
@media (max-width: 860px) {
  .flow {
    /* The Tigremed circle holds the logo and four lines of text now, so here it
       is set by hand rather than halfway: it needs 16.5rem to hold them without
       touching the ring, and the other two are placed either side of it so the
       order (manufacturers, Tigremed, patients) still holds. 17.5rem is as wide
       as the patients circle can be on a 320px phone. */
    --flow-from: 11rem;
    --flow-mid: 16.5rem;
    --flow-to: 17.5rem;
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
  }

  .flow__from,
  .flow__link {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .flow__link {
    padding-block: 1.5rem;
    padding-inline: 0;
  }

  .flow__link::before {
    content: "";
    width: 4px;
    height: 3.5rem;
    background: radial-gradient(circle, var(--slate) 1.2px, transparent 1.5px) 50% 0 / 4px 9px repeat-y;
  }

  .flow__arrow {
    order: 1;
    width: 4px;
    height: 3.5rem;
    margin-top: 1.5rem;
  }

  .flow__arrow::before {
    background: radial-gradient(circle, var(--slate) 1.2px, transparent 1.5px) 50% 0 / 4px 9px repeat-y;
    transform-origin: center top;
  }

  .flow__hub {
    margin-top: 1.5rem;
  }

  .flow__arrow::after {
    top: auto;
    right: 50%;
    bottom: 0;
    transform: translate(50%, -0.1rem) rotate(135deg);
  }

}

/* ---------- Our story ---------- */

.story-page,
.story-page .statement,
.story-page .stat__num {
  color: var(--slate);
}

/* "Who we are" closes the page but keeps the colours it had as a page of its own. */
.story-page .who {
  color: var(--ink);
}

.story-page .gradient-text {
  background: none;
  color: var(--slate);
  -webkit-text-fill-color: currentColor;
}

/* A text link in the page's red, matching the "See our CSR partnership" link on the
   Partners page, with an arrow that nudges on hover. */
.story-link {
  display: inline-block;
  color: var(--red);
  font-size: 1.0625rem;
  font-weight: var(--fw-650);
  text-underline-offset: 4px;
}

.story-link span {
  display: inline-block;
  margin-left: 0.4em;
  transition: transform 0.2s ease;
}

@media (hover: hover) {
  .story-link:hover span {
    transform: translateX(4px);
  }
}

/* Body copy, in the page's reading size. */
.story-p {
  max-width: 40em;
  margin: 0 0 1rem;
  color: var(--slate);
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  line-height: 1.65;
}

/* A paragraph straight under a band heading needs a little air. */
.heading-md + .story-p {
  margin-top: 1rem;
}

/* The line a passage turns on, set larger and darker than the copy around it. */
.statement {
  max-width: 28em;
  margin: 1.5rem 0;
  color: var(--ink);
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.875rem);
  font-weight: var(--fw-700);
  line-height: 1.3;
  text-wrap: balance;
}

.heading-md + .statement {
  margin-top: 1rem;
}

/* Cards for a run of short parallel lines. White on the shelf-grey sections. */
.tiles {
  display: grid;
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
  margin: 0 0 clamp(1.75rem, 1.25rem + 2vw, 3rem);
  padding: 0;
  list-style: none;
}

.tiles--2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.tile {
  display: grid;
  align-content: start;
  gap: 0.4rem;
  padding: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  border-radius: 20px;
  background: var(--shelf);
  color: var(--ink);
  font-size: 1.0625rem;
  font-weight: var(--fw-620);
  line-height: 1.4;
}

.tile--plain {
  background: var(--paper);
}

.tile__lead {
  color: var(--red);
  font-size: 0.8125rem;
  font-weight: var(--fw-700);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.tile strong {
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  font-weight: var(--fw-700);
  line-height: 1.25;
}

@media (max-width: 900px) {
  .tiles--2 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* A stand-in for a photograph that has not been supplied yet: a striped panel
   naming what belongs there. Swap each one for an <img> when the picture
   arrives. Inside a fade band it fills the band's media box, so it fades out like
   the photo will, and its label sits on the side the photo runs in from, which is
   the clear part of the fade. */
.placeholder {
  display: grid;
  place-content: center;
  gap: 0.35rem;
  padding: 1.5rem;
  background:
    repeating-linear-gradient(135deg, rgba(35, 31, 32, 0.05) 0 14px, transparent 14px 28px),
    var(--shelf);
  color: var(--slate);
  text-align: center;
}

.section--shelf .placeholder {
  background-color: var(--paper);
}

.distribute__media .placeholder,
.deliver__media .placeholder {
  width: 100%;
  height: 100%;
}

.distribute__media .placeholder {
  justify-content: start;
  padding-left: 12%;
  text-align: left;
}

.deliver__media .placeholder {
  justify-content: end;
  padding-right: 12%;
  text-align: right;
}

.placeholder__tag {
  color: var(--ink);
  font-size: 0.8125rem;
  font-weight: var(--fw-700);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.placeholder__desc {
  max-width: 18rem;
  font-size: 0.9375rem;
  line-height: 1.4;
}

/* Separate the partnerships heading from the cards in the left text column. */
.story-partnerships .heading-md {
  margin-bottom: 1.5rem;
}

/* Mirror the photograph within its existing fade mask. The handshake in the
   partnerships section is not mirrored: the clasped hands already sit right of
   centre, clear of the fade. */
.story-experience .deliver__media img {
  transform: scaleX(-1);
}

.story-experience .deliver__media img {
  object-position: center 45%;
}

.story-partnerships .deliver__media img {
  object-position: 65% center;
}

/* ---------- Counting stats ---------- */

/* The figure sits above its label, but the label comes first in the markup (a
   <dt> before its <dd>), so the order is flipped here rather than in the DOM. */
/* A strip of figures, not a full section: it takes a fraction of the usual
   vertical padding. The extra .section is for specificity, since .section's own
   padding is declared further down the file. */
.section.stats {
  padding-block: clamp(1.25rem, 1rem + 1.5vw, 2.25rem);
}

.stats__row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.5rem, 1rem + 2vw, 3rem);
  margin-block: 0;
}

.stat {
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 0.5rem;
  text-align: center;
}

.stat__num {
  margin: 0;
  color: #000;
  font-size: clamp(1.75rem, 1.4rem + 1.4vw, 2.75rem);
  font-weight: var(--fw-800);
  line-height: 1;
  /* Equal-width digits, so the figure does not jiggle sideways as it counts. */
  font-variant-numeric: tabular-nums;
}

/* The plus is drawn by CSS rather than typed into the number, because the
   counting script rewrites the number's text on every frame. */
.stat__num::after {
  content: "+";
}

.stat__label {
  color: var(--slate);
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  font-weight: var(--fw-620);
}

/* ---------- Sections ---------- */

.section {
  padding-block: var(--section);
}

/* ---------- Page header ---------- */

/* Stands in for the hero on a section's own page: kicker, title, lead. */

.pagehead {
  padding-block: clamp(2.75rem, 1.5rem + 4vw, 5.5rem) clamp(2rem, 1rem + 2.5vw, 3.5rem);
}

.pagehead__kicker {
  margin: 0 0 1rem;
  color: var(--red);
  font-size: 1.0625rem;
  font-weight: var(--fw-650);
}

/* A full-bleed banner in place of a pagehead. The photograph is 3:2, which at
   full viewport width would stand taller than most screens, so the height is
   capped and the frame crops from the sides instead. The source is heavily
   backlit and close to white behind the baby's head, so the copy cannot lean on
   the photo's own contrast: a scrim from the left carries it. The copy stays
   inside the wrap so its measure still lines up with the page below. */
.products-hero {
  position: relative;
  height: clamp(340px, 42vw, 560px);
  overflow: hidden;
}

/* A banner that only carries a title needs less height than the full hero. Kept
   shallow so the row of categories arrives sooner. */
.products-hero--compact {
  height: clamp(190px, 19vw, 290px);
}

/* The grid is the subject of the page, so it starts close under the banner
   instead of paying the full section padding to separate two blocks. The gap is
   the gutter the cards inset by, so the first row stands as far from the banner
   as it does from the side of the page. */
.products-hero + .section {
  padding-block-start: var(--gutter);
}

/* The faces are in the top fifth of the photograph and the frame is a short
   strip of its full height, so the crop has to favour the top: centred, or read
   40% down, the masks and safety glasses fall off the top edge. */
.products-hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 18%;
}

.products-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(35, 31, 32, 0.88) 0%, rgba(35, 31, 32, 0.8) 34%, rgba(35, 31, 32, 0.6) 62%, rgba(35, 31, 32, 0.34) 86%, rgba(35, 31, 32, 0.26) 100%);
}

/* The copy has to sit above the scrim, not under it. Both this div and the ::after
   are positioned with z-index auto, so they fall back to tree order, and a ::after
   is the element's last child: the scrim was painting on top of the headline,
   which muddied the left of the title to a dark grey and left the tail of it as
   white-on-backlit-sky. The scrim also runs right across the frame now, because
   the title is a wide condensed line and was still catching the bare photograph
   past the old 72% stop. */
.products-hero__copy {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100%;
}

/* Red is the brand accent and stays the accent everywhere else, but on a near-black
   scrim it has no legibility left, so the kicker takes the muted-on-red tint the
   full-bleed sections use instead. */
.products-hero .pagehead__kicker {
  color: var(--on-red-muted);
}

.products-hero .pagehead__title {
  color: #fff;
}

.pagehead__title {
  font-size: clamp(2rem, 1.2rem + 2.2vw, 3.25rem);
  font-weight: var(--fw-800);
  line-height: 0.95;
  overflow-wrap: break-word;
}

/* The size the "We distribute" heading was set to, shared by the page titles and
   section headings that should read at the same weight as it. Placed after
   .pagehead__title so it wins over that rule's size. */
.heading-md {
  font-size: clamp(1.75rem, 1.2rem + 1.6vw, 2.75rem);
}

.pagehead__lead {
  margin: 1.5rem 0 0;
  max-width: 44em;
  color: var(--slate);
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  line-height: 1.5;
}

/* The same lead set under a section heading rather than a page title: it hands
   over to the content below with the gap .wrap-title would have left. */
.pagehead__lead--section {
  margin-bottom: clamp(2rem, 1.5rem + 2vw, 3.5rem);
}

/* A standing notice that reads as part of the page rather than as an overlay:
   the shelf grey of a card, a small red "i" to mark it as a note, and ink text
   instead of slate so it is not the quietest thing on the screen. Set at the
   lead's measure so it lines up with the sentence above it. */
.notice {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  /* Hugs its sentence rather than a measure it was never written to fit: the
     notice is one line of supplied copy, and a 44em cap broke it in two. It can
     still wrap, against the wrap's own width, on a narrow screen. */
  width: fit-content;
  max-width: 100%;
  margin: clamp(1.5rem, 1rem + 1.5vw, 2.25rem) 0 0;
  padding: 1rem 1.25rem;
  border-radius: 14px;
  background: var(--shelf);
  color: var(--ink);
  font-size: 1rem;
  font-weight: var(--fw-600);
  line-height: 1.5;
}

.notice::before {
  content: "i";
  flex: none;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  margin-top: 0.05rem;
  border-radius: 50%;
  background: var(--red);
  color: var(--on-red);
  font-size: 0.875rem;
  font-style: italic;
  font-weight: var(--fw-800);
  line-height: 1;
}

/* The notice used to open the hub and sit directly above the category grid,
   which is what needed this gap. It now closes the listing instead, on the hub
   as on every category page, so the grid is the first thing in the section and
   the notice's own top margin is all that is left to provide. */

/* Page header with a picture: the diagram on the left, the lead on the right. The diagram carries its own copy and its background is white, so
   multiply lets any off-white at the jpeg's edges drop into the page instead of
   showing as a box. Stacked below 900px, copy first. */
.pagehead--split {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: var(--col-gap);
  align-items: center;
}

/* The heading runs across both columns, centred over the diagram and the lead. */
.pagehead__heading {
  grid-column: 1 / -1;
  font-weight: var(--fw-800);
  line-height: 0.95;
  text-align: center;
}

/* The page title is screen-reader only here, so the lead is the first thing in
   its column and carries no gap above it. */
.pagehead--split .pagehead__lead {
  margin-top: 0;
}

.pagehead__figure {
  margin: 0;
}

.pagehead__figure img {
  display: block;
  width: 100%;
  height: auto;
  mix-blend-mode: multiply;
}

@media (max-width: 900px) {
  .pagehead--split {
    grid-template-columns: minmax(0, 1fr);
  }

  .pagehead__figure {
    max-width: 36rem;
    margin-inline: auto;
  }

  .pagehead__copy {
    order: -1;
  }

  .pagehead__heading {
    order: -2;
  }
}

/* Page header with the three core services as separate circles in one row.
   Heading and lead are centred above; each circle sizes its own type from its
   width (cqw) so the copy stays inside the circle at any width. Below 700px the
   row no longer fits and the circles stack. */
.pagehead--rings {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: var(--col-gap);
}

.pagehead--rings .pagehead__copy {
  max-width: 44rem;
  text-align: center;
}

.pagehead--rings .pagehead__lead {
  margin-top: 0;
}

.rings {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 0.25rem + 2.5vw, 2.5rem);
  width: 100%;
  margin: clamp(0.5rem, 0.25rem + 1vw, 1.5rem) 0 0;
  padding: 0;
  list-style: none;
}

.ring {
  --ring-tint: var(--shelf);
  --ring-line: var(--rule);
  --ring-accent: var(--slate);
  container-type: inline-size;
  aspect-ratio: 1;
  border: 2px solid var(--ring-line);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 30%, #fff 0%, var(--ring-tint) 100%);
  box-shadow: 0 1.25rem 2.5rem -1.5rem var(--ring-line);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ring--green {
  --ring-tint: #dfe9c4;
  --ring-line: #b9cd7e;
  --ring-accent: #7fa11f;
}

.ring--slate {
  --ring-tint: #d6dbe0;
  --ring-line: #aab2ba;
  --ring-accent: var(--slate);
}

.ring--red {
  --ring-tint: #f8d3d5;
  --ring-line: #ea9aa0;
  --ring-accent: var(--red);
}

.ring__inner {
  width: 76%;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.ring__num {
  display: grid;
  place-items: center;
  width: 2.4em;
  aspect-ratio: 1;
  margin-bottom: 0.5em;
  border-radius: 50%;
  background: var(--ring-accent);
  color: #fff;
  font-size: 6.5cqw;
  font-weight: var(--fw-700);
  line-height: 1;
}

.ring__title {
  margin: 0 0 0.45em;
  color: var(--ink);
  font-size: 6.4cqw;
  font-weight: var(--fw-800);
  line-height: 1.15;
}

.ring__text {
  margin: 0;
  color: var(--slate);
  font-size: 4cqw;
  line-height: 1.45;
}

@media (max-width: 700px) {
  .rings {
    grid-template-columns: minmax(0, 1fr);
    max-width: 26rem;
  }
}

/* A page header sits directly above a white section: don't pay that section's
   top padding twice. */
.pagehead + .section {
  padding-block-start: 0;
}

/* Full-bleed colour sections are a different case. Zeroing their padding too put
   the photo flush against the top edge of the colour block, so they keep a
   padding of their own and the page header keeps its own above it. */
.pagehead + .reach,
.reach-banner + .reach,
.pagehead + .giving,
.giving--partnership + .deliver--paddy,
.pagehead + .section--shelf {
  padding-block-start: clamp(2rem, 1rem + 1.5vw, 3rem);
}

/* The shelf band that wraps a card straight after a page header: the card sits
   the same distance from the band's bottom edge as from its top. */
.pagehead + .section--shelf:not(.distribute):not(.deliver) {
  padding-block-end: clamp(2rem, 1rem + 1.5vw, 3rem);
}

/* A photo band straight after the page header is not a card band, so it keeps the
   section's full padding on both sides and its text sits in the middle of the
   band rather than high in it. */
@media (min-width: 901px) {
  .pagehead + .section--shelf.distribute {
    padding-block-start: var(--section);
  }
}

.section--shelf {
  background: var(--shelf);
}

/* The contact block closes every page, so it takes a tighter vertical rhythm
   than a full section: the details are a destination, not a story beat. */
.section--tight {
  padding-block: clamp(1.75rem, 1.25rem + 2vw, 3.25rem);
}

.split {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-items: end;
  column-gap: var(--col-gap);
  row-gap: 1.25rem;
  margin-bottom: clamp(2.5rem, 1.5rem + 3vw, 4.5rem);
}

.split > :first-child {
  grid-column: 1 / span 6;
}

.split > :last-child {
  grid-column: 8 / -1;
}

/* A section that now opens on a single claim runs its heading full width instead
   of in a split slot. It cannot stay inside .split: with the lead paragraph gone
   the heading would be the only child, matching both :first-child and
   :last-child, and the later rule would shunt it into the right-hand column. */
.wrap-title {
  max-width: 22em;
  margin-bottom: clamp(2rem, 1.5rem + 2vw, 3.5rem);
}

/* Where the heading is followed by a one-line cue rather than a paragraph, the
   cue reads as part of the heading and sits tight under it, with the grid
   starting the next beat. */
.wrap-title--tight {
  margin-bottom: 0.75rem;
}

.split p:not(.lead) {
  max-width: 38em;
  color: var(--slate);
}

/* ---------- About ---------- */

.about {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  /* stretch, not center: the photo then runs the full height of the text column,
     from the "Our story" line down to the bottom of the NDA licence block. */
  align-items: stretch;
  column-gap: var(--col-gap);
  row-gap: 2.5rem;
}

.about__photo {
  grid-column: 1 / span 6;
  overflow: hidden;
  border-radius: 16px;
}

.about__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The photo is a 3:2 landscape stretched into a much taller column, so cover
     keeps only the middle of the frame. Bias left to hold the mother's head and
     raised arm, which a centred crop would cut off. */
  object-position: 45% 50%;
}

.about__text {
  grid-column: 8 / -1;
}

.about__text h3 {
  margin-bottom: 1rem;
}

.about__text p {
  max-width: 36em;
}

/* The drone shot fills the left of the section edge to edge and fades out
   toward the text, which sits on the plain shelf background on the right. The
   fade is a mask rather than an overlay gradient, so it blends into whatever
   the section's background is. Long and shallow (opaque for the first third,
   then easing out) so there is no visible edge where the photograph ends. */
.distribute {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(380px, 34vw, 500px);
  overflow: hidden;
}

.distribute__media {
  position: absolute;
  inset: 0 auto 0 0;
  width: 57%;
  margin: 0;
  -webkit-mask-image: linear-gradient(to right, #000 22%, rgba(0, 0, 0, 0.8) 42%, rgba(0, 0, 0, 0.5) 62%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0.05) 92%, transparent 100%);
  mask-image: linear-gradient(to right, #000 22%, rgba(0, 0, 0, 0.8) 42%, rgba(0, 0, 0, 0.5) 62%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0.05) 92%, transparent 100%);
}

.distribute__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The wrap is a stacking context above the photo; the body takes the right
   half, which is clear of the photo's opaque part. The wrap itself lets the
   pointer through, so hovering the photo reaches the photo rather than the
   empty wrap laid over it. */
.distribute .wrap {
  position: relative;
  pointer-events: none;
}

.distribute__body {
  width: min(100%, 46%);
  margin-left: auto;
  pointer-events: auto;
}

/* Black and white until the pointer is over it, as on the leadership page. A
   touch screen has no hover, so it gets the colour straight away. */
.distribute__media img {
  filter: grayscale(1);
}

@media (hover: hover) {
  .distribute__media:hover img {
    filter: grayscale(0);
  }
}

@media (hover: none) {
  .distribute__media img {
    filter: grayscale(0);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .distribute__media img {
    transition: filter 0.45s ease;
  }
}

/* Smaller and grey, so the heading sits quietly beside the photograph instead
   of competing with it. The slate is the site's body-grey, which holds 4.5:1 on
   the shelf background. */
.distribute h2 {
  color: var(--slate);
}

.capsule-list {
  margin: 1.5rem 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
}

.capsule-list li {
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--rule);
  font-weight: var(--fw-580);
}

.about__text .capsule-list {
  border-top: 0;
}

.about__text .capsule-list li {
  border-bottom: 0;
}

.capsule-list li::before {
  content: "";
  flex: none;
  width: 18px;
  height: 8px;
  border-radius: 999px;
  background: var(--red);
  transform: translateY(-0.2em);
}

/* A section that opens a page with no page header above it: the full section
   padding is sized to separate two blocks, not to sit under the site header. */
.section--opening {
  padding-block-start: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
}

/* Stack the seal, vision and mission in one column at every viewport size. */
.stance {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  row-gap: 2rem;
  max-width: 52rem;
  margin-inline: auto;
  text-align: center;
}

.stance__seal {
  justify-self: center;
  width: clamp(120px, 18vw, 180px);
}

.stance__item + .stance__item {
  margin-top: clamp(1rem, 2vw, 2rem);
}

.stance__item p {
  margin: 0;
}

.stance__vision,
.stance__mission {
  color: var(--red);
  font-size: clamp(1.0625rem, 0.95rem + 0.35vw, 1.25rem);
  font-weight: var(--fw-400);
  line-height: 1.5;
}

.stance__vision {
  font-size: clamp(1.5rem, 1.1rem + 1.8vw, 2.5rem);
  line-height: 1.3;
  background: linear-gradient(90deg, #000 0%, #000 12%, #e5142d 38%, #f26b16 65%, #d91488 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* The colour sweep the vision statement on the About page uses (black into red,
   orange and magenta), on any short phrase that should carry it. Bold, so the
   colour has some weight to show in. */
.gradient-text {
  background: linear-gradient(90deg, #000 0%, #000 12%, #e5142d 38%, #f26b16 65%, #d91488 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: var(--fw-800);
}

.purpose__label,
.values__title {
  margin-bottom: 0.85rem;
  color: var(--red);
  font-size: clamp(1.25rem, 1.05rem + 0.6vw, 1.625rem);
  font-weight: var(--fw-650);
  line-height: 1.15;
}

.stance .purpose__label,
.values__title {
  color: var(--slate);
  font-size: clamp(1.5rem, 1.1rem + 1.8vw, 2.5rem);
}

.values {
  margin-top: clamp(3rem, 2rem + 2vw, 4.5rem);
}

/* The cancer support story under the mission: heading, partner label, a short
   paragraph and a link through to the CHA page. */
.cancer-story {
  margin-top: clamp(3rem, 2rem + 3vw, 5rem);
}

.cancer-story__org {
  color: var(--red);
  font-size: 0.9375rem;
  font-weight: var(--fw-800);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.stance__item p.cancer-story__org {
  margin: 0.25rem 0 0;
}

.stance__item p.cancer-story__text {
  max-width: 40em;
  margin: 0.75rem auto 1.5rem;
  color: var(--slate);
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  line-height: 1.65;
}

.company-overview {
  margin: clamp(3rem, 2rem + 2vw, 4.5rem) 0 0;
  color: var(--slate);
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.875rem);
  line-height: 1.4;
  /* Centred under the values, on a measure that breaks it into two even lines.
     (It used to be justified across the whole grid, which stretched the gaps
     between words.) */
  max-width: 34em;
  margin-inline: auto;
  text-align: center;
}

/* The global paragraph rule sets text-wrap: pretty on the <p> itself, which would
   win over anything set on the box around it. */
.company-overview p {
  text-wrap: balance;
}

/* The mission sits under the values, set like the vision at the top of the group. */
.company-mission {
  margin-top: clamp(3rem, 2rem + 3vw, 5rem);
}

.values__title {
  margin-bottom: 1rem;
  text-align: center;
}

.values__list {
  --values-gap: clamp(1rem, 2vw, 1.75rem);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--values-gap);
  margin: 0;
  counter-reset: value-step;
}

/* Five values in a three-column grid leave two on the second row. Halving each
   column lets those two sit centred under the row above rather than hanging off
   the left edge with a hole on the right. */
@media (min-width: 901px) {
  .values__list {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .values__list > div {
    grid-column: span 2;
  }

  .values__list > div:nth-child(4) {
    grid-column: 2 / span 2;
  }

  .values__list > div:nth-child(5) {
    grid-column: 4 / span 2;
  }
}

.values__list > div {
  position: relative;
  min-width: 0;
  padding: 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 20px;
  background: var(--paper);
  counter-increment: value-step;
}

.values__list > div::before {
  content: counter(value-step, decimal-leading-zero);
  display: grid;
  place-items: center;
  position: absolute;
  top: 1.5rem;
  left: 1.5rem;
  z-index: 1;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.95);
  color: var(--red);
  font-size: 0.75rem;
  font-weight: var(--fw-800);
}

.values__media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 14px;
  background: var(--shelf);
}

.values__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
  filter: grayscale(1);
}

.values__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 35%, rgba(255, 255, 255, 0.35) 50%, transparent 65%);
  transform: translateX(-110%);
}

/* Knowledge and Achievement have no photograph yet, so they carry no media block
   at all rather than a grey panel standing in for one. The numbered badge is
   pinned where that image would start, so it would land on the name: those two
   cards drop it and the row closes on a lighter note. */
.values__list > div.values__item--text::before {
  content: none;
}

.values__list dt {
  margin: 0;
  font-size: clamp(1.5rem, 1.2rem + 0.8vw, 1.875rem);
  font-weight: var(--fw-800);
  line-height: 1.1;
}

.values__name {
  display: block;
  margin: 1rem 0.5rem 0.6rem;
}

.values__list dd {
  margin: 0 0.5rem 0.75rem;
  color: var(--slate);
  font-size: 1rem;
  line-height: 1.6;
}

.values__list > div:focus-visible {
  border-color: var(--red);
  box-shadow: 0 16px 36px rgba(35, 31, 32, 0.12);
}

.values__list > div:focus-visible .values__name {
  color: var(--red);
}

.values__list > div:focus-visible .values__media img {
  filter: grayscale(0);
}

@media (hover: none) {
  .values__media img {
    filter: grayscale(0);
  }
}

@media (hover: hover) {
  .values__list > div:hover {
    border-color: var(--red);
    box-shadow: 0 16px 36px rgba(35, 31, 32, 0.12);
  }

  .values__list > div:hover .values__name {
    color: var(--red);
  }

  .values__list > div:hover .values__media img {
    filter: grayscale(0);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .values__list > div {
    transition: transform 0.35s ease, border-color 0.25s ease, box-shadow 0.35s ease;
  }

  .values__media img {
    transition: transform 0.65s cubic-bezier(0.22, 1, 0.36, 1), filter 0.45s ease;
  }

  .values__media::after {
    transition: transform 0.75s ease;
  }

  .values__name {
    transition: color 0.25s ease;
  }

  .values__list > div:focus-visible {
    transform: translateY(-8px);
  }

  .values__list > div:focus-visible .values__media img {
    transform: scale(1.07);
  }

  .values__list > div:focus-visible .values__media::after {
    transform: translateX(110%);
  }

  @media (hover: hover) {
    .values__list > div:hover {
      transform: translateY(-8px);
    }

    .values__list > div:hover .values__media img {
      transform: scale(1.07);
    }

    .values__list > div:hover .values__media::after {
      transform: translateX(110%);
    }
  }
}

.licence {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
  margin-top: 1.75rem;
  color: var(--slate);
  font-size: 1rem;
  line-height: 1.5;
}

.licence img {
  width: min(100%, 480px);
}

/* ---------- What we do ---------- */

/* One card, full width. The row used to carry a second audience card, so a
   single column now fills it rather than leaving half the row as a gap. */
.audiences {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1rem, 2vw, 1.5rem);
}

.audience h3 {
  margin-bottom: 1rem;
  font-size: clamp(1.5rem, 1.2rem + 0.8vw, 1.875rem);
  font-weight: var(--fw-800);
}

.audience p {
  max-width: 36em;
}

/* Copy left, photo right, with no card behind them. The photograph runs in from
   the right edge of the page and fades out toward the copy, the same mask and
   layout the deliver section below uses, so it blends into the shelf grey rather
   than ending in a hard edge. The copy keeps the left half clear of the photo's
   opaque part. */
.audience-band {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(340px, 34vw, 500px);
  overflow: hidden;
}

/* The wrap sits above the photo and lets the pointer through, so hovering the
   photo reaches the photo rather than the empty wrap laid over it; the copy
   takes the pointer back. */
.audience-band > .wrap {
  position: relative;
  pointer-events: none;
}

.audience__copy {
  pointer-events: auto;
}

.audience__copy {
  width: min(100%, 52%);
}

.audience__media {
  position: absolute;
  inset: 0 0 0 auto;
  width: 57%;
  margin: 0;
  -webkit-mask-image: linear-gradient(to left, #000 22%, rgba(0, 0, 0, 0.8) 42%, rgba(0, 0, 0, 0.5) 62%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0.05) 92%, transparent 100%);
  mask-image: linear-gradient(to left, #000 22%, rgba(0, 0, 0, 0.8) 42%, rgba(0, 0, 0, 0.5) 62%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0.05) 92%, transparent 100%);
}

.audience__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Black and white until the pointer is over it, as on the section below. A touch
   screen has no hover, so it gets the colour straight away. */
.audience__media img {
  filter: grayscale(1);
}

@media (hover: hover) {
  .audience__media:hover img {
    filter: grayscale(0);
  }
}

@media (hover: none) {
  .audience__media img {
    filter: grayscale(0);
  }
}

/* The list follows a paragraph here, so it takes the default top margin from
   .capsule-list; two pills to a row keeps the column short enough for the photo
   not to be stretched far past its own shape. */
.audience__body .capsule-list li {
  padding: 0.4rem 0;
}

.audience .capsule-list {
  border-top: 0;
}

.audience .capsule-list li {
  border-bottom: 0;
  color: var(--slate);
}

.audience .capsule-list li::before {
  background: #aeb4bc;
}

.capsule-list--grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 1.5rem;
}

.capsule-list--grid li {
  font-size: 0.9375rem;
}

/* ---------- Healthcare segments ---------- */

.segments {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The category grid is the one place on the site where the tile count fights the
   layout: five categories in a four-up track set left an orphan alone on the
   second row, and the empty band beside it was the most obvious flaw on the
   homepage. The track count is pinned per range rather than left to auto-fit,
   because auto-fit's arithmetic drops from five tiles to four across a 30px
   band and reintroduces the orphan exactly there. */
.segments--categories {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

/* Between the five-up and stacked ranges, six tracks solve the odd count: three
   tiles span two tracks each on the first row, and the leftover pair span three
   each on the second, so both rows are full width and the short row is centred
   by construction. The build marks which tiles those are (segment--wide for a
   pair, segment--full for a loner), so adding a category cannot break it. */
@media (max-width: 78rem) {
  .segments--categories {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

@media (max-width: 78rem) and (min-width: 41rem) {
  .segments--categories > li {
    grid-column: span 2;
  }

  .segments--categories > li.segment--wide {
    grid-column: span 3;
  }

  .segments--categories > li.segment--full {
    grid-column: span 6;
  }
}

/* Below the house one-column breakpoint a two-up pair leaves titles like
   "Medical Consumables" wrapping over three lines, so stack instead. */
@media (max-width: 40.99rem) {
  .segments--categories {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Spells out what the tiles do, for anyone who has not worked out that the
   image is the link. This line exists only on the products hub, where it is the
   sole visible heading for the section — a usage hint parked as the page's
   main signpost — so it is set as a lead-in rather than as quiet small print. */
.segments__hint {
  margin: 0 0 1.75rem;
  max-width: 44em;
  color: var(--ink);
  font-size: clamp(1.0625rem, 0.95rem + 0.45vw, 1.3125rem);
  font-weight: var(--fw-550);
  line-height: 1.45;
}

/* The whole tile is the link. It is dressed as a card and carries a visible
   "View range" cue, so it reads as tappable before anyone hovers it. */
.segment a {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  padding: 10px;
  border: 1px solid var(--rule);
  border-radius: 20px;
  background: #fff;
  color: inherit;
  text-decoration: none;
}

.segment a:hover,
.segment a:focus-visible {
  transform: translateY(-3px);
  border-color: var(--ink);
  box-shadow: 0 18px 40px rgba(35, 31, 32, 0.12);
}

/* The frame owns the crop, the aspect ratio and the loading state; the image
   inside it is absolutely positioned to fill. Before, the <img> carried the
   aspect-ratio itself, which left nowhere to put a placeholder — a shimmering
   loading tile needs a box that is already the right shape before the picture
   lands, or the grid reflows as the tiles resolve one by one. */
.segment__media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 12px;
  /* Near-white rather than --shelf, because the icons sit back from their own
     edges at rest and this is what shows through behind them. The shimmer below
     is tinted to match, so it still reads while a picture loads. */
  background: var(--paper);
}

.segment__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* While the image is in flight the frame shows a slow diagonal sheen, then the
   picture cross-fades over it. Both are opt-in via .is-loaded, which site.js
   sets on the frame's load event, so a cached image that is already decoded by
   the time script runs never flashes a shimmer at all. */
.segment__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(241, 242, 244, 0) 20%,
    rgba(241, 242, 244, 0.9) 50%,
    rgba(241, 242, 244, 0) 80%
  );
  transform: translateX(-100%);
}

@media (prefers-reduced-motion: no-preference) {
  .segment__media:not(.is-loaded)::after {
    animation: sheen 1.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
  }

  /* The opacity transition itself lives with .segment img further up, where
     the hover transform is declared, so the two cannot overwrite each other. */
  .segment__media img {
    opacity: 0;
  }

  .segment__media.is-loaded img {
    opacity: 1;
  }
}

/* The tile draws the icon back from its own edges at rest and lets it come
   forward on hover, which reads as the picture settling in rather than as a
   zoom effect. The icon files are already generated at the frame's own 4:3
   ratio (see the asset pipeline), so there is nothing for object-fit to crop
   and the only thing moving is this transform.

   The resting scale is what makes the hover legible, so it is applied outside
   the reduced-motion guard along with its counterpart: a visitor who has
   asked for less motion still gets the composed state, just without the
   transition between the two.

   Held well off the edges on purpose — the icon at rest should read as sitting
   inside the tile rather than filling it, so that arriving at full size on
   hover is the thing that happens rather than something already true. */
.segment__media img {
  transform: scale(0.65);
}

.segment a:hover img,
.segment a:focus-visible img {
  transform: scale(1);
}

/* The sheen is a light source passing over the frame, so it runs on its own
   clock and does not pause when the tile is hovered — the hover scale is on the
   img beneath it, which is invisible until the picture has landed. */
@keyframes sheen {
  to {
    transform: translateX(100%);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .segment a {
    transition:
      transform 0.18s ease,
      box-shadow 0.18s ease,
      border-color 0.18s ease;
  }

  /* Opacity and transform share one declaration: a bare `transition: transform`
     shorthand here would wipe out the load fade set on the same element, since
     the tile image is both arriving and hoverable at once. */
  .segment img,
  .segment__cta::after {
    transition:
      opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
      transform 0.3s ease;
  }
}

.segment h3 {
  margin-top: 1rem;
  font-size: 1.125rem;
}

.segment__count {
  margin-top: 0.25rem;
  color: var(--slate);
  font-size: 0.9rem;
}

/* Persistent, not hover-only: a visitor on a phone never sees the hover state,
   so the affordance has to be there at rest. */
.segment__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: auto;
  padding-top: 1rem;
  color: var(--red);
  font-size: 0.9375rem;
  font-weight: var(--fw-650);
}

.segment__cta::after {
  content: "\2192";
}

.segment a:hover .segment__cta::after {
  transform: translateX(4px);
}

/* Categories with no lifestyle photograph yet sit on a neutral tile of the same
   shape, so the grid keeps its rhythm instead of leaving a hole. The geometry
   now lives on .segment__media, which wraps this too, so the placeholder only
   has to fill its frame. */
.segment__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 1rem;
  color: var(--slate);
  font-size: 0.9rem;
  text-align: center;
}

/* ---------- Products ---------- */

/* Keep category introductions short so the range starts near the top. */
.page--catalog .pagehead {
  padding-block: 1.5rem;
}

.page--catalog .pagehead__kicker {
  margin-bottom: 0.6rem;
  font-size: 0.875rem;
}

.page--catalog .pagehead__title {
  line-height: 1.15;
}

.page--catalog .pagehead__lead {
  margin-top: 0.75rem;
  font-size: 1rem;
}

.page--catalog .section {
  padding-block: 1.5rem 2.5rem;
}

.page--catalog .pagehead + .section {
  padding-top: 0;
}

.page--catalog .group__title {
  margin-bottom: 1rem;
  font-size: clamp(1.375rem, 1rem + 1vw, 1.75rem);
  line-height: 1.2;
}

.products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

.product {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  align-items: start;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: 14px;
  background: #fff;
}

.product__stage {
  position: relative;
  height: 340px;
  overflow: hidden;
  border-radius: 12px;
  background: var(--shelf);
}

.product__stage img {
  position: absolute;
  inset: 10% 9% 12%;
  width: 82%;
  height: 78%;
  object-fit: contain;
  filter: drop-shadow(0 22px 20px rgba(35, 31, 32, 0.16)) drop-shadow(0 3px 5px rgba(35, 31, 32, 0.08));
}

/* Show the whole product in a compact image frame. */
.product--photo .product__stage {
  background: #fff;
}

.product--photo .product__stage img {
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  filter: none;
}

/* A landscape shot takes a whole row, photo beside the text. */
.product--wide {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  align-items: stretch;
}

.product--wide .product__stage {
  aspect-ratio: 4 / 3;
}

.product--wide .product__stage img {
  object-position: 50% 50%;
}

.product--wide .product__body {
  padding: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
}

.product--photo .badge {
  background: #fff;
  color: var(--red);
}

.product .badge {
  top: 8px;
  left: 8px;
  max-width: calc(100% - 16px);
  padding: 0.3rem 0.5rem;
  font-size: 0.6875rem;
  line-height: 1.2;
}

.badge {
  position: absolute;
  z-index: 1;
  top: 14px;
  left: 14px;
  padding: 0.4rem 0.8rem;
  border-radius: 999px;
  background: var(--red);
  color: #fff;
  font-size: 0.8125rem;
  font-weight: var(--fw-650);
  line-height: 1;
}

.product__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
  padding: 0.65rem 0.75rem;
  font-size: 0.875rem;
  line-height: 1.5;
}

.product__name {
  font-size: clamp(1.125rem, 1rem + 0.35vw, 1.375rem);
  font-weight: var(--fw-800);
  line-height: 1.2;
}

.product__desc {
  max-width: 40ch;
  margin: 0.5rem 0 0.75rem;
  color: var(--slate);
}

/* Composition as one run-on sentence instead of a side panel of rows: the
   strength reads as part of the ingredient name, and nine rows of dotted leaders
   pushed the card description and facts strip off the first screen. */
.comp__title {
  margin: 0.5rem 0 0.2rem;
  color: var(--slate);
  font-size: 0.8125rem;
  font-weight: var(--fw-600);
}

.comp {
  margin: 0 0 0.75rem;
  color: var(--slate);
  font-size: 0.8125rem;
  line-height: 1.5;
  text-wrap: pretty;
}

.facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  margin: auto 0 0;
  padding-top: 0.65rem;
  border-top: 1px solid var(--rule);
}

.facts dt {
  color: var(--slate);
  font-size: 0.8125rem;
}

.facts dd {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: var(--fw-600);
}

@media (max-width: 900px) {
  .distribute__media {
    position: relative;
    inset: auto;
    width: 100%;
    height: clamp(200px, 48vw, 320px);
    margin-bottom: -2.5rem;
    -webkit-mask-image: linear-gradient(to bottom, #000 40%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 40%, transparent 100%);
  }

  .distribute {
    display: block;
    min-height: 0;
    padding-top: 0;
  }

  .distribute__body {
    width: 100%;
  }

  .products {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------- Coming soon ---------- */

.soon {
  padding: clamp(1.5rem, 1rem + 2vw, 2.75rem);
  border-radius: 20px;
  background: #fff;
}

.soon__copy {
  max-width: 40rem;
}

.badge--inline {
  position: static;
  display: inline-block;
  margin-bottom: 1rem;
}

.soon__trio {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  margin: clamp(1.5rem, 1rem + 2vw, 2.5rem) 0 0;
  padding: 0;
  list-style: none;
}

.soon__trio img,
.soon__card img {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 12px;
  object-fit: cover;
  object-position: 50% 80%;
}

.soon__card img {
  aspect-ratio: 4 / 3;
  object-position: 50% 50%;
}

.soon__trio h4,
.soon__card h3 {
  margin-top: 1rem;
  font-size: 1.5rem;
  font-weight: var(--fw-800);
  line-height: 1.1;
}

.soon__trio p,
.soon__card p {
  margin-top: 0.4rem;
  color: var(--slate);
  font-size: 0.9375rem;
}

.soon__more {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  margin: clamp(1rem, 2vw, 1.5rem) 0 0;
  padding: 0;
  list-style: none;
}

.soon__card {
  padding: 10px 10px 1.25rem;
  border-radius: 20px;
  background: #fff;
}

.soon__card h3,
.soon__card p {
  margin-inline: 0.75rem;
}

/* ---------- Deliver ---------- */

/* The van runs in from the right edge of the page and fades out toward the copy
   on the left, the mirror of the distribute section above. The fade is a mask,
   so it blends into the page background; opaque for the last fifth and easing
   out to clear just short of the text column. */
.deliver {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(340px, 34vw, 500px);
  overflow: hidden;
}

.deliver__media {
  position: absolute;
  inset: 0 0 0 auto;
  width: 57%;
  margin: 0;
  -webkit-mask-image: linear-gradient(to left, #000 22%, rgba(0, 0, 0, 0.8) 42%, rgba(0, 0, 0, 0.5) 62%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0.05) 92%, transparent 100%);
  mask-image: linear-gradient(to left, #000 22%, rgba(0, 0, 0, 0.8) 42%, rgba(0, 0, 0, 0.5) 62%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0.05) 92%, transparent 100%);
}

.deliver__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 60%;
}

/* The wrap sits above the photo; the copy takes the left half, clear of the
   photo's opaque part. */
.deliver .wrap {
  position: relative;
}

.deliver__copy {
  width: min(100%, 46%);
}

.deliver .lead {
  margin-top: 1rem;
  color: var(--slate);
}

/* ---------- Reach ---------- */

.reach-banner {
  overflow: hidden;
}

.reach-banner img {
  width: 100%;
  height: auto;
}

/* Tighter than a full section: the map is the tallest thing in the band, so the
   padding above and below it is what decides how much red sits around it. */
.reach {
  padding-block: clamp(2rem, 1.5rem + 2vw, 3.5rem);
  background: var(--paper);
  color: var(--ink);
}

.reach__grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 5rem);
}

.reach h2 {
  font-size: clamp(2.25rem, 1.3rem + 2vw, 3.25rem);
  line-height: 1.05;
}

.reach .lead {
  margin-top: 1.25rem;
  color: var(--slate);
}

.reach__map {
  margin: 0;
}

.reach__map img {
  width: 100%;
  max-width: 460px;
  margin-left: auto;
}

/* The courier photo runs in from the left edge of the page and fades into the white
   behind the copy; the grid is pushed right by the width of the photo that is
   still solid, so the copy sits on plain white. --reach-wrap is the .wrap width. */
.reach--photo {
  --reach-wrap: min(100% - 2 * var(--gutter), var(--container));
  position: relative;
  overflow: hidden;
}

.reach__photo {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc((100% - var(--reach-wrap)) / 2 + var(--reach-wrap) * 0.36);
  margin: 0;
  -webkit-mask-image: linear-gradient(to right, #000 52%, rgba(0, 0, 0, 0.7) 68%, rgba(0, 0, 0, 0.3) 84%, transparent 100%);
  mask-image: linear-gradient(to right, #000 52%, rgba(0, 0, 0, 0.7) 68%, rgba(0, 0, 0, 0.3) 84%, transparent 100%);
}

.reach__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The courier stands at the right edge of the original, which is the left edge
     once mirrored. Anchor the crop there so he is never cropped out, whatever
     the band's proportions. */
  object-position: right center;
  transform: scaleX(-1);
}

.reach--photo .reach__grid {
  position: relative;
  padding-left: calc(var(--reach-wrap) * 0.38);
  grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
  gap: clamp(1rem, 0.5rem + 1.5vw, 2rem);
}

/* The copy column is held to what the heading needs so the map gets the rest. The
   map is a transparent cut-out trimmed to the country, so it can be drawn at the
   column's full width without a box of white laid over the copy. */
.reach--photo .reach__map img {
  width: 100%;
  max-width: none;
  margin: 0;
}

/* The label above a service band: the service's number in a red disc, then its name
   in red. Set well above body size so it reads as the band's title. */
.band-kicker {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0 0 1rem;
  color: var(--red);
  font-size: clamp(1.5rem, 1.15rem + 1.2vw, 2.25rem);
  font-weight: var(--fw-800);
  line-height: 1.15;
}

.band-kicker__num {
  display: grid;
  flex: none;
  place-items: center;
  width: 1.6em;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  font-size: 0.85em;
  font-weight: var(--fw-700);
  line-height: 1;
}

/* The statement that opens a band, in the same slate as the copy around it. */
.story-experience .statement {
  color: var(--slate);
}

/* ---------- Manufacturer value proposition (Partners) ---------- */

/* A full-width band of its own, in the shelf grey with white rows, so it reads as a
   different thing from the white page that follows it. */
.value {
  padding-block: clamp(2.75rem, 1.5rem + 4vw, 5.5rem);
  background: var(--shelf);
}

.value__kicker {
  margin: 0 0 1rem;
  color: var(--red);
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.25rem);
  font-weight: var(--fw-800);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.value__title {
  font-weight: var(--fw-800);
  line-height: 1.05;
}

.value__lead {
  max-width: 52em;
  margin: clamp(1.25rem, 1rem + 1vw, 2rem) 0 0;
  color: var(--slate);
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.375rem);
  line-height: 1.6;
}

.value__steps-title {
  margin-top: clamp(2.5rem, 1.5rem + 3.5vw, 4.5rem);
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem);
  font-weight: var(--fw-800);
  line-height: 1.1;
}

/* The five steps as a process: chevrons pointing along the sequence, each notched
   to take the tip of the one before. A drop shadow on the list, not the chevrons,
   because clip-path would cut a shadow off the chevrons themselves. Below 1000px
   they stack and point down. */
.steps {
  --tip: 1.75rem;
  --gap: 0.4rem;
  display: flex;
  margin: clamp(1.25rem, 1rem + 1vw, 2rem) 0 0;
  padding: 0;
  list-style: none;
  filter: drop-shadow(0 0.5rem 0.75rem rgba(35, 31, 32, 0.09));
}

.step {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.35rem;
  min-height: 9.5rem;
  margin-left: calc(var(--gap) - var(--tip));
  padding: 1.5rem calc(var(--tip) + 0.5rem) 1.5rem calc(var(--tip) + 1rem);
  background: #fff;
  clip-path: polygon(0 0, calc(100% - var(--tip)) 0, 100% 50%, calc(100% - var(--tip)) 100%, 0 100%, var(--tip) 50%);
}

.step:first-child {
  margin-left: 0;
  padding-left: 1.5rem;
  clip-path: polygon(0 0, calc(100% - var(--tip)) 0, 100% 50%, calc(100% - var(--tip)) 100%, 0 100%);
}

.step__num {
  color: var(--red);
  font-size: clamp(1.25rem, 1rem + 0.8vw, 1.75rem);
  font-weight: var(--fw-800);
  line-height: 1;
}

.step__name {
  color: var(--ink);
  font-size: clamp(1rem, 0.85rem + 0.5vw, 1.3125rem);
  font-weight: var(--fw-800);
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.step__what {
  color: var(--slate);
  font-size: clamp(0.9375rem, 0.9rem + 0.2vw, 1.0625rem);
  line-height: 1.35;
}

/* On hover a step fills with the brand red and lifts, its text turns white and the
   number slides along the direction of travel. The lift is dropped for anyone who
   has asked for less motion; the colour change stays. */
.step {
  position: relative;
  transition: background-color 0.25s ease;
}

.step__num,
.step__name,
.step__what {
  transition: color 0.25s ease, transform 0.25s ease;
}

@media (hover: hover) {
  .step:hover {
    z-index: 1;
    background: var(--red);
  }

  .step:hover .step__num,
  .step:hover .step__name,
  .step:hover .step__what {
    color: #fff;
  }
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .step {
    transition: background-color 0.25s ease, transform 0.25s ease;
  }

  .step:hover {
    transform: translateY(-6px);
  }

  .step:hover .step__num {
    transform: translateX(6px);
  }
}

@media (max-width: 1000px) {
  .steps {
    --tip: 1.25rem;
    flex-direction: column;
  }

  .step,
  .step:first-child {
    /* The row rule's `flex: 1 1 0` is fatal in a column. With a zero basis and
       `min-height: 0` there is no content contribution left to size the card,
       so each one collapses to its own padding and clip-path shears the text
       off. Back to content sizing: these cards have to be as tall as they read. */
    flex: 0 0 auto;
    align-items: center;
    min-height: 0;
    margin-left: 0;
    padding: calc(var(--tip) + 0.9rem) 1.5rem calc(var(--tip) + 0.9rem);
    text-align: center;
    clip-path: polygon(0 0, 50% var(--tip), 100% 0, 100% calc(100% - var(--tip)), 50% 100%, 0 calc(100% - var(--tip)));
  }

  .step + .step {
    margin-top: calc(var(--gap) - var(--tip));
  }

  .step:first-child {
    padding-top: 1.25rem;
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--tip)), 50% 100%, 0 calc(100% - var(--tip)));
  }
}

.value__action {
  margin: clamp(1.75rem, 1.25rem + 2vw, 2.75rem) 0 0;
}

/* ---------- Pills ---------- */

/* Short names set as pills, the shape the site already uses for buttons: the
   countries we import from, and the categories offered as a way into the range.
   Six names are few enough that a map would be mostly empty sea, and flags bring
   licensing and politics along with them. A pill that is a link darkens its ring
   on hover and keyboard focus. */
.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: clamp(1.25rem, 1rem + 1vw, 2rem) 0 0;
  padding: 0;
  list-style: none;
}

.pills li {
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: var(--ink);
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  font-weight: var(--fw-650);
}

.pills li:not(:has(a)) {
  padding: 0.7rem 1.4rem;
}

.pills a {
  display: block;
  padding: 0.7rem 1.4rem;
  border-radius: 999px;
  color: inherit;
  text-decoration: none;
}

.pills li:has(a:hover),
.pills li:has(a:focus-visible) {
  border-color: var(--ink);
}

/* ---------- Payment methods ---------- */

/* A quiet strip at the foot of the product pages: one plain sentence and the four
   marks, set on a rule. The marks are different shapes, so each carries the height
   it needs (--shown, set per logo from src/_data/payments.mjs) to look the same
   size as its neighbours, and they shrink together on a phone. */
.payments {
  padding-block: clamp(2.5rem, 1.5rem + 3vw, 4.5rem) clamp(3rem, 2rem + 4vw, 6rem);
}

.payments .wrap {
  padding-top: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  border-top: 1px solid var(--rule);
}

.payments__title {
  color: var(--slate);
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  font-weight: var(--fw-700);
  letter-spacing: 0;
  line-height: 1.3;
}

.payments__logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem clamp(1.75rem, 1rem + 3vw, 3.5rem);
  margin: clamp(1.25rem, 1rem + 1vw, 1.75rem) 0 0;
  padding: 0;
  list-style: none;
}

.payments__logos img {
  display: block;
  width: auto;
  height: calc(var(--shown) * 1px);
}

@media (max-width: 520px) {
  .payments__logos img {
    height: calc(var(--shown) * 0.8px);
  }
}

/* ---------- Search ---------- */

/* The field and its button as one pill: the input takes the width and the button
   sits inside the right end. The ring is drawn on the pill, not the input, so the
   whole thing lights up when the field has focus. */
.searchbox {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 40rem;
  margin-top: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
  padding: 0.35rem 0.35rem 0.35rem 1.4rem;
  border: 1.5px solid var(--rule);
  border-radius: 999px;
  background: var(--paper);
}

.searchbox:focus-within {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(35, 31, 32, 0.12);
}

.searchbox__input {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 1.0625rem;
  outline: 0;
}

.searchbox__input::placeholder {
  color: var(--slate);
}

/* Cancel button the browser draws inside type="search"; the field is cleared by
   selecting and typing, and the browser's own X reads as a second control. */
.searchbox__input::-webkit-search-cancel-button {
  display: none;
}

.searchbox__btn {
  flex: none;
}

.search__status {
  min-height: 1.5em;
  margin: 0 0 1.5rem;
  color: var(--slate);
  font-size: 1.0625rem;
  font-weight: var(--fw-600);
}

.results {
  display: grid;
  gap: 0.75rem;
  max-width: 52rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.result__link {
  display: grid;
  gap: 0.2rem;
  padding: 1.1rem 1.4rem;
  border: 1px solid var(--rule);
  border-radius: 20px;
  color: inherit;
  text-decoration: none;
  transition: border-color 0.2s;
}

.result__link:hover,
.result__link:focus-visible {
  border-color: var(--ink);
}

.result__meta {
  color: var(--red);
  font-size: 0.8125rem;
  font-weight: var(--fw-700);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.result__name {
  color: var(--ink);
  font-size: clamp(1.125rem, 1.05rem + 0.3vw, 1.3125rem);
  font-weight: var(--fw-800);
  line-height: 1.2;
}

.result__snippet {
  color: var(--slate);
  font-size: 1rem;
  line-height: 1.5;
}

/* The words the visitor typed, picked out in the page's own ink on a soft red
   wash rather than the browser's yellow. */
.result mark {
  background: rgba(205, 32, 45, 0.12);
  color: inherit;
  border-radius: 3px;
}

.search__browse {
  margin-top: clamp(2.5rem, 1.5rem + 3vw, 4.5rem);
}

/* ---------- Investors ---------- */

/* Three beats on the same shelf-grey band as the manufacturers page: white cards
   with the site's 20px corners, headed like the steps (ink, uppercase, heavy) so
   the two pages read as one family. Stacked below 900px. */
.beats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--col-gap);
  margin: clamp(2rem, 1.25rem + 3vw, 3.5rem) 0 0;
  padding: 0;
  list-style: none;
}

.beat {
  padding: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
  border-radius: 20px;
  background: #fff;
}

.beat__name {
  margin: 0 0 0.75rem;
  color: var(--ink);
  font-size: clamp(1rem, 0.85rem + 0.5vw, 1.3125rem);
  font-weight: var(--fw-800);
  letter-spacing: 0.01em;
  line-height: 1.2;
  text-transform: uppercase;
}

.beat__text {
  margin: 0;
  color: var(--slate);
  font-size: clamp(0.9375rem, 0.9rem + 0.2vw, 1.0625rem);
  line-height: 1.6;
}

/* The closing ambition: the lead's voice, set apart from the beats above it. */
.value__close {
  margin-top: clamp(2rem, 1.25rem + 3vw, 3.5rem);
  color: var(--ink);
  font-weight: var(--fw-650);
}

@media (max-width: 900px) {
  .beats {
    grid-template-columns: minmax(0, 1fr);
  }
}


/* ---------- Leadership ---------- */

.leadership__title {
  margin-bottom: clamp(2.5rem, 1.5rem + 3vw, 4.5rem);
}

.md {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  align-items: center;
  overflow: hidden;
  border-radius: 20px;
  background: var(--shelf);
}

.md__media {
  position: relative;
  align-self: stretch;
  min-height: clamp(460px, 40vw, 560px);
  margin: 0;
}

/* Keep the portrait crisp, blending only its right edge into
   the shared background behind the biography. */
.md .md__photo {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  -webkit-mask-image: linear-gradient(to right, #000 65%, rgba(0, 0, 0, 0.98) 72%, rgba(0, 0, 0, 0.88) 79%, rgba(0, 0, 0, 0.65) 86%, rgba(0, 0, 0, 0.35) 92%, rgba(0, 0, 0, 0.1) 97%, transparent 100%);
  mask-image: linear-gradient(to right, #000 65%, rgba(0, 0, 0, 0.98) 72%, rgba(0, 0, 0, 0.88) 79%, rgba(0, 0, 0, 0.65) 86%, rgba(0, 0, 0, 0.35) 92%, rgba(0, 0, 0, 0.1) 97%, transparent 100%);
}

.md__body {
  padding: clamp(1.75rem, 3.5vw, 3.25rem);
}

.md__quote {
  margin: 1.75rem 0 0;
}

.md__quote p {
  margin: 0;
  color: var(--red);
  font-size: 1rem;
  font-style: italic;
  line-height: 1.6;
}

.person__name {
  font-size: 1.25rem;
}

/* Post-nominals sit lowered and small beside the name, as a subscript.
   line-height 0 keeps the lowered text from pushing the heading's line taller. */
.person__creds {
  font-size: 0.5em;
  font-weight: var(--fw-650);
  letter-spacing: 0.04em;
  line-height: 0;
  vertical-align: sub;
}

/* Scoped to the featured profile: the other team members keep the smaller name. */
.md .person__name {
  font-size: clamp(1.75rem, 1.4rem + 1vw, 2.25rem);
}

.person__role {
  margin: 0.15rem 0 0;
  color: var(--red);
  font-size: 0.9375rem;
  font-weight: var(--fw-620);
}

.md__bio {
  margin-top: 1.25rem;
  color: var(--slate);
}

/* ---------- Message from our MD (homepage) ---------- */

/* The "We are Tigremed" section above already ends on a full section of padding,
   so this one starts straight under the heading rather than doubling the gap. */
.msg {
  padding-top: 0;
}

/* The same scale and colour as "We are Tigremed" (.why__title), so the two
   headings read as siblings down the page. */
.msg__title {
  margin-bottom: clamp(1.75rem, 1.25rem + 2vw, 3rem);
  color: var(--ink);
  font-size: clamp(2rem, 1.25rem + 2.75vw, 3.75rem);
}

.md__message p {
  color: var(--slate);
  line-height: 1.65;
}

.md__sign {
  margin: 1.75rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}

.md__sign strong {
  display: block;
  color: var(--ink);
  font-size: 1.125rem;
  font-weight: var(--fw-700);
}

.md__role {
  display: block;
  margin-top: 0.15rem;
  color: var(--red);
  font-size: 0.9375rem;
  font-weight: var(--fw-620);
}

/* Below 900px the card stacks and is held to 640px, centred; the heading takes
   the same width so the two share a left edge. */
@media (max-width: 900px) {
  .msg__title {
    max-width: 640px;
  }
}

.people {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  margin: clamp(3rem, 2rem + 3vw, 4.5rem) 0 0;
  padding: 0;
  list-style: none;
}

.person {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 20px;
  background: var(--shelf);
}

.person > div {
  flex: 1;
  padding: clamp(1.25rem, 2vw, 1.5rem);
}

.person img {
  flex: none;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  object-position: 50% 15%;
  background: var(--shelf);
}

.md__photo,
.person > img {
  filter: grayscale(1);
}

.md:focus-within .md__photo,
.person:focus-within > img {
  filter: grayscale(0);
}

@media (hover: hover) {
  .md:hover .md__photo,
  .person:hover > img {
    filter: grayscale(0);
  }
}

@media (hover: none) {
  .md__photo,
  .person > img {
    filter: grayscale(0);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .md__photo,
  .person > img {
    transition: filter 0.45s ease;
  }
}

.person__bio {
  margin-top: 0.75rem;
  color: var(--slate);
  font-size: 0.9375rem;
  line-height: 1.55;
}

/* ---------- Giving back ---------- */

/* The CSR page is CHA's as much as Tigremed's, so its content takes CHA's green,
   the teal of the CHA logo (#008080). Setting the variable on <main> recolours
   everything in the page body that uses --red, and leaves the top bar, header
   and footer, which sit outside <main>, in Tigremed red. */
.theme-cha main {
  --red: #008080;
}

.giving {
  padding-block: var(--section);
  background: var(--red);
  color: var(--on-red);
}

.giving--partnership {
  background: var(--paper);
  color: var(--ink);
}

.giving--partnership {
  padding-block: clamp(1.5rem, 1rem + 2vw, 3rem);
}

/* Why cancer belongs in our story: the two sides of one care pathway as a pair of
   cards with a double arrow between them. The red is the logo red written out,
   because this page's own --red is the CHA teal. Stacked on a phone, the arrow
   turns to point up and down. */
.why-cancer {
  padding-block: 0 var(--section);
}

.why-cancer__title {
  font-weight: var(--fw-800);
  line-height: 1;
  text-align: center;
}

.why-cancer__lead {
  max-width: 44em;
  margin: clamp(1rem, 0.75rem + 1vw, 1.5rem) auto 0;
  color: var(--slate);
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  line-height: 1.65;
  text-align: center;
}

.sides {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: clamp(0.75rem, 0.25rem + 1.5vw, 1.5rem);
  margin-top: clamp(2rem, 1.25rem + 2.5vw, 3.25rem);
}

.side {
  min-height: clamp(15rem, 12rem + 8vw, 21rem);
  padding: clamp(1.75rem, 1.25rem + 2vw, 3rem);
  border-radius: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  background: #cd202d;
  color: #fff;
}

.side--patient {
  background: #625489;
}

.side__org {
  margin: 0;
  font-size: clamp(1rem, 0.9rem + 0.4vw, 1.25rem);
  font-weight: var(--fw-700);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.side__name {
  margin: clamp(1rem, 0.5rem + 2vw, 2rem) 0 0;
  color: #fff;
  font-size: clamp(2rem, 1.2rem + 2.6vw, 3.5rem);
  font-weight: var(--fw-800);
  line-height: 1;
  text-transform: uppercase;
}

.side__items {
  margin: clamp(1.25rem, 0.75rem + 2vw, 2.25rem) 0 0;
  font-size: clamp(1.0625rem, 0.95rem + 0.5vw, 1.375rem);
  line-height: 1.5;
}

.sides__link {
  display: grid;
  place-items: center;
  width: clamp(2.5rem, 2rem + 2vw, 4rem);
  color: var(--ink);
}

/* The patient side nested in the corner of the commercial side. The outer card clips
   the inner one, so its bottom-right corner follows the outer card's curve. */
.nest {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 46%);
  margin-top: clamp(2.5rem, 1.5rem + 3.5vw, 4.5rem);
  border-radius: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  background: #cd202d;
  color: #fff;
  overflow: hidden;
}

.nest__outer {
  grid-column: 1;
  grid-row: 1;
  padding: clamp(1.75rem, 1.25rem + 2vw, 3rem);
  padding-bottom: clamp(7rem, 5rem + 8vw, 11rem);
}

.nest__list {
  margin: clamp(1.25rem, 0.75rem + 2vw, 2.25rem) 0 0;
  padding: 0;
  list-style: none;
  font-size: clamp(1.125rem, 1rem + 0.6vw, 1.5rem);
  font-weight: var(--fw-700);
}

.nest__list li + li {
  margin-top: 1rem;
}

.nest__inner {
  grid-column: 2;
  grid-row: 1;
  align-self: end;
  padding: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
  border-radius: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  background: #625489;
}

.nest__inner .side__name {
  font-size: clamp(1.5rem, 1rem + 1.8vw, 2.75rem);
}

.nest__item {
  margin: clamp(1rem, 0.5rem + 1.5vw, 1.5rem) 0 0;
  font-size: clamp(1rem, 0.9rem + 0.4vw, 1.25rem);
  font-weight: var(--fw-700);
}

.sides__link svg {
  width: 100%;
  height: auto;
}

@media (max-width: 760px) {
  .sides {
    grid-template-columns: minmax(0, 1fr);
    justify-items: stretch;
  }

  .side {
    min-height: 0;
  }

  .sides__link {
    justify-self: center;
    width: 2.75rem;
    transform: rotate(90deg);
  }

  .nest {
    grid-template-columns: minmax(0, 1fr);
  }

  .nest__outer {
    padding-bottom: 1.5rem;
  }

  .nest__inner {
    grid-column: 1;
    grid-row: 2;
    margin: 0 1rem 1rem;
  }
}

/* ---------- Impact page ---------- */

/* The page is CHA's as much as Tigremed's, so main takes CHA's teal (see
   .theme-cha above), which means --red is teal in here. The one band that has to
   be Tigremed's own red names it directly. */
.impact-hero {
  --brand: #cd202d;
  display: grid;
  grid-template-columns: minmax(0, 11fr) minmax(0, 9fr);
  min-height: clamp(34rem, 80vh, 52rem);
  background: var(--brand);
  color: #fff;
}

/* The copy's left edge is the page's own: the same line the wrap, the header and
   the footer share, whatever the width, so the heading does not float free of the
   rest of the site. */
.impact-hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding-block: clamp(3rem, 2rem + 5vw, 6.5rem);
  padding-left: calc((100vw - min(100vw - 2 * var(--gutter), var(--container))) / 2);
  padding-right: clamp(1.5rem, 4vw, 4rem);
}

.impact-hero__logo {
  width: clamp(6rem, 4.5rem + 4.5vw, 9rem);
  height: auto;
  margin-bottom: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  padding: 0.3rem;
  border-radius: 50%;
  background: #fff;
}

/* The same scale as "We are Tigremed" on the homepage (`.why__title`): the two are
   the site's statement headings and should carry the same weight of voice. The
   measure widens with the size, since 9ch was set for display type that is no
   longer here. */
.impact-hero__title {
  max-width: 14ch;
  color: #fff;
  font-size: clamp(2rem, 1.25rem + 2.75vw, 3.75rem);
  font-weight: var(--fw-800);
  letter-spacing: -0.02em;
  line-height: 0.94;
}

.impact-hero__lead {
  max-width: 34rem;
  margin: clamp(1.5rem, 1rem + 2vw, 2.5rem) 0 0;
  color: var(--on-red-muted);
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.375rem);
  line-height: 1.55;
}

/* The portrait fills its half edge to edge. It was shot against a pale backdrop,
   which is what makes it read as a panel set against the red rather than a photo
   dropped on it. Anchored near the top so the face is never the part cropped. */
.impact-hero__media {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: #dfe4ee;
}

.impact-hero__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 15%;
}

/* The story: the photograph and the heading side by side, the heading set large
   enough to read as the page's second statement rather than a subhead. */
.impact-story {
  padding-block: var(--section);
}

.impact-story__grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: center;
  gap: clamp(2rem, 1rem + 5vw, 6rem);
}

.impact-story__media {
  margin: 0;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  border-radius: 20px;
}

.impact-story__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
}

.impact-story__title {
  color: var(--ink);
  font-size: clamp(2.5rem, 1.5rem + 4.4vw, 5.5rem);
  font-weight: var(--fw-800);
  letter-spacing: -0.02em;
  line-height: 0.95;
}

.impact-story__org {
  margin: clamp(1.25rem, 1rem + 1vw, 2rem) 0 0;
  color: var(--red);
  font-size: 0.9375rem;
  font-weight: var(--fw-800);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.impact-story__text {
  max-width: 34rem;
  margin: 0.6rem 0 0;
  color: var(--slate);
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.375rem);
  line-height: 1.6;
}

/* The comparison on ink. The cards keep their own colours; only the ground, the
   heading and the lead change, and the heading is set left so it lines up with
   the cards' edge instead of floating over them. */
.impact-why {
  padding-block: var(--section);
  background: var(--ink);
}

/* Heading left, lead right and level with its last line, so the top of the band
   is a composition rather than a heading with an empty half beside it. The cards
   below take the full width. Stacked on a phone. */
.impact-why .wrap {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  align-items: end;
  column-gap: clamp(2rem, 1rem + 5vw, 6rem);
}

.impact-why .sides,
.impact-why .nest {
  grid-column: 1 / -1;
}

.impact-why .why-cancer__title {
  max-width: 14ch;
  color: #fff;
  font-size: clamp(2.5rem, 1.5rem + 4.4vw, 5.5rem);
  letter-spacing: -0.02em;
  line-height: 0.95;
  text-align: left;
}

.impact-why .why-cancer__lead {
  max-width: 38rem;
  margin: 0 0 0.4rem;
  color: rgba(255, 255, 255, 0.78);
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.375rem);
  text-align: left;
}

.impact-why .sides__link {
  color: #fff;
}

/* A band of CHA's teal to close, with the one action in white. */
.impact-cta {
  padding-block: clamp(3.5rem, 2rem + 5vw, 6.5rem);
  background: var(--red);
  text-align: center;
}

/* The label is long ("See our work with CHA Citizens Health Africa"), and a
   button never wraps by default, so on a phone it ran past the right edge of the
   page. Here it may wrap, with padding so two lines still sit comfortably. */
.impact-cta .btn {
  max-width: 100%;
  min-height: 64px;
  padding: 0.9rem clamp(1.5rem, 1rem + 2vw, 2.75rem);
  font-size: clamp(1rem, 0.95rem + 0.4vw, 1.1875rem);
  border-color: #fff;
  background: #fff;
  color: var(--red);
  line-height: 1.25;
  white-space: normal;
  text-align: center;
}

.impact-cta .btn:hover,
.impact-cta .btn:focus-visible {
  background: transparent;
  color: #fff;
}

@media (max-width: 860px) {
  /* The photograph leads on a phone, as a band across the top, and the red block
     with the heading follows it. */
  .impact-hero {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
  }

  .impact-hero__media {
    order: -1;
    height: clamp(17rem, 75vw, 26rem);
  }

  .impact-hero__copy {
    padding: clamp(2rem, 1.5rem + 3vw, 3rem) var(--gutter);
  }

  .impact-story__grid,
  .impact-why .wrap {
    grid-template-columns: minmax(0, 1fr);
  }

  .impact-why .why-cancer__lead {
    margin-top: clamp(1.25rem, 1rem + 1vw, 2rem);
  }

  .impact-story__media {
    aspect-ratio: 4 / 3;
  }
}

.csr-partnership {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  color: var(--ink);
}

.csr-partnership__copy {
  padding: clamp(1.5rem, 1rem + 2vw, 2.75rem);
  text-align: center;
}

.csr-partnership__kicker {
  margin-bottom: 0.8rem;
  color: var(--red);
  font-size: 0.875rem;
  font-weight: var(--fw-800);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.giving .csr-partnership .pagehead__title {
  line-height: 1.1;
}

.csr-partnership__copy > p:last-child {
  max-width: 44em;
  margin: 1rem auto 0;
  color: var(--slate);
}

/* The two logos share the top half, with the handshake between them, above the
   headline. */
.csr-partnership__brands {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: clamp(0.5rem, 1.5vw, 1.5rem);
  padding: clamp(1.5rem, 1rem + 2vw, 2.75rem);
}

.csr-partnership__brand {
  display: flex;
  justify-content: center;
  min-width: 0;
}

.csr-partnership__brand img {
  width: auto;
  max-width: 100%;
  height: clamp(110px, 8rem + 6vw, 220px);
  object-fit: contain;
}

.csr-partnership__join {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: var(--red);
  color: var(--on-red);
}

.csr-partnership__join svg {
  width: 65%;
  height: 65%;
}

.quote {
  margin: 0;
}

.quote__text {
  margin: 0;
}

.quote__text p {
  max-width: 100%;
  margin: 0;
  color: var(--slate);
  font-size: clamp(1.75rem, 1.1rem + 2.4vw, 3.25rem);
  font-weight: var(--fw-800);
  line-height: 1.15;
  text-wrap: balance;
}

/* The longer statement that goes with the quote, set as ordinary body copy
   beneath the name. */
.quote__more {
  max-width: 38em;
  margin: 1.5rem 0 0;
  color: var(--slate);
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.125rem);
  line-height: 1.6;
}

/* Name and role directly under the quote, in the page's accent. */
.quote__by {
  display: grid;
  gap: 0.15rem;
  margin-top: 1.5rem;
  color: var(--slate);
  font-size: 0.9375rem;
  line-height: 1.4;
}

.quote__by strong {
  color: var(--red);
  font-size: 1.125rem;
  font-weight: var(--fw-700);
}

/* Paddy's photo is shown whole rather than cropped to the band: the box is
   exactly as wide as the picture at the band's height, pinned to the right
   edge, and the fade runs across the picture itself so its left edge melts into
   the page instead of ending in a visible line. */
.deliver--paddy .deliver__media {
  width: auto;
  aspect-ratio: 900 / 1260;
  -webkit-mask-image: linear-gradient(to left, #000 30%, rgba(0, 0, 0, 0.75) 55%, rgba(0, 0, 0, 0.35) 78%, transparent 100%);
  mask-image: linear-gradient(to left, #000 30%, rgba(0, 0, 0, 0.75) 55%, rgba(0, 0, 0, 0.35) 78%, transparent 100%);
}

.deliver--paddy .deliver__media img {
  object-fit: contain;
}

.deliver--paddy {
  min-height: clamp(460px, 44vw, 660px);
}

/* The photo is a slim figure at the right edge, so the quote is given most of
   the width up to it instead of the half the other fade bands use, which left a
   wide gap between the two. */
@media (min-width: 901px) {
  .deliver--paddy .deliver__copy {
    width: min(100%, 66%);
  }
}

/* A label for the occasion, in the clear part of the photo by the right edge. */
.deliver__caption {
  position: absolute;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  max-width: 18rem;
  padding: 0.6rem 0.9rem;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 0.875rem;
  font-weight: var(--fw-600);
  line-height: 1.35;
}

/* A video on its own line: the full width of the page column, at the file's
   own 16:9 so nothing is cropped or letterboxed. */
.giving--video {
  background: var(--paper);
  color: var(--ink);
}

.giving__video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 20px;
  background: #000;
}

/* CHA's NGO documents: two photographed sheets side by side on the shelf-grey, the
   page's teal (--red here) carrying the small print. The picture is a link to the
   full-size scan, and "Enlarge" says so on hover and focus. Stacked on a phone. */
.certs {
  background: var(--shelf);
}

.certs__title {
  color: var(--ink);
  font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.5rem);
  line-height: 1.05;
}

.certs__lead {
  max-width: 40em;
  text-wrap: balance;
  margin-top: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
  color: var(--slate);
}

.certs__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--col-gap);
  margin: clamp(2rem, 1.25rem + 2.5vw, 3.5rem) 0 0;
  padding: 0;
  list-style: none;
}

.cert__link {
  position: relative;
  display: block;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  box-shadow: 0 10px 28px -14px rgba(35, 31, 32, 0.35);
}

.cert__img {
  width: 100%;
  height: auto;
}

.cert__zoom {
  position: absolute;
  right: 0.75rem;
  bottom: 0.75rem;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: 0.8125rem;
  font-weight: var(--fw-650);
  opacity: 0;
  transition: opacity 0.2s;
}

.cert__link:hover .cert__zoom,
.cert__link:focus-visible .cert__zoom {
  opacity: 1;
}

/* No hover on a touch screen, so the cue is always shown there. */
@media (hover: none) {
  .cert__zoom {
    opacity: 1;
  }
}

.cert__name {
  margin-top: 1.25rem;
  color: var(--ink);
}

.cert__meta {
  margin: 0.35rem 0 0;
  color: var(--slate);
  font-size: 0.9375rem;
  line-height: 1.45;
}

@media (max-width: 800px) {
  .certs__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* The document viewer: a native dialog opened by site.js over a certificate link.
   The sheet is held to 1100px wide at the least, so on a phone it scrolls sideways
   inside the dialog with its print still legible, instead of shrinking to a
   thumbnail that cannot be read. */
.lightbox {
  width: min(96vw, 1500px);
  max-width: none;
  max-height: none;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: 12px;
  background: var(--paper);
}

.lightbox::backdrop {
  background: rgba(35, 31, 32, 0.82);
}

/* The scroller is inside the dialog so the close button can sit on the dialog
   itself and stay put while the sheet is scrolled underneath it. */
.lightbox__scroll {
  max-height: 94vh;
  max-height: 94dvh;
  overflow: auto;
}

.lightbox__img {
  display: block;
  /* max-width off: the site-wide img rule would cap it at the dialog's width and
     defeat the 1100px floor below. */
  max-width: none;
  width: max(100%, 1100px);
  height: auto;
}

.lightbox__close {
  position: absolute;
  top: 0.75rem;
  right: 1.5rem;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  cursor: pointer;
}

.lightbox__close svg {
  width: 20px;
  height: 20px;
}

.giving__kicker {
  margin-bottom: 1rem;
  color: var(--on-red-muted);
  font-size: 1.0625rem;
  font-weight: var(--fw-650);
}

.giving h2 {
  color: #fff;
  text-wrap: balance;
}

.giving__stat {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin: 2rem 0 2.5rem;
  padding-block: 1.25rem;
  border-block: 1px solid var(--on-red-rule);
}

.giving__stat strong {
  flex: none;
  color: #fff;
  font-size: clamp(3.5rem, 2.5rem + 3vw, 5.5rem);
  font-weight: var(--fw-800);
  line-height: 0.9;
}

.giving__stat span {
  max-width: 22em;
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  line-height: 1.4;
}

.cha {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  align-items: start;
  gap: 1.5rem;
  padding: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
  border-radius: 20px;
  background: var(--paper);
  color: var(--ink);
}

/* In the fade band the card is plain text on the page, not a white tile. */
.distribute .cha {
  display: block;
  padding: 0;
  background: none;
}

/* The photo stays in colour here, unlike the black-and-white one on What we do. */
.distribute--colour .distribute__media img {
  filter: none;
}

/* The services list sits as plain rows: no rules above, between or below. */
.distribute .capsule-list,
.distribute .capsule-list li {
  border: 0;
}

/* The photo is a portrait and the band is wide, so it is cropped to a strip;
   weighted toward the top, where the faces are. */
.distribute--colour .distribute__media img {
  object-position: center 22%;
}

.cha h3 {
  font-size: clamp(1.5rem, 1.2rem + 0.8vw, 1.875rem);
  font-weight: var(--fw-800);
}

.cha__tag {
  margin: 0.2rem 0 1rem;
  color: var(--red);
  font-size: 0.9375rem;
  font-weight: var(--fw-620);
}

.cha p:not(.cha__tag) {
  color: var(--slate);
}

/* ---------- Video ---------- */

.video {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  align-items: start;
  gap: var(--col-gap);
}

.video__frame {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 16px;
  background: var(--ink);
}

.video__frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ---------- Partners ---------- */

.partner-feature {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 5rem);
  margin-bottom: clamp(2.5rem, 2rem + 2vw, 4rem);
}

@media (min-width: 901px) {
  .partner-feature--reverse {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  }

  .partner-feature--reverse .partner-feature__logo {
    grid-column: 2;
    grid-row: 1;
  }

  .partner-feature--reverse .partner-feature__copy {
    grid-column: 1;
    grid-row: 1;
  }
}

.partner-feature__logo {
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 10;
  padding: 12%;
  border-radius: 20px;
  background: var(--shelf);
}

.partner-feature__logo img {
  width: 100%;
  max-width: 340px;
}

.partner-feature__logo--square {
  padding: clamp(1.5rem, 4vw, 3rem);
}

.partner-feature__logo--square img {
  max-width: 220px;
  max-height: 220px;
  object-fit: contain;
}

.partner-feature__label {
  margin-bottom: 0.75rem;
  color: var(--red);
  font-size: 1rem;
  font-weight: var(--fw-650);
}

.partner-feature h3 {
  font-size: clamp(1.875rem, 1.3rem + 1.8vw, 3rem);
  font-weight: var(--fw-800);
  line-height: 1.02;
}

.partner-feature p:not(.partner-feature__label) {
  max-width: 34em;
  margin-top: 1rem;
  color: var(--slate);
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
}

.partner-feature__link {
  display: inline-block;
  margin-top: 1.25rem;
  color: var(--red);
  font-weight: var(--fw-650);
  text-underline-offset: 3px;
}

.manufacturers {
  padding-top: 1rem;
  text-align: center;
}

.manufacturers__logos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: center;
  gap: clamp(2rem, 6vw, 5rem);
  max-width: 640px;
  margin: clamp(2rem, 4vw, 3rem) auto 0;
  padding: 0;
  list-style: none;
}

.manufacturers__logos li {
  display: grid;
  place-items: center;
  min-height: 144px;
}

.manufacturers__logos img {
  width: 240px;
  max-width: 100%;
  height: auto;
  object-fit: contain;
}

/* Square marks need more height to carry the same visual weight as wordmarks. */
.manufacturers__logos .manufacturers__logo--square img {
  width: 128px;
}

/* ---------- Contact ---------- */

/* The contact block closes every page, so it is deliberately the quietest thing
   on the site: no rules between the detail rows, type a step down from the
   surrounding page, and a photo that stretches to whatever height the details
   need rather than setting the height itself and dictating the section's. */
.contact {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  align-items: stretch;
  gap: clamp(1.5rem, 3.5vw, 3.5rem);
}

.contact__photo {
  position: relative;
  overflow: hidden;
  border-radius: 20px;
}

/* Absolutely positioned so the photo contributes no height of its own. Left in
   flow its intrinsic 1152x1366 ratio set the figure's height, the grid row
   followed that, and the shorter text column was stretched to match — the photo
   was dictating the section's height instead of matching it. */
.contact__photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* The site h2 runs to 4.125rem, which is a page-opening size. This one heads a
   block most people scroll past, so it gets its own ceiling. The form and the
   map below the contact page's details share it, so the three read as one
   destination. */
.contact__body h2,
.enquiry h2,
.findus h2 {
  font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.75rem);
}

.contact .lead,
.enquiry .lead,
.findus .lead {
  margin-top: 0.75rem;
  color: var(--slate);
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
}

.contact__list {
  margin: 1.25rem 0 0;
}

.contact__list > div {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  align-items: baseline;
  gap: 0.85rem;
  padding: 0.5rem 0;
}

.contact__list dt {
  color: var(--slate);
  font-size: 0.8125rem;
}

.contact__list dd {
  margin: 0;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  font-weight: var(--fw-620);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.contact__list a {
  text-decoration: none;
  background: linear-gradient(var(--red), var(--red)) 0 100% / 0 2px no-repeat;
  transition: background-size 0.25s ease, color 0.2s;
}

.contact__list a:hover {
  color: var(--red);
  background-size: 100% 2px;
}

/* The form and the map, side by side above 1100px. The form takes the wider
   track because its fields pair up two to a row; the map needs only enough
   width to show the street.

   Each region spans three shared rows (heading, note, body) through subgrid,
   so the two headings line up, and the map's top edge lines up with the form's
   first field however many lines the form's note wraps to. Below 1100px it is
   one column and the two regions simply stack. */
.connect {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  column-gap: clamp(1.5rem, 3.5vw, 3.5rem);
  row-gap: clamp(2.5rem, 2rem + 2vw, 3.5rem);
}

.enquiry,
.findus {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  align-content: start;
  row-gap: 0;
}

/* Grid items' margins never collapse, so the note's bottom margin would add to
   the body's top one rather than merge with it. The body's alone sets the gap. */
.enquiry .lead,
.findus .lead {
  margin-bottom: 0;
}

.enquiry__form,
.findus__map {
  margin-top: 1.5rem;
}

.enquiry .lead a {
  overflow-wrap: anywhere;
  text-underline-offset: 3px;
}

.enquiry__form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem 1rem;
}

.field {
  display: grid;
  align-content: start;
  gap: 0.4rem;
}

.field--wide,
.enquiry__actions {
  grid-column: 1 / -1;
}

/* Set like the contact list's labels, so a field's name and a detail's name
   are the same voice. */
.field label {
  color: var(--slate);
  font-size: 0.8125rem;
  font-weight: var(--fw-600);
}

.field__hint {
  font-weight: var(--fw-400);
}

/* Matched to the buttons' 52px so a field and the send button stand the same
   height, but squared off to 12px: a pill-shaped text box reads as a button. */
.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 52px;
  padding: 0.75rem 1rem;
  border: 1.5px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
  transition: border-color 0.2s;
}

.field textarea {
  min-height: 9rem;
  resize: vertical;
}

/* The native arrow is drawn differently by every browser and cannot be styled,
   so it is replaced by a chevron in --ink (Lucide chevron-down; license:
   assets/lucide-LICENSE.txt). */
.field select {
  appearance: none;
  padding-right: 2.75rem;
  background: var(--paper) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23231f20' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 1rem center / 1.125rem;
}

.field :is(input, select, textarea):hover {
  border-color: var(--slate);
}

.field :is(input, select, textarea):focus {
  border-color: var(--ink);
}

/* :user-invalid rather than :invalid, so an empty required field is not marked
   as an error before anyone has had the chance to fill it in. */
.field :is(input, select, textarea):user-invalid {
  border-color: var(--red);
}

.enquiry__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
}

.enquiry__status {
  flex: 1 1 16rem;
  margin: 0;
  color: var(--slate);
  font-size: 0.9375rem;
  line-height: 1.45;
}

.enquiry__status:empty {
  display: none;
}

/* A fixed height rather than an aspect ratio, and short of the form beside it:
   the map is there to show which street, not to be explored. The shelf grey
   holds the space while the lazy-loaded frame arrives. */
.findus__map {
  height: clamp(260px, 24vw, 340px);
  overflow: hidden;
  border-radius: 20px;
  background: var(--shelf);
}

.findus__map iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ---------- Footer ---------- */

.footer {
  background: #000;
  color: #ddd;
  font-size: 0.9375rem;
  /* Every item in the footer — the two links, the copyright line and the
     back-to-top link — is set in caps so the block reads as one stamped
     legend rather than three links in three voices. The case is applied here
     rather than typed into the markup so the copy stays sentence case in the
     source and the DOM. Caps set wider than the lowercase they replace, hence
     the small positive tracking that keeps the longest label on one line. */
  text-transform: uppercase;
  letter-spacing: 0.035em;
}

/* Three tracks: the brand, then one per link. The brand gets the widest because
   it carries the wordmark and tagline lockup; the two link tracks are equal and
   left-aligned beside it rather than centred under a bar of their own. */
/* The logo and links sit on a full-width grey band; the copyright bar beneath
   stays black, and the change of colour is the divider between them. */
.footer__upper {
  padding-top: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  background: #444;
}

.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 3fr) repeat(2, minmax(0, 2fr));
  align-items: start;
  justify-items: start;
  gap: 2rem var(--col-gap);
  padding-bottom: clamp(1rem, 0.75rem + 0.75vw, 1.5rem);
}

/* Flattened so the three anchors are placed straight into tracks of the parent
   row instead of stacking one-above-the-other. The nav element itself stays in
   the accessibility tree — display: contents removes its box, not its role —
   which is the same trick the header nav panel uses above 1100px. */
.footer__links {
  display: contents;
}

/* Shrink-wrapped to the logo, which is what the tagline stretches to match. Its
   sizing and justification are shared with the header's; see .brand__tagline. */
.footer__brand {
  --logo-w: 130px;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.footer__brand img {
  width: var(--logo-w);
}

/* Sentence case, unlike the rest of the footer: this is the brand line, part of
   the logo lockup, not one of the footer's labels. */
.footer__tagline {
  margin: 0;
  color: #fff;
  text-transform: none;
  letter-spacing: normal;
}

/* Underlined permanently, not on hover. The footer is the last thing on the
   page and the least likely place for a cursor to already be hovering, and on a
   phone there is no hover state at all — so a link that only announces itself on
   hover never announces itself. Hover thickens the rule instead of adding it. */
.footer a {
  color: #fff;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  overflow-wrap: anywhere;
}

.footer a:hover {
  text-decoration-thickness: 2px;
}

/* Icon outside the underline. The rule belongs on the words: decorating the
   whole inline-flex box runs it under the glyph and across the gap, which reads
   as a mistake rather than as emphasis. */
.footer__link {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.9375rem;
  text-decoration: none;
}

.footer__link span {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.footer__link:hover span {
  text-decoration-thickness: 2px;
}

.footer__icon {
  flex: none;
  width: 17px;
  height: 17px;
  color: #ddd;
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem 2rem;
  padding-block: 0.75rem;
  font-size: 0.875rem;
}

.footer__bottom p {
  margin: 0;
}

/* ---------- Scroll reveals ---------- */

/* One shared entrance, opt-in per element through data-reveal. The whole
   mechanism hangs off .js-reveal, which site.js adds at runtime: with no
   JavaScript the attribute is inert and every block simply renders, so a failed
   script costs the animation and nothing else.

   The curve is a long, soft settle rather than a snappy arrival — 0.22, 1, 0.36,
   1 spends most of its time decelerating, which is what makes a block read as
   easing into place instead of arriving. The rise is deliberately short at 22px:
   a long travel reads as sliding, and sliding is the wrong verb for content
   that is meant to feel like a printed page. */
@media (prefers-reduced-motion: no-preference) {
  .js-reveal [data-reveal],
  .js-reveal [data-reveal-group] > * {
    opacity: 0;
    transform: translateY(22px);
    transition:
      opacity 0.95s cubic-bezier(0.22, 1, 0.36, 1) var(--reveal-delay, 0ms),
      transform 0.95s cubic-bezier(0.22, 1, 0.36, 1) var(--reveal-delay, 0ms);
  }

  .js-reveal [data-reveal].is-in,
  .js-reveal [data-reveal-group] > .is-in {
    opacity: 1;
    transform: none;
  }

  /* Photographs settle from a slight over-scale as they arrive, reusing the
     idea the hero already uses for its own image. Scaling the frame rather than
     the img is deliberate: the frame owns the crop and the border-radius, so
     the picture appears to settle into its shape instead of the shape growing
     around it. Every photo frame on the site already sets overflow: hidden, so
     the overscale never escapes its border-radius. */
  .js-reveal [data-reveal="photo"],
  .js-reveal [data-reveal-group="photo"] > * {
    transform: translateY(22px) scale(0.975);
  }

  .js-reveal [data-reveal="photo"].is-in,
  .js-reveal [data-reveal-group="photo"] > .is-in {
    transform: none;
  }
}

/* ---------- Motion: the "We are Tigremed" graphic and the band photographs ---------- */

/* Everything here sits inside no-preference, moves only transform, scale, translate
   and opacity, plays once, and carries no meaning of its own: with the motion gone
   the graphic is simply complete.

   The graphic is sequenced so it reads as a journey. The manufacturers circle
   settles first; the dotted arrow then draws itself out of it toward the patient;
   the Tigremed circle settles onto the line as the dots pass behind it; and the
   patients circle arrives last, with the arrowhead landing as it does. The delays
   carry the order (the patients circle's own comes from data-reveal-delay in the
   markup).

   These are keyframe animations, not transitions, on purpose. The hidden starting
   state is applied by .js-reveal, which site.js adds after the page can already
   have painted; a transition would play into that state on load, shrinking things
   that were never visible. A keyframe animation only starts when the section is
   revealed, so the starting state is plain and static. The circles use the
   individual `scale` property so it composes with the shared reveal's transform. */
@media (prefers-reduced-motion: no-preference) {
  .js-reveal .flow__step,
  .js-reveal .flow__hub {
    scale: 0.86;
  }

  .js-reveal .flow__arrow::before {
    transform: scaleX(0);
  }

  .js-reveal .flow__arrow::after {
    opacity: 0;
  }

  .js-reveal .flow__from.is-in .flow__step {
    animation: flow-settle 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;
  }

  .js-reveal .flow__link.is-in .flow__arrow::before {
    animation: flow-draw 1.1s cubic-bezier(0.45, 0, 0.2, 1) 0.35s both;
  }

  .js-reveal .flow__link.is-in .flow__hub {
    animation: flow-settle 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.75s both;
  }

  .js-reveal .flow__link.is-in .flow__arrow::after {
    animation: flow-fade 0.35s ease 1.35s both;
  }

  .js-reveal .flow__step--end.is-in {
    animation: flow-settle 0.95s cubic-bezier(0.22, 1, 0.36, 1) var(--reveal-delay, 0ms) both;
  }

  @keyframes flow-settle {
    from { scale: 0.86; }
    to { scale: 1; }
  }

  @keyframes flow-draw {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
  }

  @keyframes flow-draw-down {
    from { transform: scaleY(0); }
    to { transform: scaleY(1); }
  }

  @keyframes flow-fade {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  /* Stacked, the arrow runs down, so it draws down. */
  @media (max-width: 860px) {
    .js-reveal .flow__arrow::before {
      transform: scaleY(0);
    }

    .js-reveal .flow__link.is-in .flow__arrow::before {
      animation-name: flow-draw-down;
    }
  }

  /* The band photographs sit a touch over scale so site.js can drift them
     without exposing an edge; the class is only present while that script runs.
     The frame clips the overhang itself: on a phone the frames have no mask
     and would otherwise let it spill over what is above and below. */
  .js-drift :is(.audience__media, .distribute__media, .deliver__media) {
    overflow: hidden;
  }

  .js-drift :is(.audience__media, .distribute__media, .deliver__media) img {
    scale: 1.1;
    will-change: translate;
  }
}

/* ---------- Responsive ---------- */

@media (max-width: 1350px) {
  .topbar__address {
    display: none;
  }
}

/* Below 1100px the header is one row: logo, search field, toggle. The nav and both
   buttons move into a panel that opens beneath it, so no row has to hold seven
   items and nothing overflows on a 360px phone. On a phone the search field takes
   a row of its own under the logo (see the 640px block below), so it is never
   squeezed to nothing between the two. */
@media (max-width: 1100px) {
  .product--wide {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  :root {
    --header-h: 86px;
  }

  /* The narrowest the lockup can go and keep the tagline readable: at 100px the
     tagline sets at 8px. Logo and tagline come to about 62px, which with the
     padding below makes the collapsed row 82px. */
  .brand {
    --logo-w: 100px;
    gap: 2px;
  }

  /* Below this the form's paired fields would be squeezed beside the map, so
     the map drops under the form instead. */
  .connect {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Stacked: the photo comes back into flow above the copy, at its own shape,
     with the fade dropped since there is no copy beside it to blend into. */
  .audience-band {
    display: block;
    min-height: 0;
  }

  .audience__copy {
    width: auto;
  }

  .audience__media {
    position: static;
    width: auto;
    aspect-ratio: 3 / 2;
    margin: 0 var(--gutter) 1.5rem;
    border-radius: 16px;
    overflow: hidden;
    -webkit-mask-image: none;
    mask-image: none;
  }

  /* min-height rather than height, so the header can grow to fit the open panel.
     The padding is what keeps the logo and the toggle off the top edge. */
  .header__inner {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    min-height: var(--header-h);
    padding-block: 10px;
  }

  .header__actions {
    display: none;
  }

  .hsearch {
    order: 2;
    flex: 1 1 0;
    width: auto;
    max-width: none;
  }

  .nav-toggle {
    order: 3;
    display: block;
    margin-left: 0;
  }

  .nav-panel {
    display: none;
    order: 5;
    width: 100%;
    /* Cap the open panel against the viewport. On a short phone the six links and
       two buttons are taller than the screen, and a sticky header that overflows
       can never be scrolled out of the way. */
    max-height: calc(100vh - var(--header-h) - 40px);
    max-height: calc(100dvh - var(--header-h) - 40px);
    overflow-y: auto;
    padding-top: 4px;
    padding-bottom: 12px;
  }

  .nav-panel.is-open {
    display: block;
  }

  .nav-panel .nav {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    width: 100%;
    margin-top: 0;
    padding-block: 0;
    border-top: 0;
  }

  .nav-panel .nav a,
  .nav-panel .nav .nav__trigger,
  .nav-panel .nav .nav__chevron {
    padding-block: 0.9rem;
    border-bottom: 1px solid var(--rule);
    font-size: 1.0625rem;
  }

  /* In the panel the group opens in place: the two links indent under the
     trigger instead of floating over the rows below it. */
  .nav-panel .nav__trigger {
    width: 100%;
    justify-content: space-between;
    background: none;
    text-align: left;
  }

  /* The split group is a row: the link takes the width and the chevron sits at
     the far end with a touch target to match. The categories drop onto a row of
     their own beneath both. */
  .nav-panel .nav__group--split {
    flex-wrap: wrap;
    align-items: stretch;
  }

  .nav-panel .nav__group--split > a {
    flex: 1;
  }

  .nav-panel .nav__chevron {
    width: 3.5rem;
    padding-inline: 0;
    /* At the far end, in line with the other groups' chevrons; the button is
       still 3.5rem wide, so the touch target is unchanged. */
    justify-content: flex-end;
  }

  .nav-panel .nav__group--split > .nav__sub {
    flex-basis: 100%;
  }

  .nav-panel .nav__sub {
    position: static;
    min-width: 0;
    padding: 0 0 0 1rem;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .nav-panel .nav .nav__sub a {
    padding: 0.9rem 0;
    border-radius: 0;
    background: none;
  }

  .nav-panel .nav .nav__sub a[aria-current="page"] {
    color: var(--red);
  }

  .nav-panel__actions {
    display: grid;
    gap: 0.6rem;
    padding-top: 1rem;
  }

  .nav-panel__actions .btn {
    width: 100%;
    min-height: 52px;
    font-size: 1rem;
  }
}

/* Phones: the logo and the toggle share the first row, and the search field runs
   the full width of the header on the one beneath, where it has room for the
   cycling words. The panel, when open, comes last. */
@media (max-width: 640px) {
  :root {
    --header-h: 148px;
  }

  .nav-toggle {
    margin-left: auto;
  }

  .hsearch {
    order: 4;
    flex: 1 0 100%;
  }
}

@media (max-width: 900px) {
  .reach__grid,
  .quote,
  .partner-feature,
  .video,
  .contact,
  .audiences {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Stacked: the courier becomes a band above the copy, fading down into the red. */
  .reach--photo {
    padding-top: 0;
  }

  .reach__photo {
    position: relative;
    inset: auto;
    width: 100%;
    height: clamp(200px, 48vw, 320px);
    margin-bottom: -0.75rem;
    -webkit-mask-image: linear-gradient(to bottom, #000 40%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 40%, transparent 100%);
  }

  .reach--photo .reach__grid {
    padding-left: 0;
    grid-template-columns: minmax(0, 1fr);
  }

  .reach--photo .reach__map img {
    width: 100%;
    max-width: 460px;
    margin: 0 auto;
  }

  /* Stacked: the van becomes a band above the copy, fading downward into it. */
  .deliver {
    display: block;
    min-height: 0;
    padding-top: 0;
  }

  .deliver__media {
    position: relative;
    inset: auto;
    width: 100%;
    height: clamp(200px, 48vw, 320px);
    margin-bottom: -0.75rem;
    -webkit-mask-image: linear-gradient(to bottom, #000 40%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 40%, transparent 100%);
  }

  .deliver__copy {
    width: 100%;
  }

  /* The Paddy variant's sizing and fade-to-the-left mask are more specific than
     the stacked band's, so they are reset here. The band is full width and shows
     the whole picture, centred. The fade moves from the band to the picture
     itself, which is narrower than the screen, so it melts out at the bottom and
     at both sides rather than ending in a visible pale edge. */
  .deliver--paddy .deliver__media {
    width: 100%;
    aspect-ratio: auto;
    height: clamp(260px, 70vw, 420px);
    -webkit-mask-image: none;
    mask-image: none;
  }

  .deliver--paddy .deliver__media img {
    position: relative;
    inset: auto;
    display: block;
    width: auto;
    max-width: 100%;
    height: 100%;
    margin-inline: auto;
    -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%), linear-gradient(to right, transparent, #000 22%, #000 78%, transparent);
    -webkit-mask-composite: source-in;
    mask-image: linear-gradient(to bottom, #000 55%, transparent 100%), linear-gradient(to right, transparent, #000 22%, #000 78%, transparent);
    mask-composite: intersect;
  }

  /* The band fades downward, so the label moves to the top, where it is clear,
     and to the left, narrow enough to stay off his face. */
  .deliver__caption {
    top: 0.75rem;
    right: auto;
    left: 0.75rem;
    bottom: auto;
    max-width: 9.5rem;
    padding: 0.45rem 0.6rem;
    font-size: 0.6875rem;
  }

  /* Three markers across leaves each description about twenty characters per
     line once the icon and its gap are taken out, so they stack with the rest
     of the page rather than turn into a wall of short measures. */
  .hero-stats__row {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  }

  .md {
    grid-template-columns: minmax(0, 1fr);
    max-width: 640px;
  }

  .md__media {
    height: clamp(320px, 90vw, 460px);
    min-height: 0;
  }

  .md .md__photo {
    -webkit-mask-image: linear-gradient(to bottom, #000 80%, rgba(0, 0, 0, 0.9) 86%, rgba(0, 0, 0, 0.6) 92%, rgba(0, 0, 0, 0.2) 97%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 80%, rgba(0, 0, 0, 0.9) 86%, rgba(0, 0, 0, 0.6) 92%, rgba(0, 0, 0, 0.2) 97%, transparent 100%);
  }

  .md .person__name {
    text-wrap: wrap;
  }

  .md .person__creds {
    display: block;
    margin-top: 0.5rem;
    line-height: 1.2;
    vertical-align: baseline;
  }

  /* Once the columns stack, nothing sets the photo's height any more, since the
     image is taken out of flow. Give it a floor so it does not collapse flat. */
  .contact__photo {
    min-height: clamp(260px, 46vw, 420px);
  }

  .people {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 640px;
    margin-inline: auto;
  }

  .split,
  .about {
    grid-template-columns: minmax(0, 1fr);
  }

  .split > :first-child,
  .split > :last-child,
  .about__photo,
  .about__text {
    grid-column: 1 / -1;
  }

  /* Stacked, the photo is its own row with no text to stretch to, so it needs a
     ratio of its own to keep any height at all. */
  .about__photo {
    aspect-ratio: 3 / 2;
  }

  .soon__trio,
  .soon__more {
    grid-template-columns: minmax(0, 1fr);
  }

  .values__list {
    --values-gap: 1.5rem;
    grid-template-columns: minmax(0, 1fr);
    max-width: 32rem;
    margin-inline: auto;
  }

  .segments {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .reach__map img {
    margin-inline: auto;
  }

  .footer__top {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer__brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 640px) {
  body {
    font-size: 1rem;
  }

  /* Four across is too tight on a phone; two by two keeps each figure large. */
  .stats__row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 2rem;
  }

  .reach-banner {
    height: clamp(180px, 52vw, 220px);
  }

  .reach-banner img {
    height: 100%;
    object-fit: cover;
    object-position: left center;
  }

  .topbar__optional {
    display: none;
  }

  .topbar__list {
    gap: 0.75rem 1.25rem;
  }

  .topbar__inner {
    padding-block: 10px;
  }

  .products {
    grid-template-columns: minmax(0, 1fr);
  }

  .product__stage {
    height: 280px;
    aspect-ratio: auto;
  }

  .product {
    grid-template-columns: minmax(0, 1fr);
  }

  .product--wide {
    display: flex;
  }

  .people {
    grid-template-columns: minmax(0, 1fr);
  }

  .csr-partnership__brands {
    gap: 0.25rem;
    padding-inline: 0.75rem;
  }

  .csr-partnership__brand img {
    height: 110px;
  }

  .csr-partnership__join {
    width: 2rem;
    height: 2rem;
  }

  .cha {
    grid-template-columns: minmax(0, 1fr);
  }

  .cha img {
    width: 96px;
  }

  .product__body {
    padding-inline: 0.75rem;
  }

  .footer__top {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.5rem;
  }

  .manufacturers__logos {
    gap: 1.5rem;
  }

  .manufacturers__logos li {
    min-height: 120px;
  }

  .manufacturers__logos .manufacturers__logo--square img {
    width: 104px;
  }

  .capsule-list--grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .contact__list > div {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.15rem;
  }

  .enquiry__form {
    grid-template-columns: minmax(0, 1fr);
  }

  .hero__actions .btn {
    flex: 1 1 auto;
  }
}

/* ---------- Product categories ---------- */

.backlink {
  color: inherit;
  text-decoration: none;
}

.backlink:hover,
.backlink:focus-visible {
  text-decoration: underline;
}

.group__title {
  margin: 0 0 1.25rem;
}

/* A product whose photography has not been supplied yet, or whose copy is still
   unconfirmed. Dashed rather than solid so it never reads as final. */
.product__pending {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  margin: 0;
  padding: 1rem;
  color: var(--slate);
  font-size: 0.9rem;
  text-align: center;
}

.product__desc--todo {
  color: var(--slate);
  font-style: italic;
}

/* A single unconfirmed value inside an otherwise complete fact list. */
.product__gap {
  color: var(--slate);
  font-style: italic;
}

.badge--todo {
  background: #fff4e5;
  color: #8a5a00;
}

.product--todo {
  border-style: dashed;
}

/* ---------- Cookie notice ---------- */

/* The footer's "Cookie settings" control, dressed as the link beside it. */
.footer__bottom-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
}

.footer__cookie {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.footer__cookie[hidden] {
  display: none;
}

/* A slim bar across the foot of the screen. A corner card would sit over the
   hero's buttons or its slideshow arrows, which fill both bottom corners; the
   bar covers them too, but only until the visitor has answered. */
.cookie {
  position: fixed;
  inset: auto 0 0;
  z-index: 50;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1rem 2rem;
  padding: 1rem var(--gutter);
  border-top: 1px solid var(--rule);
  background: var(--paper);
  box-shadow: 0 -8px 28px rgba(35, 31, 32, 0.12);
}

.cookie__text {
  margin: 0;
  max-width: 46rem;
  color: var(--ink);
  font-size: 0.9375rem;
  line-height: 1.5;
}

.cookie__actions {
  display: flex;
  gap: 0.75rem;
}

@media (max-width: 600px) {
  .cookie__actions {
    width: 100%;
  }

  .cookie__actions .btn {
    flex: 1 1 0;
  }
}

/* ---------- Research papers page ---------- */

/* A reading list, so the rows are ruled rather than carded: the year is the mark
   that does the finding, set in the display face the way the values cards set
   their step number. The rules sit on the rows themselves, which means an empty
   list shows the invitation panel with no stray hairline above it. */
/* The pagehead already pays the space between the nav and the title, and the list
   is one row until papers arrive. Full section padding on top of that left a band
   of white taller than the content it separated. */
.papers {
  padding-block-start: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
  padding-block-end: clamp(3rem, 2rem + 3vw, 5rem);
}

.papers__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.paper {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  gap: clamp(1rem, 2vw, 2.5rem);
  padding-block: clamp(1.75rem, 1.25rem + 1.75vw, 2.75rem);
  border-block-start: 1px solid var(--rule);
}

.paper:last-child {
  border-block-end: 1px solid var(--rule);
}

.paper__year {
  margin: 0;
  color: var(--red);
  font-size: clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem);
  font-weight: var(--fw-800);
  font-stretch: 66%;
  line-height: 0.9;
}

.paper__source {
  max-width: 11rem;
  margin: 0.6rem 0 0;
  color: var(--slate);
  font-size: 0.875rem;
  line-height: 1.4;
}

.paper__body {
  min-width: 0;
}

.paper__kind {
  margin: 0 0 0.6rem;
  color: var(--red);
  font-size: 0.8125rem;
  font-weight: var(--fw-650);
}

.paper__title {
  max-width: 32ch;
  margin: 0 0 0.6rem;
  font-size: clamp(1.25rem, 1.05rem + 0.9vw, 1.75rem);
  font-weight: var(--fw-800);
  font-stretch: 72%;
  line-height: 1.04;
  letter-spacing: -0.01em;
}

/* A citation line, so it keeps the body face rather than the display one. */
.paper__authors {
  margin: 0 0 0.9rem;
  color: var(--slate);
  font-size: 0.9375rem;
}

.paper__summary {
  max-width: 58ch;
  margin: 0 0 1.1rem;
  color: var(--slate);
}

.paper__action {
  margin: 0;
}

/* Always visible: a phone never sees a hover state, so the way through to the
   paper cannot live in one. */
.paper__link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--red);
  font-size: 0.9375rem;
  font-weight: var(--fw-650);
}

.paper__link::after {
  content: "\2192";
}

@media (prefers-reduced-motion: no-preference) {
  .paper__link::after {
    transition: transform 0.3s ease;
  }

  .paper__link:hover::after {
    transform: translateX(4px);
  }
}

/* Nothing published yet: a panel that reads as an answer rather than a blank
   section, with the way through to the team sitting beside the sentence instead of
   underneath it. */
.papers__empty {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 3rem);
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem) clamp(1.25rem, 1rem + 2vw, 2.5rem);
  border-radius: 20px;
  background: var(--shelf);
}

.papers__empty-title {
  margin: 0 0 0.4rem;
  color: var(--ink);
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  font-weight: var(--fw-800);
  font-stretch: 72%;
  line-height: 1.1;
}

.papers__empty-text {
  max-width: 52ch;
  margin: 0;
  color: var(--slate);
}

.papers__empty-action {
  margin: 0;
}

@media (max-width: 700px) {
  /* Stacked, because a button pinned to the right of a wrapped paragraph reads as
     a mistake rather than as an answer. */
  .papers__empty {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem;
  }

  .papers__empty-action .btn {
    width: 100%;
  }
}

@media (max-width: 900px) {
  /* One column: the year sits beside the journal on a line of its own instead of
     holding open a column it no longer needs. */
  .paper {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.9rem;
  }

  .paper__mark {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
  }

  .paper__source {
    max-width: none;
    margin: 0;
  }
}

/* ---------- WhatsApp button ---------- */

/* The one contact route that follows the visitor past the footer, pinned to the
   bottom-right corner of every page. The green is the only colour on the site
   that does not come from :root, and it is here on purpose: it is WhatsApp's
   own, and the button is only read as WhatsApp while it wears it. The darker
   shade is the same green's hover state, not a second accent.
   
   z-index 40 keeps it under the cookie bar (50). That bar spans the foot of the
   screen for the one visit that has not answered it yet, and a floating button
   landing on top of the bar's own Accept/Decline pair would be worse than a
   button that waits its turn. */
.whatsapp {
  --whatsapp: #25d366;
  --whatsapp-dark: #1da851;
  position: fixed;
  right: 1.25rem;
  /* Notch-safe: a phone with a home indicator eats its usual inset, so the
     button adds the inset rather than ignoring it. */
  bottom: calc(1.25rem + env(safe-area-inset-bottom));
  z-index: 40;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 999px;
  background: var(--whatsapp);
  color: #fff;
  box-shadow: 0 6px 20px rgba(35, 31, 32, 0.24);
  transition: background-color 0.2s, box-shadow 0.2s;
}

.whatsapp:hover {
  background: var(--whatsapp-dark);
  box-shadow: 0 8px 24px rgba(35, 31, 32, 0.3);
}

.whatsapp__icon {
  width: 28px;
  height: 28px;
}

/* The shared focus ring sets a 4px radius on whatever it lands on, which would
   square off the circle for as long as it held focus. The ring itself is left
   alone: red on white is the ring every other control on the site draws. */
.whatsapp:focus-visible {
  border-radius: 999px;
  outline-offset: 4px;
}

/* Two clusters already end at the bottom-right corner, and both have to move
   over rather than disappear under the button: the homepage hero's slideshow
   arrows and the footer's cookie/back-to-top pair. The offset is the button's
   own footprint (56px wide, 20px in from the edge) plus a little air, so the
   corner reads as two neighbours instead of as one control sitting on another. */
.hero__nav {
  margin-right: 4rem;
}

.footer__bottom-links {
  margin-right: 4rem;
}
