@charset "UTF-8";
/* ==========================================================================
   Yellow Archer — Hi-Vis Signal
   --------------------------------------------------------------------------
   One stylesheet, cached for a year. Replaces 8–27KB of inline CSS that was
   re-downloaded on every page view across nine files, each with its own drifted
   copy of the token block.

   The idea: the brand mark is a hooded archer at full draw over a serif VA
   monogram, with binary digits and circuit traces through the hood and sleeve.
   Old craft, new instrument. So the page is a stack of full-bleed bands that
   commit to one of three grounds — paper, signal, ink — with hard edges between
   them, and yellow used as a GROUND rather than as timid accent text.

   That last decision is also the accessibility fix. The old site had to end
   every stylesheet with a #8a6a00 "darker gold" override because #f5c518 text
   on white fails contrast. Ink on signal is 10.8:1.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts — self-hosted. Removes two preconnects and a render-blocking
   cross-origin request per page, and stops sending every visitor's IP to a
   third party on a site that markets POPIA compliance.
   -------------------------------------------------------------------------- */
/* Two real static cuts of Archivo at wdth 125.
   Getting this right needed measuring, not reading: the axis-tuple form
   `Archivo:wdth,wght@125,700..800` silently returns a CONDENSED instance. Canvas
   measurement of the same string at 100px settled it —
     condensed (what that request returns): 728px
     normal width:                          854px
     wdth 125 expanded:                    1073px
   Pin one weight per request (`@125,700`, `@125,800`) to get the real thing. */
