/* PUURE: brand tokens and the page's own rules, shared by every page.
   Loaded after the kit's stylesheets. Where a rule departs from the taste kit, the comment says so; each is PUURE's decision (BRIEF.md). */

/* start.mjs brand --page software --bg #07110D --ink #EEF4EA --accent #89D957 --surface #0E1A15 --muted #95A69C --type manrope --radius sharp */
:root {
  --p-bg: #07110d; --p-surface: #0e1a15; --p-ink: #eef4ea; --p-muted: #95a69c;
  --p-accent: #89d957; --p-accent-ink: #07110d; --p-action: #89d957; --p-action-ink: #07110d;
  --p-inv-bg: #eef4ea; --p-inv-surface: #dbe2d8; --p-inv-ink: #07110d; --p-inv-muted: #535d56;
  --p-inv-accent: #07110d; --p-inv-accent-ink: #eef4ea; --p-inv-action: #07110d; --p-inv-action-ink: #eef4ea;
  --font-text: "Manrope", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  /* brand: Archivo ExtraBold headlines and the one gradient signal */
  --font-display: "Archivo", "Arial Black", system-ui, sans-serif;
  --display-weight: 800;
  --display-tracking: -0.015em;
  --display-tracking-xl: -0.02em;
  --signal: linear-gradient(90deg, #89D957 0%, #C9E265 100%);
  --ly-scale: 0.86;   /* Archivo ExtraBold sets wider than the dealt grotesk */
  --sec: clamp(64px, 7vw, 104px);   /* a section's top and bottom padding */
}
@media (max-width: 639px) { :root { --ly-scale: 0.8; } }
.btn--primary { background-image: var(--signal); }
/* a heading never breaks inside a word: the kit's automatic hyphenation split "infra-structure" in the headline at some desktop widths */
h1, h2, h3, h4 { hyphens: manual; -webkit-hyphens: manual; }
/* the open menu covers the page and "Get in touch" is its only action, so there it takes the primary look */
.nav.is-open .nav__actions .btn--secondary { background: var(--action) var(--signal); color: var(--action-ink); border-color: transparent; }
/* ------------------------------------------------------------------ brand guidelines (the puure-brand skill), checked 15 November 2026
   Sizes: page headline up to 64px, section headings up to 40px, card headings 20px, body leading 1.6. One line colour.
   Buttons in Manrope SemiBold. Labels in muted mono capitals at 0.08em. Written as overrides of the kit's tokens. */
html:root { --line: #1f2e26; --line-strong: #1f2e26; --t-h1: clamp(40px, 6vw, 64px); --t-h2: clamp(28px, 4vw, 40px); --t-h3: 20px; }
body { line-height: 1.6; }
h3, .t-h3 { line-height: 1.2; }
.btn { font-weight: 600; font-size: 15px; }
.btn--xl { font: 600 18px/1 var(--font-text); letter-spacing: 0; }
.closing__links .footer__lede { font: 500 var(--t-lead)/1.4 var(--font-text); letter-spacing: 0; }
html .nav:not(.is-open) .nav__actions .btn--secondary:not(:hover) { background: transparent; border-color: var(--line); }
/* the home headline: as large as its column allows while "infrastructure behind" stays on one line, so it is three
   lines at every width (the brand asks for two or three), and 64px once the column is wide enough */
.hero--split .hero__text { container-type: inline-size; }
@media (max-width: 1023px) { .hero--split .hero__text { align-self: stretch; } }   /* a size container has no width of its own, so it must be stretched in the stacked layout */
.hero--split .hero__text > h1 { font-size: clamp(26px, 9.6cqi, 64px); line-height: 1.05; }
/* the grid is an empty layer: it sits behind the graphic, not behind the words beside it (below it on a phone) */
:is(.hero, .page-top).bg-grid::before { -webkit-mask-image: radial-gradient(58% 90% at 78% 30%, #000 0%, transparent 72%); mask-image: radial-gradient(58% 90% at 78% 30%, #000 0%, transparent 72%); }
@media (max-width: 1023px) { :is(.hero, .page-top).bg-grid::before { -webkit-mask-image: radial-gradient(90% 46% at 50% 76%, #000 0%, transparent 72%); mask-image: radial-gradient(90% 46% at 50% 76%, #000 0%, transparent 72%); } }
.signal { background: var(--signal); -webkit-background-clip: text; background-clip: text; color: transparent; }
/* the nav holds the secondary button (one gradient button a screen), so it stays in the bar on a tablet as the primary would */
@media (min-width: 640px) and (max-width: 1023px) { .nav:not(.is-open) .nav__actions > .btn--secondary { display: inline-flex; } }

/* ------------------------------------------------------------------ the header collapses once the page has scrolled
   PUURE's decision (the kit keeps one fixed, full-width bar). At the top it is the full bar; after 40px of scroll the
   bar's own ground and hairline go and its contents draw in to a compact, centred, rounded bar. The inline script at
   the foot of each page sets .is-compact; an open phone menu always shows the full bar. */
.nav { transition: background-color .3s var(--ease), border-color .3s var(--ease); }
.nav__bar { box-sizing: border-box; border: 1px solid transparent; border-radius: 0;
  transition: width .4s var(--ease), height .3s var(--ease), margin-top .3s var(--ease), padding .3s var(--ease), gap .3s var(--ease), border-radius .3s var(--ease), background-color .3s var(--ease), border-color .3s var(--ease); }
.nav__actions .btn { transition: height .3s var(--ease), padding .3s var(--ease); }
/* the logo: the wordmark in the full bar. On collapse its letters fade and tuck in, the two U's slide left to stand
   alone as the icon, and the link narrows to the icon's width (4.5954 and 1.6055 are the two marks' width to height). */
.nav .nav__logo { overflow: hidden; width: calc(24px * 4.5954); transition: width .4s var(--ease); }
.logo { flex: none; max-width: none; transition: height .4s var(--ease); }
.logo__l, .logo__uu { transition: transform .4s var(--ease), opacity .3s linear .1s; }
.nav.is-compact:not(.is-open) .nav__logo { width: calc(20px * 1.6055); }
.nav.is-compact:not(.is-open) .logo { height: 20px; }
.nav.is-compact:not(.is-open) .logo__uu { transform: translateX(-653px); }
.nav.is-compact:not(.is-open) .logo__l { opacity: 0; transition-delay: 0s; }
.nav.is-compact:not(.is-open) .logo__p { transform: translateX(300px); }
.nav.is-compact:not(.is-open) :is(.logo__r, .logo__e) { transform: translateX(-900px); }
.nav.is-compact:not(.is-open) { background-color: transparent; border-bottom-color: transparent; pointer-events: none; }
.nav.is-compact:not(.is-open) .nav__bar { pointer-events: auto; width: min(100% - 2 * var(--gut), 680px); height: 52px; margin-top: 10px; padding-inline: 20px 8px; gap: var(--s-4);
  border-color: var(--line-strong); border-radius: 26px; background-color: color-mix(in oklab, var(--p-surface) 88%, transparent); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); }
.nav.is-compact:not(.is-open) .nav__actions .btn { height: 36px; padding-inline: var(--s-4); }
.nav.is-compact:not(.is-open) .nav__actions:empty { display: none; }
@media (max-width: 1023px) {
  /* no words in the bar on a tablet or phone: it draws in to the logo, the button and the menu button */
  .nav.is-compact:not(.is-open) .nav__bar { width: fit-content; padding-inline: 16px 6px; gap: var(--s-3); }
  .nav.is-compact:not(.is-open) .nav__toggle { width: 38px; height: 38px; margin-left: var(--s-4); border-color: transparent; }
  .nav.is-compact:not(.is-open) .nav__actions + .nav__toggle { margin-left: 0; }
  /* the drawn-in bar sits at the top right, where the menu button already is (the full bar is in the same place
     with this margin, as it spans the gutters) */
  .nav__bar { margin-inline: auto var(--gut); }
  .nav__toggle { transition: width .3s var(--ease), height .3s var(--ease), border-color .3s var(--ease); }
}
@media (max-width: 639px) {
  /* a phone's bar holds the logo and the menu button only, so its drawn-in width is known and the bar can narrow
     towards the right in one move, carrying the logo across while it turns into the icon (fit-content would jump) */
  .nav.is-compact:not(.is-open) .nav__bar { width: 118px; }
  .nav.is-compact:not(.is-open) .nav__actions { display: none; }
  .nav.is-compact:not(.is-open) .nav__actions + .nav__toggle { margin-left: auto; }
}

/* ------------------------------------------------------------------ the Services dropdown (PUURE's direction)
   One word in the header, "Services", opens two picture cards: RevOps and Outbound. The kit's menu is a full-width
   panel; this one is a small box hung under the word, so it also fits the drawn-in bar. In the phone menu the two
   cards are always shown under "Services", with no button to open them. */
.drop { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.drop__card { display: grid; gap: 6px; align-content: start; padding: 10px 10px 12px; border: 1px solid transparent; border-radius: 12px; color: var(--ink); line-height: 1.4; transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.drop__card > b { margin-top: 4px; font-weight: 600; font-size: 15px; }
.drop__card > span:not(.drop__pic) { font-size: 13px; color: var(--muted); }
.drop__card:hover, .drop__card:focus-visible { background: var(--p-bg); border-color: var(--line-strong); }
.drop__card[aria-current="page"] { border-color: var(--p-muted); }
.drop__pic { display: block; aspect-ratio: 16 / 9; border: 1px solid var(--line); border-radius: 8px; background: var(--p-bg); overflow: hidden; }
.drop__pic svg { display: block; width: 100%; height: 100%; }
.d-box { fill: var(--p-surface); stroke: color-mix(in oklab, var(--p-ink) 24%, transparent); }
.d-hot { stroke: var(--p-accent); }
.d-rule { fill: none; stroke: var(--line); }
.d-bar { fill: color-mix(in oklab, var(--p-ink) 26%, transparent); }
.d-bar--hi { fill: color-mix(in oklab, var(--p-ink) 62%, transparent); }
.d-on { fill: var(--p-accent); }
.d-tk { fill: none; stroke: var(--p-bg); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.d-wire { fill: none; stroke: color-mix(in oklab, var(--p-ink) 36%, transparent); stroke-width: 1.5; stroke-dasharray: 4 5; animation: wf-march .7s linear infinite; }
.d-wire--back { stroke: var(--p-accent); animation-direction: reverse; }
/* the service pages sit under "Services": the word carries the kit's current-page bar */
.nav__link--on::after { content: ""; position: absolute; left: var(--s-3); right: var(--s-3); bottom: -2px; height: 2px; border-radius: 2px; background: currentColor; }
@media (min-width: 1024px) {
  .nav__item--drop { position: relative; }
  .nav__item--drop > .nav__menu { left: calc(-1 * var(--s-4)); right: auto; width: 520px; padding: 8px 0 0; border: 0; background: none; }
  .drop { padding: 8px; border: 1px solid var(--line-strong); border-radius: 18px; background: var(--p-surface); }
}
@media (min-width: 1024px) and (max-width: 1279px) { .nav__link--on::after { left: var(--s-2); right: var(--s-2); } }
@media (max-width: 1023px) {
  .nav.is-open .nav__item--drop > .nav__menu { display: block; padding: 0 0 var(--s-4); }
  .nav.is-open .nav__item--drop > .nav__expand { display: none; }
  .nav.is-open .nav__link--on::after { left: 0; right: auto; width: 24px; bottom: 10px; }
  .nav.is-open .drop__card { border-color: var(--line); }
  .nav.is-open .drop__card[aria-current="page"] { border-color: var(--p-muted); }
}

/* ------------------------------------------------------------------ sections take the height of their content
   PUURE's decision: no screen-tall sections (they left large empty areas on big monitors). */
html main > :is(section, .section):not(.hero, .section--hero, .is-live), html footer.closing { height: auto; min-height: 0; padding-block: var(--sec); }
html main > :is(section, .section):not(.hero, .section--hero, .is-live) > :is(.wrap, .container), html footer.closing > .wrap { height: auto; }
html main > section.hero { height: auto; min-height: 0; padding-top: calc(var(--nav) + var(--s-7)); padding-bottom: var(--s-8); }
html main > section.hero > .wrap { height: auto; }
@media (min-width: 1024px) {
  .hero--split .hero__text { align-self: center; }   /* the words sit level with the middle of the graphic */
  .hero--split .hero__media { min-height: 520px; }
}
@media (max-width: 1023px) { .hero--split .hero__media { min-height: 300px; } }
.section-head { margin-bottom: var(--s-7); }
.section-head > h2 + p { margin-top: var(--s-4); }
.split-top { align-items: start; }
/* a short column sits level with the middle of its taller neighbour, not hanging from the top */
:is(#problem, .page-top) .split-top { align-items: center; }
/* brand: small labels are JetBrains Mono capitals, so a label never reads as a line of body text */
.t-label { font: 500 12px/1.4 var(--font-mono); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
/* the closing button is a button, not a bar across half the page */
.closing__cta .btn--xl { width: auto; justify-self: start; min-width: min(100%, 300px); padding-inline: var(--s-7); }

/* ------------------------------------------------------------------ backgrounds (a trial)
   .bg-grid: a faint grid that drifts slowly behind a section and fades out at its edges. .band: a section on the surface colour. */
.bg-grid { position: relative; isolation: isolate; }
.bg-grid::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  --grid: color-mix(in oklab, var(--line) 60%, transparent);   /* the brand grid: the line colour at 60% */
  background-image: linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: radial-gradient(110% 90% at 72% 28%, #000 0%, transparent 72%); mask-image: radial-gradient(110% 90% at 72% 28%, #000 0%, transparent 72%);
  animation: grid-drift 28s linear infinite;
}
.bg-grid--low::before { -webkit-mask-image: radial-gradient(90% 120% at 20% 100%, #000 0%, transparent 70%); mask-image: radial-gradient(90% 120% at 20% 100%, #000 0%, transparent 70%); }
/* the brand guide's own fading grid (its .puure-grid): strongest at the top centre and faded out below, so it sits
   behind the top of the page and is gone before the lower half of the form (the contact page, PUURE's direction) */
.bg-grid--top::before { bottom: auto; height: min(100%, 760px);
  -webkit-mask-image: radial-gradient(ellipse 80% 90% at 50% 0%, #000 0%, transparent 100%); mask-image: radial-gradient(ellipse 80% 90% at 50% 0%, #000 0%, transparent 100%); }
@keyframes grid-drift { to { background-position: 56px 56px, 56px 56px; } }
.band { background: var(--p-surface); }
.band .frame { background: var(--p-bg); }

/* ------------------------------------------------------------------ client logos: a carousel (PUURE's decision; the kit keeps logos still) */
/* dark and light alternate strictly down every page: the client band and the closing footer are on the lighter
   surface, so the page reads dark, light, dark, light from the hero to the foot */
html main > section.clients { padding-block: var(--s-7); background: var(--p-surface); }
/* the logos are the centre of the band: the line above them sits in the top padding and does not push them down */
/* the one band that runs the full width of the screen (PUURE): on a wide monitor the logos reach both edges */
.clients > .wrap { position: relative; width: 100%; }
.clients__head { position: absolute; inset: auto 0 100% 0; display: flex; justify-content: center; text-align: center; margin-bottom: var(--s-5); }
/* each logo carries its own optical height (--h, in px, set so the eight read as one size); --mq-k scales them all */
.marquee { --mq-gap: 56px; --mq-k: 1.35; display: flex; gap: var(--mq-gap); overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.marquee__track { display: flex; align-items: center; gap: var(--mq-gap); flex: none; margin: 0; padding: 0; list-style: none; animation: marquee 44s linear infinite; }
/* a set is as wide as its logos and gaps, never stretched to the screen, so the gaps stay as set: the markup repeats it four times to fill a wide monitor */
.marquee__track img { display: block; width: auto; height: calc(var(--h) * var(--mq-k) * 1px); }
@media (max-width: 639px) { .marquee { --mq-gap: 40px; --mq-k: 1.12; } }
@keyframes marquee { to { transform: translateX(calc(-100% - var(--mq-gap))); } }
/* no pause controls anywhere (PUURE decision): the kit's loop button is hidden and the band it kept clear is given back */
html .loop-pause { display: none; }
[data-m-loop] { --m-safe: 0px; }
/* nor does a hover pause or restart anything: the carousel and the graphics keep moving (motion.js carries the same edit) */

/* ------------------------------------------------------------------ graphics
   The hero's graphic is a feed of notifications. Every other graphic is a plain motion diagram. Green is the signal only. */
.hero__media { display: grid; place-items: center; padding-inline: var(--s-5); }

/* the hero's graphic is a feed of notifications (PUURE's direction): the alerts a client's team gets once the system
   runs. One arrives at the top every eighth of the cycle and pushes the rest down, where they fade out. The eight notes
   are in the markup twice, so the track can step through one set and start again unseen. Each note has a fixed
   height, which is what lets the track move by whole steps. */
.nt { --nt-h: 84px; --nt-gap: 12px; --nt-step: calc(var(--nt-h) + var(--nt-gap)); width: min(100%, 420px); height: calc(4 * var(--nt-step) + .4 * var(--nt-h)); margin: 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(#000 56%, transparent); mask-image: linear-gradient(#000 56%, transparent); }
.nt__track { display: grid; gap: var(--nt-gap); margin: 0; padding: 0; list-style: none; }
.nt__n { position: relative; box-sizing: border-box; height: var(--nt-h); display: grid; align-content: center; gap: 3px; padding: 0 16px; border: 1px solid var(--line); border-radius: 14px; background: var(--p-bg); line-height: 1.3; }
.nt__app { display: flex; align-items: center; gap: 6px; height: 16px; margin: 0; color: var(--ink); font-size: 12px; font-weight: 500; }
.nt__app img { display: block; flex: none; }
.nt__app > i { font-style: normal; font-weight: 400; color: var(--muted); }
.nt__n > b { font-weight: 600; font-size: var(--t-small); }
.nt__n > span { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; font-size: 13px; color: var(--muted); }
/* the unread dot and the green edge: on the newest note only */
.nt__n::after { content: ""; position: absolute; top: 14px; right: 14px; width: 8px; height: 8px; border-radius: 50%; background: var(--p-accent); opacity: 0; }
[data-m-loop] .nt__track { animation: nt-feed var(--m-cycle) cubic-bezier(.2, .8, .2, 1) infinite; }
/* --p is the note's place in the order of arrival (0 to 7): its own cycle starts as it reaches the top */
[data-m-loop] .nt__n { animation: nt-new var(--m-cycle) linear infinite; animation-delay: calc(var(--m-cycle) * (var(--p) / 8 - 1)); }
[data-m-loop] .nt__n::after { animation: nt-dot var(--m-cycle) linear infinite; animation-delay: calc(var(--m-cycle) * (var(--p) / 8 - 1)); }
@keyframes nt-feed {
  0% { transform: translateY(calc(-8 * var(--nt-step))); }
  2.6%, 12.5% { transform: translateY(calc(-7 * var(--nt-step))); }
  15.1%, 25% { transform: translateY(calc(-6 * var(--nt-step))); }
  27.6%, 37.5% { transform: translateY(calc(-5 * var(--nt-step))); }
  40.1%, 50% { transform: translateY(calc(-4 * var(--nt-step))); }
  52.6%, 62.5% { transform: translateY(calc(-3 * var(--nt-step))); }
  65.1%, 75% { transform: translateY(calc(-2 * var(--nt-step))); }
  77.6%, 87.5% { transform: translateY(calc(-1 * var(--nt-step))); }
  90.1%, 100% { transform: translateY(0); }
}
@keyframes nt-new {
  0% { opacity: 0; scale: .96; border-color: var(--p-accent); }
  2.6%, 11% { opacity: 1; scale: 1; border-color: var(--p-accent); }
  14%, 100% { opacity: 1; scale: 1; border-color: var(--line); }
}
@keyframes nt-dot { 0% { opacity: 0; } 2.6%, 11% { opacity: 1; } 14%, 100% { opacity: 0; } }
@media (max-width: 639px) {
  /* a phone's notes are narrower, so their second line may wrap; three show at once and the panel makes room */
  .nt { --nt-h: 100px; --nt-gap: 10px; height: calc(3 * var(--nt-step) + .3 * var(--nt-h)); }
  .nt__n > span { -webkit-line-clamp: 2; }
  .hero--split .hero__media:has(> .nt) { min-height: 392px; }
}

/* the hero's feed, second look (PUURE's direction): no panel behind it, the notes in the lighter Pine colour (the
   brand's surface), three in view with the third fading away, and everything larger. The newest keeps the green edge
   and dot from the rules above. Scoped to .nt, so the closing section's notes are untouched. */
.hero--split .hero__media:has(> .nt) { overflow: visible; min-height: auto; padding: 0; border-radius: 0; background: none; }
.nt { --nt-h: 124px; --nt-gap: 14px; width: min(100%, 520px); height: calc(3 * var(--nt-step) - var(--nt-gap));
  -webkit-mask-image: linear-gradient(#000 64%, transparent 98%); mask-image: linear-gradient(#000 64%, transparent 98%); }
.nt .nt__n { gap: 5px; padding: 0 22px; border-radius: 18px; background: var(--p-surface); }
.nt .nt__app { height: 20px; gap: 8px; font-size: 14px; font-weight: 600; }
.nt .nt__app img { height: 18px; width: auto; }
.nt .nt__n > b { font-size: 18px; }
.nt .nt__n > span { -webkit-line-clamp: 2; font-size: 15px; }
.nt .nt__n::after { top: 20px; right: 20px; width: 9px; height: 9px; }
@media (max-width: 639px) {
  .nt { --nt-h: 112px; --nt-gap: 10px; height: calc(3 * var(--nt-step) - var(--nt-gap)); }
  .nt .nt__n { padding: 0 18px; }
  .nt .nt__n > b { font-size: 16px; }
  .nt .nt__n > span { font-size: 14px; }
  .hero--split .hero__media:has(> .nt) { min-height: auto; }
}

/* motion: every loop sits in a [data-m-loop] box, so the kit gives it one cycle and stops it while it is off screen */
/* a node that lights when the signal reaches it: --on is the moment, in hundredths of the cycle */
[data-m-loop] .lit { animation: lit var(--m-cycle) linear infinite; }
[data-m-loop] .lit--1 { animation-name: lit-1; } [data-m-loop] .lit--2 { animation-name: lit-2; } [data-m-loop] .lit--3 { animation-name: lit-3; } [data-m-loop] .lit--4 { animation-name: lit-4; } [data-m-loop] .lit--5 { animation-name: lit-5; }
@keyframes lit-1 { 0%, 3% { fill: var(--p-surface); stroke: var(--p-ink); background-color: transparent; border-color: var(--p-ink); } 4%, 100% { fill: var(--p-accent); stroke: var(--p-accent); background-color: var(--p-accent); border-color: var(--p-accent); } }
@keyframes lit-2 { 0%, 22% { fill: var(--p-surface); stroke: var(--p-ink); background-color: transparent; border-color: var(--p-ink); } 23%, 100% { fill: var(--p-accent); stroke: var(--p-accent); background-color: var(--p-accent); border-color: var(--p-accent); } }
@keyframes lit-3 { 0%, 41% { fill: var(--p-surface); stroke: var(--p-ink); background-color: transparent; border-color: var(--p-ink); } 42%, 100% { fill: var(--p-accent); stroke: var(--p-accent); background-color: var(--p-accent); border-color: var(--p-accent); } }
@keyframes lit-4 { 0%, 60% { fill: var(--p-surface); stroke: var(--p-ink); background-color: transparent; border-color: var(--p-ink); } 61%, 100% { fill: var(--p-accent); stroke: var(--p-accent); background-color: var(--p-accent); border-color: var(--p-accent); } }
@keyframes lit-5 { 0%, 79% { fill: var(--p-surface); stroke: var(--p-ink); background-color: transparent; border-color: var(--p-ink); } 80%, 100% { fill: var(--p-accent); stroke: var(--p-accent); background-color: var(--p-accent); border-color: var(--p-accent); } }

/* ------------------------------------------------------------------ workflow canvases (the two services)
   Chips at the left run along dashed wires into a card of steps that tick in order; the outcomes leave at the right.
   Built in HTML so the words stay readable at any width; with less than 540px of room the three columns stack. */
.frame.wf-box { display: block; container-type: inline-size; padding: var(--s-6) var(--s-5); background: var(--p-bg); }
.wf { display: grid; grid-template-columns: auto minmax(20px, 1fr) auto minmax(20px, 1fr) auto; align-items: stretch; }
.wf ul { list-style: none; margin: 0; padding: 0; }
.wf__col { display: grid; grid-auto-rows: 1fr; align-items: center; row-gap: var(--s-3); }
.wf__chip { display: grid; gap: 1px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--p-surface); font-size: var(--t-small); font-weight: 500; line-height: 1.3; white-space: nowrap; }
.wf__chip > b { font-weight: 500; }
.wf__chip > i { font-style: normal; font-size: 12px; font-weight: 400; color: var(--muted); }
.wf__wire { width: 100%; height: 100%; overflow: visible; }
.wf__wire path { fill: none; stroke: color-mix(in oklab, var(--p-ink) 36%, transparent); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-dasharray: 4 5; }
[data-m-loop] .wf__wire path { animation: wf-march .7s linear infinite; }
@keyframes wf-march { to { stroke-dashoffset: -9; } }
.wf__card { align-self: center; border: 1px solid var(--line); border-radius: 14px; background: var(--p-bg); }
.wf__head { display: flex; align-items: center; min-height: 44px; padding: 0 14px; border-bottom: 1px solid var(--line); border-radius: 13px 13px 0 0; background: var(--p-surface); }
.wf__rows > li { display: grid; grid-template-columns: minmax(0, 1fr) 16px; align-items: center; gap: 10px; padding: 9px 14px; font-size: var(--t-small); line-height: 1.3; }
.wf__rows > li + li { border-top: 1px solid var(--line); }
.wf__rows--logos > li { grid-template-columns: 86px auto 16px; }
.wf__rows--logos > li > span { color: var(--muted); white-space: nowrap; }
.wf__rows img { display: block; height: 16px; width: auto; }
/* a step's tick: an empty ring until its turn in the cycle, then the signal green (the lit keyframes above) */
.wf__tick { position: relative; width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid var(--p-accent); background-color: var(--p-accent); box-sizing: border-box; }
.wf__tick::after { content: ""; position: absolute; left: 4px; top: 1.5px; width: 4px; height: 7px; border: solid var(--p-bg); border-width: 0 1.5px 1.5px 0; transform: rotate(45deg); }
/* the outcomes wait dimmed and arrive at the end of the cycle */
[data-m-loop] .wf__col--out > li { animation: wf-arrive var(--m-cycle) linear infinite; }
/* lit from the last tick, through the restart, until the second tick of the next run: the result lingers */
@keyframes wf-arrive { 0%, 14% { opacity: 1; border-color: var(--p-accent); transform: none; } 19%, 83% { opacity: .42; border-color: var(--line); transform: translateY(3px); } 88%, 100% { opacity: 1; border-color: var(--p-accent); transform: none; } }
@container (max-width: 539px) {
  .wf { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .wf__wire { display: none; }
  .wf__col { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
  .wf > .wf__card { position: relative; width: min(100%, 300px); margin-block: 30px; }
  .wf > .wf__card::before, .wf > .wf__card::after { content: ""; position: absolute; left: 50%; height: 20px; border-left: 1.5px dashed color-mix(in oklab, var(--p-ink) 36%, transparent); }
  .wf > .wf__card::before { bottom: calc(100% + 5px); }
  .wf > .wf__card::after { top: calc(100% + 5px); }
}
.wf__chip > b > img { display: inline-block; height: 14px; width: 14px; margin-right: 6px; vertical-align: -2px; }

/* ------------------------------------------------------------------ how it works: four cards on one line
   Each card ticks in turn; a wire under the last two runs from Optimise back to Run. Stacks with the system line. */
.proc-box { container-type: inline-size; }
.proc { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr) clamp(36px, 5cqw, 64px)) minmax(0, 1fr); align-items: stretch; }
.proc .wf__card { align-self: stretch; }
.proc .wf__head { justify-content: space-between; }
.proc__text { padding: 14px 14px 18px; font-size: var(--t-small); line-height: 1.5; }
.proc__loop { position: relative; grid-column: 5 / 8; height: 46px; margin: 4px 0 0; color: var(--muted); font-size: var(--t-small); text-align: center; }
.proc__loop > svg { display: block; width: 100%; height: 100%; overflow: visible; }
.proc__loop path { fill: none; stroke: color-mix(in oklab, var(--p-ink) 36%, transparent); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-dasharray: 4 5; }
[data-m-loop] .proc__loop path { animation: wf-march .7s linear infinite; }
.proc__loop > span { position: absolute; left: 50%; bottom: -6px; transform: translate(-50%, 50%); padding: 0 10px; background: var(--p-surface); white-space: nowrap; }
/* stacked, after the rules above so that it wins */
@container (max-width: 999px) {
  .proc { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .proc > .wf__wire { display: none; }
  .proc > .wf__card { position: relative; width: min(100%, 320px); }
  .proc > .wf__card ~ .wf__card { margin-top: 30px; }
  .proc > .wf__card ~ .wf__card::before { content: ""; position: absolute; left: 50%; bottom: calc(100% + 5px); height: 20px; border-left: 1.5px dashed color-mix(in oklab, var(--p-ink) 36%, transparent); }
  .proc__loop { grid-column: auto; height: auto; margin-top: var(--s-4); }
  .proc__loop > svg { display: none; }
  .proc__loop > span { position: static; transform: none; padding: 0; white-space: normal; }
}

/* ------------------------------------------------------------------ ways to work: one lane per service */
.lanes { display: grid; gap: var(--s-6); }
.lane { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 4fr) 56px minmax(0, 4fr); align-items: stretch; }
.lane + .lane { padding-top: var(--s-6); border-top: 1px solid var(--line); }
.lane__k { display: grid; gap: var(--s-2); align-content: start; padding-right: var(--s-6); }
.lane__k > h3 { font: var(--display-weight) var(--t-h3)/1.2 var(--font-display); letter-spacing: var(--display-tracking); margin: 0; }
.lane .wf__card { align-self: stretch; }
.lane__body { display: grid; gap: var(--s-3); align-content: start; padding: 14px 14px 18px; }
@media (max-width: 899px) {
  .lane { grid-template-columns: minmax(0, 1fr); }
  .lane > .wf__wire { display: none; }
  .lane__k { padding: 0 0 var(--s-4); }
  .lane > .wf__card ~ .wf__card { position: relative; margin-top: 30px; }
  .lane > .wf__card ~ .wf__card::before { content: ""; position: absolute; left: 50%; bottom: calc(100% + 5px); height: 20px; border-left: 1.5px dashed color-mix(in oklab, var(--p-ink) 36%, transparent); }
}

/* ------------------------------------------------------------------ the two services
   On the home page: two cards, each a line on the service, four ticking outcomes and a link to its page.
   On a service's own page: the workflow beside the heading, the four steps with what happens in each, and the eight parts written out. */
.svcs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gutter); }
.svc { align-self: stretch; display: grid; grid-template-rows: 1fr auto auto; }
.svc ul, .proc ul { margin: 0; }
.svc__body { display: grid; gap: var(--s-3); align-content: start; padding: var(--s-5); }
.svc__body > h3 { font: var(--display-weight) var(--t-h3)/1.2 var(--font-display); letter-spacing: var(--display-tracking); margin: 0; }
.svc__body > p { color: var(--muted); }
.svc .wf__rows { border-block: 1px solid var(--line); }
.svc .wf__rows > li { padding-inline: var(--s-5); }
.svc__more { margin: 0; padding: var(--s-4) var(--s-5); }
@media (max-width: 767px) { .svcs { grid-template-columns: minmax(0, 1fr); } }
/* a detailed step: its line, then what happens in it, ruled off like the rows of a workflow card */
.proc--detail .wf__rows { border-top: 1px solid var(--line); color: var(--muted); }
.section-head + .svc-groups { margin-top: 0; }
.svc-list { list-style: none; margin: var(--s-4) 0 0; padding: 0; }
.svc-list > li { display: grid; gap: var(--s-2); padding: var(--s-4) 0; border-bottom: 1px solid var(--line); }
.svc-list > li:first-child { border-top: 1px solid var(--line); }
.svc-list h3 { font: 500 var(--t-lead)/1.4 var(--font-text); letter-spacing: 0; margin: 0; }
.svc-list p { color: var(--muted); max-width: 56ch; }

/* how a service is bought: a ruled line under the intro, each word a link to "Ways to work" */
.runs { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s-2) var(--s-3); padding-top: var(--s-4); border-top: 1px solid var(--line); font-weight: 500; }
.runs__k { margin-right: var(--s-3); font: 500 12px/1.4 var(--font-mono); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.runs > a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 5px; }
.runs > a:hover { text-decoration-color: var(--ink); }
.runs > span:not(.runs__k) { color: var(--muted); font-weight: 400; }

/* ------------------------------------------------------------------ lists inside sections */
/* the eight deliverables of a service: names only, two groups side by side, each line opens on a click */
/* two columns on the page's own twelve-column grid, so the right one starts where the frames above start */
.svc-groups, .qa-cols { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--s-6); align-items: start; }
.svc-groups > *, .qa-cols > * { grid-column: span 6; }
@media (max-width: 639px) { .svc-groups > *, .qa-cols > * { grid-column: 1 / -1; } .qa-cols { row-gap: 0; } .qa-cols > .qa + .qa > details:first-child { border-top: 0; } }
.svc-groups { margin-top: var(--s-7); }
.svc-groups .qa { margin-top: var(--s-4); }
.qa-more { margin-top: var(--s-6); }
.qa.qa--tight summary { padding: var(--s-4) 0; font-size: var(--t-body); }
.qa.qa--tight details > p { padding-bottom: var(--s-4); color: var(--muted); }
/* problem against fix: two columns, one line under each pair */
.pf { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-3); }
.pf__head, .pf > li { display: grid; grid-template-columns: minmax(0, 1fr) 48px minmax(0, 1fr); align-items: stretch; }
.pf__head > p:last-child { grid-column: 3; }
.pf__head { padding-bottom: var(--s-3); }
.pf .wf__chip { align-content: center; padding: 14px 16px; font-size: var(--t-body); line-height: 1.45; white-space: normal; }
.pf__p { background: transparent; font-weight: 400; color: var(--muted); }
.pf .pf__f { grid-template-columns: minmax(0, 1fr) 16px; align-items: center; gap: 12px; border-color: var(--line); background: var(--p-surface); font-weight: 500; color: var(--ink); }
@media (max-width: 639px) { .pf__head { display: none; } .pf { gap: var(--s-5); } .pf > li { grid-template-columns: minmax(0, 1fr); row-gap: 6px; } .pf > li > .wf__wire { display: none; } }
/* the three engagements: a line above each, no boxes */
.eng__for { color: var(--muted); }
.eng__for b { color: var(--ink); font-weight: 500; }
/* the close: the ask at the left, what happens next at the right, level with each other */
.closing__split { align-items: center; row-gap: var(--s-7); }
.closing__ask { display: grid; gap: var(--s-6); justify-items: start; }
/* the home page's close has no graphic: the ask and one line on the call at the left, the button at the right end of the row */
.closing__split--row .closing__ask { gap: var(--s-4); }
.closing__cta .closing__split--row h2 { max-width: none; }
.closing__go { display: grid; justify-items: end; }
.closing__cta .closing__go .btn--xl { justify-self: end; }
@media (max-width: 1023px) { .closing__go { justify-items: start; } .closing__cta .closing__go .btn--xl { justify-self: start; } }
/* the foot of a page starts under a hairline, close to the section above it */
html footer.closing { padding-top: calc(var(--sec) * .7); background: var(--p-surface); }
/* what happens next: three cards down a dashed line, ticking in turn (the close and the contact page) */
.next { list-style: none; margin: 0; padding: 0; display: grid; gap: 30px; }
.next > li { position: relative; }
.next > li + li::before { content: ""; position: absolute; left: 28px; bottom: calc(100% + 5px); height: 20px; border-left: 1.5px dashed color-mix(in oklab, var(--p-ink) 36%, transparent); }
.next .wf__head { justify-content: space-between; }
.next .proc__text { padding-block: 12px 14px; }
.contact-intro > .next { margin-block: var(--s-5); }
/* the close, on the home and service pages: the same three steps as notifications that arrive in order (PUURE's
   pick of three options). They use the hero's note; the third keeps the green edge. */
.nx-box { display: grid; }
.nx { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; width: min(100%, 440px); justify-self: end; }
.nx .nt__n { height: auto; min-height: 84px; padding-block: 14px; }
.nx .nt__app { color: var(--muted); font: 500 12px/1.4 var(--font-mono); text-transform: uppercase; letter-spacing: 0.08em; }
[data-m-loop] .nx > li { animation: nx-1 var(--m-cycle) linear infinite both; }
[data-m-loop] .nx > li:nth-child(2) { animation-name: nx-2; }
[data-m-loop] .nx > li:nth-child(3) { animation-name: nx-3; }
.nx .nt__n::after { content: none; }   /* no unread dot here: the green edge is enough */
@keyframes nx-1 { 0% { opacity: 0; transform: translateY(10px); } 6%, 94% { opacity: 1; transform: none; } 100% { opacity: 0; transform: none; } }
@keyframes nx-2 { 0%, 24% { opacity: 0; transform: translateY(10px); } 30%, 94% { opacity: 1; transform: none; } 100% { opacity: 0; transform: none; } }
@keyframes nx-3 { 0%, 48% { opacity: 0; transform: translateY(10px); border-color: var(--p-accent); } 54%, 94% { opacity: 1; transform: none; border-color: var(--p-accent); } 100% { opacity: 0; transform: none; border-color: var(--p-accent); } }
@media (max-width: 1023px) { .nx { justify-self: start; width: min(100%, 520px); } }

/* tools: the logo, then one line */
.tools { row-gap: var(--s-6); }
.tools > li { display: grid; gap: var(--s-3); align-content: start; }
.tools img { display: block; height: 26px; width: auto; max-width: 100%; }
@media (min-width: 1024px) { .tools { grid-template-columns: repeat(5, minmax(0, 1fr)); } .tools > li { grid-column: auto; } }
@media (max-width: 1023px) { .tools > li { grid-column: span 6; } .tools { row-gap: var(--s-5); } }

/* ------------------------------------------------------------------ questions: expand on a click (PUURE's decision; the kit keeps answers open) */
.qa > details { border-bottom: 1px solid var(--line); }
.qa > details:first-child { border-top: 1px solid var(--line); }
.qa summary { display: flex; justify-content: space-between; align-items: center; gap: var(--s-5); padding: var(--s-5) 0; cursor: pointer; list-style: none; font: 500 var(--t-lead)/1.4 var(--font-text); }
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after { content: "+"; flex: none; width: 24px; text-align: center; font: 400 24px/1 var(--font-text); color: var(--muted); }
.qa details[open] > summary::after { content: "\2212"; color: var(--ink); }
.qa summary:hover::after { color: var(--ink); }
.qa summary:focus-visible { outline: 2px solid var(--action); outline-offset: 2px; }
.qa details > p { padding-bottom: var(--s-5); max-width: 64ch; }

/* ------------------------------------------------------------------ the contact page: a form with room */
.contact-form .field textarea { min-height: 120px; }
.contact-form .field :is(input, select) { height: 52px; }
/* fields that can be seen on the dark field: a surface fill and a border at about 3:1 */
.contact-form .field :is(input, select, textarea):not([aria-invalid="true"]) { background-color: var(--p-surface); border-color: color-mix(in oklab, var(--p-ink) 45%, transparent); }
.contact-form .field label { font-size: var(--t-body); }
/* required fields carry an asterisk, drawn from the input's own required attribute, so the mark and the check cannot drift apart */
.contact-form .field:has(:required) > label::after { content: " *"; }
.contact-form .req { color: var(--ink); }
/* a hint or an error under one field must not push its neighbour's input down */
.contact-form .field { align-content: start; }
.contact-form .btn { height: 52px; padding-inline: var(--s-7); }
.contact-form a { text-decoration: underline; }
/* the intro and its three cards follow the form down the page, but only in a window tall enough to show all of
   them: in a shorter one the third card was cut off for as long as the form scrolled */
@media (min-width: 1024px) and (min-height: 780px), (min-width: 1340px) and (min-height: 690px) { .contact-intro { position: sticky; top: calc(var(--nav) + var(--s-4)); } }
@media (max-width: 1023px) { .contact-intro { margin-bottom: var(--s-6); } }
html main > section.section:is(.contact-page, .page-top) { padding-top: calc(var(--nav) + var(--s-8)); padding-bottom: var(--s-8); }   /* the header is fixed: clear it, then the usual room */
:is(.contact-page, .page-top) h1 { font: var(--display-weight) var(--t-h1)/1.05 var(--font-display); letter-spacing: var(--display-tracking-xl); margin: 0; }