@font-face {
  font-family: 'Archivo Expanded';
  src: url('/assets/fonts/archivo-expanded-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212;
}
@font-face {
  font-family: 'Archivo Expanded';
  src: url('/assets/fonts/archivo-expanded-800.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212;
}
@font-face {
  font-family: 'Public Sans';
  src: url('/assets/fonts/public-sans.woff2') format('woff2');
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212;
}
@font-face {
  font-family: 'Martian Mono';
  src: url('/assets/fonts/martian-mono.woff2') format('woff2');
  font-weight: 400 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC, U+2122;
}

/* --------------------------------------------------------------------------
   Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Corrected to the logo's actual value. The old CSS had drifted to #f5c518. */
  --signal:      #F7BE0F;
  --signal-deep: #D9A400;
  --ink:         #151109;   /* warm, brown-shifted — not a neutral black */
  --paper:       #F6F3EC;
  --olive:       #3A3121;   /* the logo's own shadow tone */
  --rule:        #DCD7C9;
  --live:        #1F7A4C;   /* functional only: "in production", WhatsApp */

  --band-bg: var(--paper);
  --band-fg: var(--ink);
  --band-muted: var(--olive);
  --band-rule: var(--rule);

  --font-display: 'Archivo Expanded', 'Arial Black', system-ui, sans-serif;
  --font-body:    'Public Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:    'Martian Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;

  --measure-w: 4.5rem;   /* the left measure gutter */
  --page-max: 1240px;
  --gut: clamp(1.25rem, 4vw, 2.5rem);

  --t-fast: 120ms;
  --t-mid:  160ms;
  --ease: cubic-bezier(.2, .7, .3, 1);
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

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

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

a { color: inherit; text-underline-offset: .18em; text-decoration-thickness: .08em; }

/* One visible focus treatment everywhere. The old site had none. */
:focus-visible {
  outline: 3px solid var(--signal);
  outline-offset: 2px;
  border-radius: 1px;
}
.band--signal :focus-visible { outline-color: var(--ink); }

::selection { background: var(--signal); color: var(--ink); }

.ya-skip {
  position: absolute; left: .5rem; top: -4rem; z-index: 200;
  background: var(--ink); color: var(--paper);
  padding: .75rem 1.25rem; font: 500 .8125rem/1 var(--font-mono);
  text-transform: uppercase; letter-spacing: .1em;
  transition: top var(--t-mid) var(--ease);
}
.ya-skip:focus { top: .5rem; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Typography
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: .95;
  letter-spacing: -.025em;
  margin: 0 0 .5em;
  text-wrap: balance;
}

.t-display {
  font-size: clamp(2.75rem, 7.5vw, 6.5rem);
  line-height: .92;
  letter-spacing: -.03em;
}
.t-h2 { font-size: clamp(2rem, 4.5vw, 3.5rem); line-height: 1; }
.t-h3 { font-size: clamp(1.25rem, 2vw, 1.625rem); line-height: 1.15; font-weight: 700; }

.t-lede {
  font-family: var(--font-body);
  font-size: clamp(1.125rem, 1.6vw, 1.375rem);
  line-height: 1.55;
  font-weight: 400;
  max-width: 34ch;
  color: var(--band-muted);
}

/* Eyebrows, stat numerals, labels, status, breadcrumbs. */
.t-label {
  font-family: var(--font-mono);
  font-size: .6875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .1em;
  line-height: 1.4;
}

p { margin: 0 0 1.15em; max-width: 68ch; }
p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   Bands — the page is a stack of full-bleed grounds with hard edges.
   No gradients, no shadows, no rounded corners anywhere.
   -------------------------------------------------------------------------- */
.band {
  background: var(--band-bg);
  color: var(--band-fg);
  padding-block: clamp(3.5rem, 9vw, 7rem);
  position: relative;
}
.band--paper  { --band-bg: var(--paper);  --band-fg: var(--ink);    --band-muted: var(--olive);              --band-rule: var(--rule); }
.band--signal { --band-bg: var(--signal); --band-fg: var(--ink);    --band-muted: #4A3B08;                   --band-rule: rgba(21,17,9,.28); }
.band--ink    { --band-bg: var(--ink);    --band-fg: var(--paper);  --band-muted: #A79C88;                   --band-rule: rgba(246,243,236,.18); }
.band--tight  { padding-block: clamp(2rem, 5vw, 3.25rem); }

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

/* The measure: a ruled gutter running the length of the page, so the whole
   thing reads as one measured run rather than a pile of sections. It is the
   structural echo of the signature element below. */
@media (min-width: 1100px) {
  .band > .wrap { padding-left: var(--measure-w); }
  .band::before {
    content: "";
    position: absolute; inset-block: 0;
    left: max(var(--gut), calc((100vw - var(--page-max)) / 2 + var(--gut)));
    width: 1px;
    background: var(--band-rule);
  }
  .band[data-measure]::after {
    content: attr(data-measure);
    position: absolute;
    top: clamp(3.5rem, 9vw, 7rem);
    left: max(var(--gut), calc((100vw - var(--page-max)) / 2 + var(--gut)));
    transform: rotate(180deg) translateX(-.25rem);
    writing-mode: vertical-rl;
    font: 500 .625rem/1 var(--font-mono);
    text-transform: uppercase;
    letter-spacing: .18em;
    color: var(--band-muted);
    white-space: nowrap;
  }
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: .6em;
  font: 700 .875rem/1 var(--font-body);
  text-transform: uppercase; letter-spacing: .06em; text-decoration: none;
  padding: 1.05em 1.6em;
  border: 2px solid currentColor;
  background: none; color: inherit;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.btn--fill { background: var(--signal); border-color: var(--signal); color: var(--ink); }
.btn--fill:hover, .btn--fill:focus-visible { background: var(--ink); border-color: var(--ink); color: var(--signal); }
.btn--ghost:hover, .btn--ghost:focus-visible { background: var(--band-fg); color: var(--band-bg); }
.band--signal .btn--fill { background: var(--ink); border-color: var(--ink); color: var(--signal); }
.band--signal .btn--fill:hover { background: transparent; color: var(--ink); }

.btn-row { display: flex; flex-wrap: wrap; gap: .875rem; margin-top: 2rem; }

/* --------------------------------------------------------------------------
   Nav — sticky, hairline base. Includes the mobile drawer the old site
   simply did not have: below 768px it did `display:none` on the links with no
   hamburger and no alternative, so phones got a logo and one button.
   -------------------------------------------------------------------------- */
.nav {
  position: sticky; top: 0; z-index: 100;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
.nav__inner {
  width: min(100% - (var(--gut) * 2), var(--page-max));
  margin-inline: auto;
  display: flex; align-items: center; gap: 1.5rem;
  min-height: 4.25rem;
}
.nav__logo { display: flex; align-items: center; gap: .6rem; text-decoration: none; margin-right: auto; }
.nav__logo svg, .nav__logo img { width: 2rem; height: 2rem; color: var(--ink); }
.nav__wordmark {
  font: 800 .9375rem/1 var(--font-display);
  letter-spacing: -.01em; text-transform: uppercase;
}
.nav__wordmark span { color: var(--signal-deep); }

.nav__links { display: flex; align-items: center; gap: 1.75rem; list-style: none; margin: 0; padding: 0; }
.nav__links a {
  font: 500 .875rem/1 var(--font-body);
  text-decoration: none; padding: .5rem 0;
  border-bottom: 2px solid transparent;
  transition: border-color var(--t-fast) var(--ease);
}
.nav__links a:hover { border-bottom-color: var(--signal); }
.nav__links a[aria-current="page"] { border-bottom-color: var(--ink); }

.nav__toggle {
  display: none;
  width: 2.75rem; height: 2.75rem;
  border: 1px solid var(--rule); background: none; cursor: pointer;
  padding: 0; place-items: center;
}
.nav__toggle span, .nav__toggle span::before, .nav__toggle span::after {
  content: ""; display: block; width: 1.125rem; height: 2px; background: var(--ink);
  transition: transform var(--t-mid) var(--ease), opacity var(--t-fast) var(--ease);
}
.nav__toggle span::before { transform: translateY(-6px); }
.nav__toggle span::after  { transform: translateY(4px); }
.nav__toggle[aria-expanded="true"] span { background: transparent; }
.nav__toggle[aria-expanded="true"] span::before { transform: rotate(45deg); }
.nav__toggle[aria-expanded="true"] span::after  { transform: rotate(-45deg) translateY(-1px); }

@media (max-width: 860px) {
  .nav__toggle { display: grid; }
  .nav__links {
    position: fixed; inset: 4.25rem 0 auto 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--ink); color: var(--paper);
    padding: .5rem var(--gut) 1.5rem;
    transform: translateY(-100%);
    visibility: hidden;
    transition: transform var(--t-mid) var(--ease), visibility var(--t-mid);
  }
  .nav__links[data-open="true"] { transform: translateY(0); visibility: visible; }
  .nav__links li { border-bottom: 1px solid rgba(246,243,236,.15); }
  .nav__links a { display: block; padding: 1rem 0; font-size: 1.0625rem; border: 0; }
  .nav__cta { display: none; }
  .nav__links .nav__cta { display: block; }
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.hero { padding-block: clamp(4rem, 11vw, 8.5rem) clamp(3rem, 7vw, 5rem); }
.hero__eyebrow { color: var(--band-muted); margin-bottom: 1.75rem; }
.hero__eyebrow::before {
  content: ""; display: inline-block; vertical-align: middle;
  width: .5rem; height: .5rem; background: var(--signal); margin-right: .7rem;
}
.hero .t-lede { margin-top: 1.5rem; max-width: 46ch; }

.stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px; background: var(--band-rule);
  border-block: 1px solid var(--band-rule);
  margin-top: clamp(3rem, 7vw, 5rem);
}
.stat { background: var(--band-bg); padding: 1.5rem 1.25rem; }
.stat__n {
  font: 800 clamp(1.75rem, 3.5vw, 2.75rem)/1 var(--font-display);
  letter-spacing: -.02em; display: block;
}
.stat__l { color: var(--band-muted); margin-top: .5rem; display: block; }

/* --------------------------------------------------------------------------
   THE MEASURE — the signature element.
   The core claim rendered as information rather than decoration: two bars on a
   genuinely shared scale. A practice owner understands it in one second without
   reading a word of body copy.
   -------------------------------------------------------------------------- */
.measure { margin-top: clamp(2.5rem, 6vw, 4rem); }
.measure__row + .measure__row { margin-top: 2.25rem; }
.measure__head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem; margin-bottom: .625rem;
}
.measure__who { font: 700 1rem/1.2 var(--font-body); }
.measure__val { font-family: var(--font-mono); font-weight: 500; font-size: .8125rem; }

.measure__track {
  position: relative; height: 2.25rem;
  border-left: 2px solid var(--ink);
  /* tick marks every 10% — this is a ruler, so it should read as one */
  background-image: repeating-linear-gradient(90deg,
    rgba(21,17,9,.28) 0 1px, transparent 1px 10%);
}
.measure__bar {
  position: absolute; inset-block: .5rem; left: 0;
  width: var(--pct, 0%);
  background: var(--ink);
  transform-origin: left center;
}
.measure__row--ours .measure__bar { background: var(--ink); }
.measure__row--ours .measure__val { font-weight: 500; }
.measure__note {
  margin-top: 2rem; font: 700 clamp(1rem, 1.8vw, 1.25rem)/1.4 var(--font-body);
  max-width: 40ch;
}

/* One orchestrated moment on the whole site: the rule draws itself once when
   scrolled into view. Everything else is hover/focus only. */
@media (prefers-reduced-motion: no-preference) {
  .measure__bar { transform: scaleX(0); transition: transform 900ms var(--ease); }
  .measure.is-visible .measure__bar { transform: scaleX(1); }
  .measure.is-visible .measure__row--ours .measure__bar { transition-delay: 700ms; }
}

/* --------------------------------------------------------------------------
   Service rows — full-width, invert to signal on hover
   -------------------------------------------------------------------------- */
.rows { border-top: 1px solid var(--band-rule); }
.row {
  display: grid; grid-template-columns: minmax(0, 22ch) minmax(0, 1fr) auto;
  gap: 1.5rem; align-items: baseline;
  padding: clamp(1.5rem, 3vw, 2.25rem) 0;
  border-bottom: 1px solid var(--band-rule);
  text-decoration: none;
  transition: background-color var(--t-fast) var(--ease), padding-inline var(--t-fast) var(--ease);
}
a.row:hover, a.row:focus-visible {
  background: var(--signal); color: var(--ink);
  padding-inline: 1.25rem;
}
.row__title { font-family: var(--font-display); font-weight: 700; font-size: clamp(1.125rem, 2vw, 1.5rem); letter-spacing: -.02em; }
.row__desc { color: var(--band-muted); margin: 0; font-size: .9375rem; }
a.row:hover .row__desc { color: var(--olive); }
.row__tag { color: var(--band-muted); white-space: nowrap; }
a.row:hover .row__tag { color: var(--olive); }
@media (max-width: 720px) {
  .row { grid-template-columns: 1fr; gap: .5rem; }
}

/* --------------------------------------------------------------------------
   Swap rows — "instead of X, you get Y". Its own component rather than a reuse
   of .row: the two halves need comparable weight, and .row's fixed first column
   collides the struck text into the bold text.
   -------------------------------------------------------------------------- */
.swaps { border-top: 1px solid var(--band-rule); }
.swap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.15fr);
  gap: .35rem 1.5rem; align-items: baseline;
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--band-rule);
}
.swap__old {
  color: var(--band-muted);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  font-size: .9375rem;
}
.swap__arrow { color: var(--signal-deep); font-family: var(--font-mono); font-size: .75rem; }
.swap__new { font-weight: 700; font-size: 1.0625rem; }
@media (max-width: 720px) {
  .swap { grid-template-columns: 1fr; }
  .swap__arrow { display: none; }
}

/* --------------------------------------------------------------------------
   Live in production
   -------------------------------------------------------------------------- */
.systems { display: grid; gap: 1px; background: var(--band-rule); border: 1px solid var(--band-rule); }
@media (min-width: 720px) { .systems { grid-template-columns: repeat(2, 1fr); } }
.system {
  background: var(--band-bg); padding: clamp(1.5rem, 3vw, 2rem);
  display: flex; flex-direction: column; gap: .875rem;
  text-decoration: none;
  transition: background-color var(--t-fast) var(--ease);
}
.system:hover { background: color-mix(in srgb, var(--band-bg) 88%, var(--signal)); }
/* Client logos are drawn for light backgrounds, and the JPEG-sourced ones carry
   a baked-in white field with no alpha. On the ink band they would read as white
   boxes, so every logo gets the same paper plate — consistent, and it means a
   new client logo can be dropped in without checking its background first. */
.system__logo {
  height: 48px; width: auto;
  background: var(--paper);
  padding: .4rem .6rem;
  align-self: start;
}
/* Grid cells equalise height, so a card with a short description would leave a
   ragged gap under it. Anchoring the status line to the bottom keeps the row of
   "in production" markers aligned across cards regardless of copy length. */
.system__status {
  display: inline-flex; align-items: center; gap: .5rem;
  color: var(--band-muted); margin-top: auto; padding-top: .5rem;
}
.system__status::before {
  content: ""; width: .5rem; height: .5rem; border-radius: 50%;
  background: var(--live); flex: none;
}
.system__quote {
  font-style: italic; color: var(--band-muted);
  border-left: 2px solid var(--signal); padding-left: 1rem; margin: 0;
}

/* --------------------------------------------------------------------------
   Process — numbered because the content genuinely IS a sequence
   -------------------------------------------------------------------------- */
.steps { counter-reset: step; display: grid; gap: 1px; background: var(--band-rule); border-top: 1px solid var(--band-rule); }
@media (min-width: 900px) { .steps { grid-template-columns: repeat(4, 1fr); } }
.step { background: var(--band-bg); padding: clamp(1.5rem, 3vw, 2rem); counter-increment: step; }
.step::before {
  content: counter(step, decimal-leading-zero);
  display: block; font: 500 .75rem/1 var(--font-mono);
  color: var(--signal-deep); letter-spacing: .1em; margin-bottom: 1rem;
}
.band--ink .step::before { color: var(--signal); }

/* --------------------------------------------------------------------------
   FAQ
   -------------------------------------------------------------------------- */
.faq { border-top: 1px solid var(--band-rule); }
.faq__item { border-bottom: 1px solid var(--band-rule); }
.faq__q {
  width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  font: 700 clamp(1rem, 1.8vw, 1.1875rem)/1.4 var(--font-body);
  color: inherit; padding: 1.5rem 3rem 1.5rem 0; position: relative;
}
.faq__q::after {
  content: "+"; position: absolute; right: .5rem; top: 50%; transform: translateY(-50%);
  font: 400 1.5rem/1 var(--font-mono); color: var(--signal-deep);
  transition: transform var(--t-mid) var(--ease);
}
.faq__q[aria-expanded="true"]::after { transform: translateY(-50%) rotate(45deg); }
.faq__a { padding-bottom: 1.5rem; color: var(--band-muted); }
.faq__a[hidden] { display: none; }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */
.field { margin-bottom: 1.25rem; }
.field label { display: block; margin-bottom: .4rem; }
.field input, .field select, .field textarea {
  width: 100%; font: 400 1rem/1.5 var(--font-body);
  padding: .8rem .9rem; color: var(--ink);
  background: #fff; border: 1px solid var(--rule); border-radius: 0;
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--ink); }
.field textarea { min-height: 9rem; resize: vertical; }

/*  Honeypot.
    contact.php drops any submission where company_website is non-empty. The
    element ALSO carries this rule inline, deliberately: if hiding it depended
    only on this stylesheet, a CSS load failure or a CSP style-src block would
    make the field visible, real people would fill it in, and every enquiry
    would be silently discarded behind a success message. Belt and braces. */
.ya-hp { position: absolute !important; left: -9999px !important; width: 1px !important; height: 1px !important; overflow: hidden !important; }

/* Contact page: form beside a direct-contact aside. Single column until there is
   genuinely room, so the form never gets squeezed. */
.contact-grid { display: grid; gap: clamp(2rem, 5vw, 4rem); margin-top: clamp(2rem, 5vw, 3.5rem); }
@media (min-width: 900px) { .contact-grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); } }
.contact-grid__aside { border-top: 2px solid var(--ink); padding-top: 1.5rem; }
.contact-list { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: 1.25rem; }
.contact-list li { display: grid; gap: .15rem; }
.contact-list .t-label { color: var(--band-muted); }
.contact-list a { font-weight: 600; }

.form-status { padding: .9rem 1rem; border-left: 3px solid; margin-bottom: 1.25rem; }
.form-status.ok  { border-color: var(--live);   background: color-mix(in srgb, var(--live) 8%, transparent); }
.form-status.err { border-color: #B3261E;       background: color-mix(in srgb, #B3261E 8%, transparent); }

/* --------------------------------------------------------------------------
   Breadcrumbs, footer
   -------------------------------------------------------------------------- */
.crumbs { padding-block: 1rem; border-bottom: 1px solid var(--rule); }
.crumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: .5rem; margin: 0; padding: 0; }
.crumbs li + li::before { content: "/"; margin-right: .5rem; color: var(--band-muted); }
.crumbs a { text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }

.footer__grid { display: grid; gap: 2.5rem; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); }
.footer h2 { font-size: .6875rem; font-family: var(--font-mono); font-weight: 500; text-transform: uppercase; letter-spacing: .1em; color: var(--band-muted); margin-bottom: 1rem; }
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.footer a { text-decoration: none; }
.footer a:hover { text-decoration: underline; }
.footer__legal { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--band-rule); color: var(--band-muted); }

/* --------------------------------------------------------------------------
   Print
   -------------------------------------------------------------------------- */
@media print {
  .nav, .ya-skip, .btn-row { display: none; }
  .band { padding-block: 1rem; background: #fff !important; color: #000 !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; }
}
/* ==========================================================================
   HERO — "The Live Ledger", tuned.  APPEND TO THE END OF assets/css/site.css.

   Written as a pure append block: every rule here either has higher
   specificity than, or later source order than, the declaration it
   supersedes. Nothing above needs deleting for this to take effect. The
   now-dead originals are listed at the foot of this block for a later
   cleanup pass.

   Measured at 1440x800 with the real font metrics: the hero band falls from
   1168.9px to 700.5px (-40%), the band edge lands at y=769.5, and a 30.5px
   sliver of signal yellow holds the bottom of the screen. THE MEASURE's own
   padding-block is 112px, so not one tick of the ruler is spent early.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Heading rhythm.
   `margin: 0 0 .5em` under display type is quadratic — 52px at 104px, the
   single largest gap on the page — and because adjacent margins collapse it
   also swallowed `.hero .t-lede { margin-top: 1.5rem }` whole: max(52,24)=52.
   A rem margin is the same 24px whatever the heading does, on all twelve
   bands. h3/h4 are restated because .75rem is smaller than their old .5em.
   text-wrap: balance is deliberately left inherited — at five lines it was
   squaring a slab; at two it evens the rag, which is what it is for.
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 { margin: 0 0 1.5rem; }
h3, h4         { margin-bottom: .75rem; }

/* --------------------------------------------------------------------------
   2. Display scale.

   CEILING 5.25rem / 84px, reached at viewport 1320.75px.
   This is the load-bearing number. .wrap is min(100vw - 80, 1240px) and
   .band > .wrap carries 4.5rem of measure padding border-box, so the text
   column freezes at 1240 - 72 = 1168px once the viewport passes 1320px.
   6.36vw x 1320.75 = 84px, so the type stops growing 0.75px BEFORE the
   column does. The old 7.5vw kept growing to 1387px — type expanding into a
   column that could not — which is why 1440x800 and 1920x950 rendered a
   typographically identical five-line slab.

   The 40-character headline is 25.06em of advance net of tracking. Two lines
   in 1168px needs 51.1% fill per line; balanced it measures 1059/1046px, so
   90.7% widest and it does not overflow to three lines until 92.6px. That is
   10.3% of headroom — it survives Archivo failing to load (Arial Black is
   narrower), 125% zoom, and every width from 566px to 4K.

   FLOOR 2.25rem / 36px, in force below 566px. At 360px the column is 331.2px
   and greedy breaking gives "Your software" (306px) / "should change" (293px)
   / "when you do." (271px) — three lines, 102.6px. At 40px line one measures
   339px and blows the column into four or five lines, so 36 is not merely
   better than the old 44px floor (nine lines, 540.7px), it is better than 40.
   A rem floor, so 200% browser zoom still scales it (WCAG 1.4.4).

   line-height .92 -> .95: tuned for a five-line slab, needlessly tight on a
   two-line lockup. Costs 8.4px total. Archivo's content area is 1.088em, so
   at .92 the half-leading was -5px a side and ascenders nearly touched
   descenders — compression, read as cheap.

   letter-spacing stays -.03em. Tightening to -.05em removes 3.3% of a
   multi-column overflow (it cannot save a line at any size) while closing the
   counters on "ou"/"us" at display size.

   max-width is em, not ch — Archivo Expanded's '0' is 0.786em, so any ch
   figure is ~20% wrong. 15em = 1260px against a 1168px column, i.e. inert at
   every width we ship. It exists so a future --page-max increase cannot
   silently turn the nameplate back into a paragraph.
   -------------------------------------------------------------------------- */
.t-display {
  font-size: clamp(2.25rem, 6.36vw, 5.25rem);
  line-height: .95;
  letter-spacing: -.03em;
  max-width: 15em;
}

/* Desktop ceiling UNCHANGED at 56px, so eleven other bands, /services, /blog,
   /contact and /portal are untouched: 84/56 = 1.50, a clean fifth. Only the
   mobile floor moves, 32px -> 28px, in force below 622px — where the H1 floor
   is 36px and a 32px h2 left a limp 1.13 step. 36/28 = 1.29. */
.t-h2 { font-size: clamp(1.75rem, 4.5vw, 3.5rem); line-height: 1; }

/* --------------------------------------------------------------------------
   3. Hero band.
   The old padding was frozen above viewport 1236px and knew nothing about
   viewport HEIGHT — the axis that actually differs between the machines this
   page is read on. min(6.5vw, 11vh) is continuous, so it needs no height
   media query and no separate short-laptop guard:
     1280x720  -> 79.2px      1366x768  -> 84.5px
     1440x800  -> 88.0px      1920x950  -> 104.5px
   Safe because this is PADDING, not font-size (no text-resize violation), and
   vh not dvh, so an animating mobile URL bar cannot reflow it.
   -------------------------------------------------------------------------- */
.hero {
  padding-block: clamp(2.5rem, min(6.5vw, 11vh), 6.5rem)
                 clamp(2.5rem, 3.5vw, 4rem);
}

/* The vertical Martian Mono section label is pinned by .band[data-measure]
   ::after at top: clamp(3.5rem, 9vw, 7rem) = 112px, independent of .hero's
   own padding. With the hero now opening at 88px the label would slip 24px
   below the eyebrow it currently aligns with. Same specificity as the .band
   rule (0,2,0), later source order, so this wins. Harmless below 1100px,
   where `content` is never set and the pseudo-element does not generate. */
.hero[data-measure]::after {
  top: clamp(2.5rem, min(6.5vw, 11vh), 6.5rem);
}

.hero__eyebrow { color: var(--band-muted); margin-bottom: 1.5rem; }

/* rem, not em, and paired with margin-top: 0 on the lede below, so there is
   exactly one number controlling this gap and no margin collapse to reason
   about. 28px, flat, at every size. */
.hero .t-display { margin-bottom: 1.75rem; }

/* 20px ceiling, not 22px: the lede supports the nameplate, it does not
   compete with the proof block. 54ch is a deliberate widening from 46ch — at
   20px that is ~60 characters a line, which holds the 86-character sentence
   in two lines with real margin rather than on a knife edge. */
.hero .t-lede {
  margin-top: 0;
  max-width: 54ch;
  font-size: clamp(1.0625rem, 1.35vw, 1.25rem);
}

/* --------------------------------------------------------------------------
   4. Secondary CTA, demoted but not disarmed.
   Two equal-weight buttons is the loudest generic-SaaS tell left in the hero.
   But for a buyer whose fear is "can one person be trusted", going to look at
   the evidence IS part of converting — and on a phone a 14px underlined text
   link is a poor tap target. So: keep the button, halve its optical weight.
   1px border against the primary's 2px, olive against ink, and a mono
   down-arrow so it reads as scroll-to-proof rather than leave-the-page.
   Scoped to .hero, so .btn--ghost is unchanged on every other band.
   Flex default align-items: stretch keeps both buttons the same 47.4px
   height despite the thinner border, so the row stays level.
   -------------------------------------------------------------------------- */
.hero .btn--ghost {
  border-width: 1px;
  color: var(--band-muted);
}
.hero .btn--ghost::after {
  content: "\2193";
  font: 500 .875em/1 var(--font-mono);
}
.hero .btn--ghost:hover,
.hero .btn--ghost:focus-visible { color: var(--band-bg); }

/* --------------------------------------------------------------------------
   5. The proof block.
   Explicit 4 columns instead of auto-fit(minmax(9rem,1fr)): auto-fit produces
   a ragged 3+1 at intermediate widths, and a visibly broken grid in the one
   block whose entire job is to look reliable is a conversion bug, not a
   cosmetic one.
   Numerals 44px -> 36px. At 44 they were LOUDER than every 56px section
   heading once you account for Archivo 800's weight; at 36 they sit correctly
   under the section heads and stop competing with the 84px nameplate.
   :first-child padding-left: 0 puts "28+" on the same left edge as the H1,
   the lede and the buttons. On a design whose whole discipline is hard-left
   alignment against a measure gutter, a 20px inset on the first cell is a
   visible break.
   -------------------------------------------------------------------------- */
.stats {
  grid-template-columns: repeat(4, 1fr);
  margin-top: clamp(2rem, 4vw, 3.5rem);
}
.stat__n { font-size: clamp(1.5rem, 2.6vw, 2.25rem); }
.stats > .stat:first-child { padding-left: 0; }

/* The receipt. Six domains a sceptical practice owner can type into a browser
   bar, welded to the underside of the cell that claims "6" — which makes the
   site's own metric auditable, a thing nobody in this category does.
   Deliberately a CAPTION, not a component: no list markers, no status
   squares, no rules of its own. It hangs off the stat bar's existing bottom
   hairline and costs 16px. A ruled strip with coloured markers would have
   been a second measured object 30px above THE MEASURE; this is a footnote.
   Rendered as plain unlinked text so it registers as proof without becoming
   six exit ramps above the fold — the hero keeps exactly two clickable things.
   Fits one line at 1168px (~759px wide); wraps to three at 360px. */
.stats__proof {
  margin: .875rem 0 0;
  max-width: none;
  color: var(--band-muted);
  font-size: .625rem;
  letter-spacing: .09em;
  line-height: 1.6;
}

/* Below the existing nav breakpoint — no new breakpoint invented. 2x2 rather
   than the single-column spec plate: the plate is four ~54px rows against
   2x2's ~193px total, i.e. TALLER, and mobile fold is the binding constraint
   now that the hero button is the only CTA a phone user can reach. */
@media (max-width: 860px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
  .stat  { padding: 1rem; }
  .stats > .stat:nth-child(odd) { padding-left: 0; }
}

/* --------------------------------------------------------------------------
   6. THE MEASURE — three honesty fixes. Not a redesign: same grammar, truer
   numbers. The signature's entire rhetorical force is "both bars use the same
   ruler", so it has to survive someone measuring it.

   a) The track had only border-left, so the 180-day terminus was undrawn and
      the scale was only legible AFTER the animation ran. Now the bar arrives
      into a frame that already exists.
   b) Tick pitch was `transparent 1px 10%` — an 18-day tick, a meaningless
      unit. 8.3333% is 15 days (minor, half-height, hanging from the baseline)
      and 25% is 45 days (major, full height). 25% is exactly 3 x 8.3333%, so
      the two layers can never disagree.
   c) The 1-day bar is held at --pct:0.9% in index.php with a comment openly
      admitting 1/180 rounds to nothing. The true ratio is 0.5555% = 6.5px in
      the 1168px column, which renders honestly on desktop; min-width floors
      it at 3px on a phone where it would otherwise vanish. Inflate the bar
      and you have handed a sceptic the one thing they could catch you on.
   The existing prefers-reduced-motion guard on .measure__bar is untouched.
   -------------------------------------------------------------------------- */
.measure__track {
  border-right: 2px solid var(--ink);
  background-image:
    repeating-linear-gradient(90deg, rgba(21,17,9,.28) 0 1px, transparent 1px 25%),
    repeating-linear-gradient(90deg, rgba(21,17,9,.28) 0 1px, transparent 1px 8.3333%);
  background-size:     100% 100%, 100% 45%;
  background-position: 0 0,       0 100%;
  background-repeat:   no-repeat;
}
.measure__row--ours .measure__bar { min-width: 3px; }

/* --------------------------------------------------------------------------
   7. Two defects every judge flagged, neither hero-specific.
   scroll-behavior: smooth is set at site.css:102 and no scroll-margin exists
   anywhere in the stylesheet, so "See 6 live systems" -> #production puts the
   sticky nav's 69px (4.25rem + 1px rule) straight over that section's
   heading. 69 + 23px of air.
   And .system__status::before is the only border-radius on the entire site
   outside the focus ring — it directly contradicts the direction's hard
   constraint. One declaration makes the page obey its own rule.
   -------------------------------------------------------------------------- */
[id] { scroll-margin-top: 5.75rem; }
.system__status::before { border-radius: 0; }

/* --------------------------------------------------------------------------
   8. Mobile CTA blackout — INERT UNTIL THE MARKUP MOVE (see htmlChanges).
   Below 860px .nav__cta is display:none and its only visible instance lives
   inside .nav__links, which is transform: translateY(-100%); visibility:
   hidden until the hamburger is tapped. So on every phone the hero's "Book a
   discovery call" is not the primary CTA — it is the ONLY one, with no
   persistent fallback anywhere on the page. These selectors match nothing in
   the current DOM (.nav__cta is a child of .nav__links, not .nav__inner), so
   pasting them changes nothing until the <li> is moved out of the <ul>.
   -------------------------------------------------------------------------- */
@media (max-width: 860px) {
  .nav__inner > .nav__cta { display: block; order: 1; }
  .nav__inner > .nav__cta .btn {
    padding: .8em 1em;
    font-size: .75rem;
    letter-spacing: .05em;
  }
  .nav__toggle { order: 2; }
}

/* ==========================================================================
   SUPERSEDED — safe to delete from the block above in a later cleanup pass.
   Leaving them costs nothing but dead bytes; deleting them is tidier.
     line 154  h1,h2,h3,h4  margin: 0 0 .5em
     line 159  .t-display   font-size: clamp(2.75rem, 7.5vw, 6.5rem)
     line 160  .t-display   line-height: .92
     line 163  .t-h2        font-size: clamp(2rem, 4.5vw, 3.5rem)
     line 326  .hero        padding-block: clamp(4rem,11vw,8.5rem) clamp(3rem,7vw,5rem)
     line 327  .hero__eyebrow  margin-bottom: 1.75rem
     line 333  .hero .t-lede   margin-top: 1.5rem; max-width: 46ch
     line 336  .stats       grid-template-columns: repeat(auto-fit, minmax(9rem,1fr))
     line 339  .stats       margin-top: clamp(3rem, 7vw, 5rem)
     line 342  .stat__n     font-size inside the `font:` shorthand
     line 368  .measure__track  background-image (10% tick pitch)
     line 472  .system__status::before  border-radius: 50%
   ========================================================================== */
/* --------------------------------------------------------------------------
   Service pages — prose beside a spec aside.
   -------------------------------------------------------------------------- */
.svc-grid { display: grid; gap: clamp(2rem, 5vw, 4rem); }
@media (min-width: 900px) { .svc-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); } }
.svc-grid > div > h2:first-child { margin-top: 0; }
.svc-aside { border-top: 2px solid var(--ink); padding-top: 1.25rem; align-self: start; }
@media (min-width: 900px) { .svc-aside { position: sticky; top: 6rem; } }
.svc-aside h2 { color: var(--band-muted); margin-bottom: 1rem; }
.svc-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; font-size: .9375rem; }
.svc-list li { padding-left: 1.15rem; position: relative; }
.svc-list li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: .4rem; height: .4rem; background: var(--signal);
}

/* --------------------------------------------------------------------------
   Long-form prose. The seven posts previously rendered in an abandoned
   gold/black Vite design that did not match their own listing page.
   -------------------------------------------------------------------------- */
.post__head { max-width: 46rem; margin-bottom: clamp(2.5rem, 6vw, 4rem); }
.post__head .t-label { color: var(--band-muted); margin-bottom: 1.25rem; }

.prose { max-width: 42rem; font-size: 1.09375rem; }
.prose > * + * { margin-top: 1.35em; }
.prose h2 {
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  margin-top: 2.75em; margin-bottom: .6em;
  padding-top: 1.5rem; border-top: 1px solid var(--rule);
}
.prose h3 { font-size: clamp(1.125rem, 1.9vw, 1.375rem); margin-top: 2em; margin-bottom: .5em; }
.prose p  { color: var(--olive); max-width: none; }
.prose strong { color: var(--ink); font-weight: 600; }
.prose a { color: var(--ink); text-decoration-color: var(--signal-deep); }
.prose a:hover { background: var(--signal); text-decoration: none; }
.prose ul, .prose ol { padding-left: 1.35rem; color: var(--olive); }
.prose li + li { margin-top: .5em; }
.prose li::marker { color: var(--signal-deep); }
.prose blockquote {
  margin-inline: 0; padding: .25rem 0 .25rem 1.5rem;
  border-left: 3px solid var(--signal);
  font-size: 1.1875rem; color: var(--ink);
}
.prose pre {
  background: var(--ink); color: var(--paper);
  padding: 1.25rem 1.5rem; overflow-x: auto;
  font: 400 .875rem/1.7 var(--font-mono);
}
.prose :not(pre) > code {
  font: 400 .875em/1 var(--font-mono);
  background: color-mix(in srgb, var(--signal) 22%, transparent);
  padding: .15em .35em;
}
.prose img { margin-block: 2rem; border: 1px solid var(--rule); }
.prose table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.prose th, .prose td { text-align: left; padding: .6rem .75rem; border-bottom: 1px solid var(--rule); }
.prose th { font: 500 .6875rem/1.4 var(--font-mono); text-transform: uppercase; letter-spacing: .1em; }

/* Listing rows carry a description, so they need a wider middle column. */
.post-row { grid-template-columns: minmax(0, 9rem) minmax(0, 1fr) auto; align-items: start; }
@media (max-width: 720px) { .post-row { grid-template-columns: 1fr; } }
