/* ==========================================================================
   Levantar.ai
   Design register: typography-led, instrument motif, generous whitespace.
   Ink on warm paper, structural teal, and one flame accent reserved for action.
   ========================================================================== */

/* Self-hosted fonts (latin subset) — no third-party font requests. */
@font-face {
  font-family: 'Inter Tight';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/inter-tight-var.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/source-serif-4-400.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/source-serif-4-400-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------------------
   Tokens
   -------------------------------------------------------------------------- */
:root {
  --paper: #f7f5f0;
  --paper-warm: #efece4;
  --paper-3: #e5e0d4;
  --ink: #0e1216;
  --ink-2: #4a5158;
  --ink-lede: #2f3438;
  /* Muted, but not so muted it fails WCAG AA. #798086 came in at 3.67:1 on
     paper and 3.39:1 on warm; this is the lightest grey that clears 4.5:1 on
     both, so captions and dates keep their recessive feel and stay readable. */
  --ink-3: #656c72;
  /* Teal is structural: eyebrows, links, hairlines, chart strokes, outline buttons. */
  --teal-700: #0d5257;
  --accent: var(--teal-700);
  --accent-2: #0a3f43;
  --accent-lift: #7fc5c2;

  /* Flame is the one colour that pops, and it is reserved for action:
     primary CTA fills, the problem router's interactive edge, the terminal
     dot on a spark-line, the single hero highlight, and focus rings.

     flame-500 stays the brand accent everywhere it carries no text — the hero
     highlight, the router's edge, the focus ring (3.40:1 on paper, over the
     3:1 non-text bar). White on it is only 3.71:1, so anything with text on a
     flame fill steps down to flame-600 (5.11:1) and hovers to flame-700. */
  --flame-500: #e05a2b;
  --flame-600: #c24314;
  --flame-700: #a63811;
  --flame-100: #fae4da;
  --teal-deep: #083a3e;
  --dark: #0b1315;
  --dark-2: #122023;
  --dark-ink: #e9e7e0;
  --dark-ink-2: #a7b0b1;
  --rule: #dcd5c6;
  --rule-strong: #c6bda9;
  --rule-dark: rgba(233, 231, 224, 0.16);

  --sans: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --serif: 'Source Serif 4', Georgia, 'Times New Roman', serif;

  --maxw: 1320px;
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --section-y: clamp(4.5rem, 9vw, 8rem);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.125rem;
  line-height: 1.65;
  /* A long unbroken token — a bare URL in a post — is wider than a phone and
     forces the whole page wide, at which point body text stops wrapping to the
     viewport at all. Nothing here is worth that. */
  overflow-wrap: break-word;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.08;
  text-wrap: balance;
}

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

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 0.2em; }

/* WCAG 1.4.1: inside running copy, teal against ink is the only thing marking
   a link, and colour alone is not an affordance. The link components carry an
   arrow or sit in their own box, so they are already distinguishable — this is
   scoped to bare links in body text. */
.prose p a, .prose li a,
.article p a, .article li a,
.lead a {
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.2em;
}
.prose .textlink, .prose .btn,
.article .textlink, .article .btn,
.lead .textlink, .lead .btn {
  text-decoration: none;
}

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

ul { margin: 0 0 1.15em; padding-left: 1.15em; }
li { margin-bottom: 0.4em; }

::selection { background: var(--accent); color: var(--paper); }

:focus-visible {
  outline: 2px solid var(--flame-500);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--ink);
  color: var(--paper);
  padding: 0.75rem 1.25rem;
  z-index: 200;
}
.skip-link:focus { left: 0; }

/* --------------------------------------------------------------------------
   Layout
   -------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.wrap--narrow { max-width: 760px; }

.section {
  padding: var(--section-y) 0;
  position: relative;
}

.section--alt { background: var(--paper-warm); }

/* Pure white, for the logo band: twelve of the marks are white-background
   tiles, which show as boxes on paper but disappear on white. */
.section--white { background: #fff; }

.section--dark {
  background: var(--dark);
  color: var(--dark-ink);
}
.section--dark h1,
.section--dark h2,
.section--dark h3 { color: var(--dark-ink); }
.section--dark a { color: var(--accent-lift); }

.section--hairline { border-top: 1px solid var(--rule); }

/* Full-bleed bands, so the router and the who-we-are strip don't sit in the
   same paper as everything around them.

   The router sits on warm paper; the who-we-are strip keeps its slab. */
.section--teal-deep {
  background: var(--teal-deep);
  color: var(--paper);
}
.section--teal-deep h2 { color: inherit; }

/* --------------------------------------------------------------------------
   Instrument motif — rules, ticks, sparklines
   -------------------------------------------------------------------------- */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0 0 1.5rem;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow::before {
  content: '';
  width: 2.25rem;
  height: 8px;
  flex: none;
  background-image: repeating-linear-gradient(to right, currentColor 0 1px, transparent 1px 6px);
}
.section--dark .eyebrow { color: var(--accent-lift); }

.ticks {
  height: 10px;
  background-image: repeating-linear-gradient(to right, var(--rule-strong) 0 1px, transparent 1px 12px);
  border-top: 1px solid var(--rule);
  margin: 0;
}
.section--dark .ticks {
  background-image: repeating-linear-gradient(to right, var(--rule-dark) 0 1px, transparent 1px 12px);
  border-top-color: var(--rule-dark);
}

.grid-field {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(20, 24, 27, 0.045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(20, 24, 27, 0.045) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(120% 90% at 78% 12%, #000 0%, transparent 72%);
  mask-image: radial-gradient(120% 90% at 78% 12%, #000 0%, transparent 72%);
}

/* --------------------------------------------------------------------------
   Section headers
   -------------------------------------------------------------------------- */
.section-head { max-width: 900px; margin-bottom: clamp(2.5rem, 5vw, 3.75rem); }

.section-head h2 {
  font-size: clamp(2rem, 3.6vw, 3.25rem);
  line-height: 1.05;
}

.section-head .standfirst {
  margin-top: 1.5rem;
  font-family: var(--serif);
  font-size: 1.5rem;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 720px;
}
.section--dark .section-head .standfirst { color: var(--dark-ink-2); }

/* A narrative paragraph: the one that carries a section's argument, or the
   line that lands after a pull-quote. Between standfirst and body — 20px, and
   in ink rather than the muted grey body copy uses. */
.lede {
  font-size: 1.375rem;
  line-height: 1.6;
  color: var(--ink-lede);
}
.section--dark .lede,
.section--teal-deep .lede { color: var(--dark-ink); }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.9rem 1.75rem;
  background: var(--flame-600);
  color: #fff;
  font-size: 1.125rem;
  font-weight: 500;
  letter-spacing: 0.005em;
  border: 1px solid var(--flame-600);
  border-radius: 2px;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
.btn:hover {
  background: var(--flame-700);
  border-color: var(--flame-700);
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
}
.btn svg { flex: none; }

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule-strong);
}
.btn--ghost:hover {
  background: transparent;
  color: var(--accent);
  border-color: var(--accent);
}

/* Flame carries straight onto dark sections; no restyling needed. */

/* .section--dark a repaints every link pale teal, and it out-specifies .btn —
   which left white-on-flame buttons rendering teal-on-flame. */
.section--dark .btn,
.section--dark .btn:hover {
  color: #fff;
}

.section--dark .btn--ghost {
  background: transparent;
  color: var(--dark-ink);
  border-color: var(--rule-dark);
}
.section--dark .btn--ghost:hover {
  color: var(--accent-lift);
  border-color: var(--accent-lift);
  background: transparent;
}

.textlink {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-weight: 500;
  font-size: 1em;
}
.textlink svg { transition: transform 0.2s var(--ease); }
.textlink:hover svg { transform: translateX(3px); }

/* --------------------------------------------------------------------------
   Header / navigation
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(247, 245, 240, 0.88);
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s var(--ease);
}
.site-header.is-stuck { border-bottom-color: var(--rule); }

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 5.25rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--ink);
  font-weight: 600;
  letter-spacing: -0.02em;
  font-size: 1.15rem;
}
.brand:hover { text-decoration: none; }
.brand img { width: 40px; height: auto; }

.nav-links {
  display: flex;
  align-items: center;
  gap: 2rem;
}
.nav-links a {
  color: var(--ink-2);
  font-size: 1rem;
  font-weight: 500;
}
.nav-links a:hover { color: var(--ink); text-decoration: none; }
.nav-links .btn { padding: 0.6rem 1.1rem; color: #fff; }

.nav-toggle {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: transparent;
  cursor: pointer;
  position: relative;
}
.nav-toggle span {
  position: absolute;
  left: 50%;
  width: 18px;
  height: 1.5px;
  background: var(--ink);
  transform: translateX(-50%);
  transition: transform 0.2s var(--ease), opacity 0.2s var(--ease);
}
.nav-toggle span:nth-child(1) { top: 16px; }
.nav-toggle span:nth-child(2) { top: 22px; }
.nav-toggle span:nth-child(3) { top: 28px; }
.nav-toggle[aria-expanded='true'] span:nth-child(1) { transform: translateX(-50%) translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded='true'] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded='true'] span:nth-child(3) { transform: translateX(-50%) translateY(-6px) rotate(-45deg); }

@media (max-width: 860px) {
  .nav-toggle { display: block; }
  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 0 var(--gutter);
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s var(--ease);
  }
  .nav-links.is-open { max-height: 26rem; padding-bottom: 1.5rem; }
  .nav-links a {
    width: 100%;
    padding: 1rem 0;
    border-bottom: 1px solid var(--rule);
    font-size: 1rem;
  }
  .nav-links .btn {
    margin-top: 1.25rem;
    border-bottom: none;
    justify-content: center;
    padding: 0.9rem 1.1rem;
  }
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  padding: clamp(4rem, 10vw, 8rem) 0 clamp(3.5rem, 7vw, 6rem);
}

.hero .wrap { position: relative; z-index: 1; }

.hero h1 {
  font-size: clamp(2.75rem, 5.5vw, 5.25rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
  max-width: 900px;
}
.hero h1 .problem {
  display: block;
  color: var(--ink-2);
}
.hero h1 .promise { display: block; }

/* The eyebrow carries a shorter line on phones, where the long one wraps to
   three lines of small caps before the headline even starts. */
.eyebrow-short { display: none; }
@media (max-width: 620px) {
  .eyebrow-long { display: none; }
  .eyebrow-short { display: inline; }
}

/* Phones: the headline needs room. At 1.02 the two statements almost touch
   once each of them wraps, and the eyebrow and lead crowd in from both sides. */
@media (max-width: 620px) {
  .hero { padding: 3.25rem 0 4rem; }
  .hero .eyebrow { margin-bottom: 2.25rem; }
  .hero h1 { line-height: 1.12; }
  .hero h1 .promise { margin-top: 0.6rem; }
  .hero .lead { margin-top: 2.25rem; }
  .hero-actions { margin-top: 2.25rem; }
}

/* The one highlighter treatment on the site: "gain big" in the hero. */
.mark {
  background-image: linear-gradient(var(--flame-500), var(--flame-500));
  background-repeat: no-repeat;
  background-size: 100% 0.26em;
  background-position: 0 92%;
  padding: 0 0.06em;
}

.hero .lead {
  margin-top: clamp(1.75rem, 3vw, 2.25rem);
  max-width: 900px;
  font-family: var(--serif);
  font-size: 1.5rem;
  line-height: 1.55;
  color: var(--ink-2);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.75rem;
  margin-top: clamp(2rem, 4vw, 2.75rem);
}

/* --------------------------------------------------------------------------
   Problem router — the primary conversion path. A skimming visitor picks
   their own problem in five seconds; the long scroll is supporting material.
   -------------------------------------------------------------------------- */
.router {
  padding: clamp(2.5rem, 5vw, 3.5rem) 0;
}


.router-label {
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  margin-bottom: 1.25rem;
}

.router-grid {
  display: grid;
  /* Five explicit columns: auto-fit was dropping to four and leaving one card
     stranded on a second row. Five and one are the only counts that divide
     evenly, so below the threshold it goes to two and then one. */
  grid-template-columns: repeat(5, 1fr);
  gap: clamp(0.75rem, 1.2vw, 1rem);
}
@media (max-width: 1040px) {
  .router-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .router-grid { grid-template-columns: 1fr; }
}

.router-card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  background: var(--paper);
  border: 1px solid var(--rule-strong);
  border-left: 3px solid var(--flame-500);
  padding: clamp(1.15rem, 1.8vw, 1.45rem);
  color: var(--ink);
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease), transform 0.15s var(--ease);
}
.router-card:hover,
.router-card:focus-visible {
  background: var(--flame-100);
  border-color: var(--rule-strong);
  border-left-color: var(--flame-600);
  text-decoration: none;
  transform: translateY(-2px);
}

.router-quote {
  font-size: 1.1875rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.015em;
}

.router-action {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 1em;
  font-weight: 500;
  /* flame-600 reads at only 4.18:1 once the card takes its flame-100 hover
     tint, so this one steps down again and clears both states. */
  color: var(--flame-700);
}
.router-card:hover .router-action svg { transform: translateX(3px); }
.router-action svg { transition: transform 0.15s var(--ease); }

/* --------------------------------------------------------------------------
   The gap — 88 / 6 instrument
   -------------------------------------------------------------------------- */
.gap-layout {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(2.5rem, 6vw, 5.5rem);
  align-items: start;
}
@media (max-width: 880px) {
  .gap-layout { grid-template-columns: 1fr; }
}

.gauge {
  border: 1px solid var(--rule-strong);
  background: var(--paper);
  padding: clamp(1.5rem, 3vw, 2.25rem);
}
.section--alt .gauge { background: var(--paper); }

.gauge-row + .gauge-row { margin-top: 2rem; }

.gauge .note-line { font-size: 1rem; }

.gauge-source {
  margin-top: 1.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* The methodology link sits in the attribution, not above it: same fine print,
   same muted ink, underlined because at this size colour alone would be the
   only thing marking it — the point in the WCAG note further up. */
.gauge-source a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.2em;
}
.gauge-source a:hover { color: var(--ink); }

.section-head--flush { margin-bottom: 0; }

.gauge-figure {
  font-size: clamp(2.5rem, 5vw, 4.5rem);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1;
}
.gauge-row--accent .gauge-figure { color: var(--accent); }

.gauge-label {
  margin-top: 0.5rem;
  font-size: 1rem;
  color: var(--ink-2);
  max-width: 34ch;
}

.gauge-bar {
  position: relative;
  height: 10px;
  margin-top: 1rem;
  background: var(--paper-3);
  overflow: hidden;
}
.gauge-fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--ink);
  width: 0;
  transition: width 1.1s var(--ease);
}
.gauge-row--accent .gauge-fill { background: var(--accent); }
.is-revealed .gauge-fill { width: var(--value); }

.gauge-scale {
  display: flex;
  justify-content: space-between;
  margin-top: 0.5rem;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Defines what the accent figure counts. Secondary to the number by size and
   colour, on the small step the rest of the page's fine print already uses. */
.gauge-note {
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  color: var(--ink-3);
  max-width: 40ch;
}

.pull {
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 0;
  padding-left: clamp(1.25rem, 3vw, 2rem);
  border-left: 3px solid var(--accent);
  font-size: clamp(1.35rem, 2.7vw, 1.9rem);
  line-height: 1.28;
  letter-spacing: -0.02em;
  font-weight: 500;
  max-width: 24ch;
}

.note-line {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  font-size: 1.125rem;
  color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   Who we are — quote
   -------------------------------------------------------------------------- */
.quote-block {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(1.25rem, 3vw, 2rem);
  align-items: start;
  border-top: 1px solid var(--rule);
  padding-top: clamp(2rem, 4vw, 2.75rem);
}
.quote-block img {
  width: 76px;
  height: 76px;
  border-radius: 50%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05);
}
.quote-block blockquote {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.15rem, 2.3vw, 1.55rem);
  line-height: 1.45;
}
.quote-attr {
  margin-top: 1rem;
  font-size: 1rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
@media (max-width: 620px) {
  .quote-block { grid-template-columns: 1fr; }
}

/* The three pillars, closing the gap section and previewing the doors. */
.pillars-lead {
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 1.5rem;
  font-size: 1.1rem;
  font-weight: 500;
  color: var(--ink);
}

.pillars {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
}
@media (max-width: 780px) {
  .pillars { grid-template-columns: 1fr; }
}

.pillar {
  display: block;
  border-top: 3px solid var(--teal-700);
  padding-top: 1.1rem;
  color: var(--ink);
}
.pillar:hover { text-decoration: none; }
.pillar h3 {
  font-size: 1.25rem;
  letter-spacing: -0.025em;
  margin-bottom: 0.6rem;
}
.pillar p {
  font-size: 1.125rem;
  color: var(--ink-2);
  margin-bottom: 0.8rem;
}
.pillar-action {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 1em;
  font-weight: 500;
  color: var(--accent);
}
.pillar-action svg { transition: transform 0.18s var(--ease); }
.pillar:hover .pillar-action svg { transform: translateX(3px); }

/* --------------------------------------------------------------------------
   Delivery history — wordmarks now, official logos when they land
   -------------------------------------------------------------------------- */
/* A marquee, not a scrollbar: the row drifts across the full width of the
   viewport and loops. The list is rendered twice — the second copy is
   aria-hidden — so translating by exactly half its width returns to the start
   with no visible seam. */
/* Track record — two rows of white tiles drifting in opposite directions on
   paper. The tiles are the white: the paper between them is what separates the
   marks, so the logos that carry their own white background stop reading as
   boxes. Each row is listed twice and the track is translated by half its
   width, which is what makes the loop seamless. */
.orgs-viewport {
  position: relative;
  width: 100vw;
  margin-left: calc(-50vw + 50%);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
}
.orgs-viewport + .orgs-viewport { margin-top: 1.5rem; }

.orgs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
  width: max-content;
  gap: 1.5rem;
}
.orgs--left { animation: orgs-drift 52s linear infinite; }
.orgs--right { animation: orgs-drift 52s linear infinite reverse; }
.orgs-viewport:hover .orgs { animation-play-state: paused; }

@keyframes orgs-drift {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.org {
  margin: 0;
  flex: 0 0 auto;
  width: 212px;
  min-height: 114px;
  padding: 1.125rem;
  display: grid;
  place-items: center;
  background: #fff;
}

/* Equal height is not equal weight: a 3.7:1 wordmark and a square mark at the
   same height read nothing alike, because a wordmark's weight lives in its
   letter height. Each mark is therefore sized by its own proportions in the
   generated block below; this is only the floor. */
.org img {
  display: block;
  margin: 0 auto;
  max-width: 100%;
  max-height: 56px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.72;
  transition: opacity 0.2s var(--ease);
}
.org:hover img { opacity: 1; }

/* logo-sizing:start */
/* generated by tools/swap-logo.py — sizes each mark by its own proportions */

/* 72px tall — defra 1.9:1 (set by hand), dft 1.5:1 (set by hand), dwp 1.2:1 (set by hand), hmrc 1.7:1 (set by hand) */
.org img[src$="defra.jpg"],
.org img[src$="dft.svg"],
.org img[src$="dwp.svg"],
.org img[src$="hmrc.svg"] {
  max-height: 72px;
}

/* 56px tall — g2g3-digital 1.0:1, intechnica 1.0:1, laterooms 1.4:1, plusnet 1.4:1, split-the-bills 1.5:1, zuhlke 1.0:1 */
.org img[src$="g2g3-digital.jpeg"],
.org img[src$="intechnica.jpeg"],
.org img[src$="laterooms.png"],
.org img[src$="plusnet.png"],
.org img[src$="split-the-bills.jpg"],
.org img[src$="zuhlke.png"] {
  max-height: 56px;
}

/* 51px tall — assetz-capital 2.2:1, capita 3.1:1, hp-enterprise 2.4:1, on-the-beach 2.3:1 */
.org img[src$="assetz-capital.png"],
.org img[src$="capita.png"],
.org img[src$="hp-enterprise.svg"],
.org img[src$="on-the-beach.png"] {
  max-height: 51px;
}

/* 42px tall — and-digital 5.2:1, equal-experts 3.7:1, first-direct 3.6:1, hsbc 3.7:1, valtech 4.4:1 */
.org img[src$="and-digital.png"],
.org img[src$="equal-experts.jpg"],
.org img[src$="first-direct.png"],
.org img[src$="hsbc.svg"],
.org img[src$="valtech.svg"] {
  max-height: 42px;
}

/* 39px tall — emis 2.6:1 (set by hand) */
.org img[src$="emis.jpg"] {
  max-height: 39px;
}
/* logo-sizing:end */

/* The four government marks are crest-over-text lockups carrying their own
   built-in side space, so centring them reads as a drift. Flush left. */
.org img[src*="hmrc"],
.org img[src*="dwp"],
.org img[src*="dft"],
.org img[src*="defra"] {
  justify-self: start;
  margin-left: 0;
  margin-right: auto;
}

@media (max-width: 700px) {
  .org { width: 168px; min-height: 96px; padding: 0.9rem; }
  .orgs { gap: 1rem; }
}

/* Motion is decoration here; the marks are the point. Without it the rows
   simply wrap, and the duplicate copy is hidden so nothing reads twice. */
@media (prefers-reduced-motion: reduce) {
  .orgs { animation: none; flex-wrap: wrap; width: auto; justify-content: center; }
  .orgs-viewport {
    width: auto;
    margin-left: 0;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .org[aria-hidden="true"] { display: none; }
}

/* Option 2 services layout: a boxed flagship, then the rest as plain links. */
.ways-more-label {
  margin: 1.5rem 0 0.6rem;
  font-size: 0.8125rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
}
.ways-more {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
}
.ways-more li { margin: 0; padding: 0.4rem 0; border-bottom: 1px solid var(--rule); }
.ways-more li:first-child { border-top: 1px solid var(--rule); }
.ways-more a { color: var(--ink); font-weight: 500; }
.ways-more a:hover { color: var(--accent); }

/* --------------------------------------------------------------------------
   Who-we-are band — one sentence, the numbers, and a route to the company page
   -------------------------------------------------------------------------- */
.band {
  padding: clamp(3rem, 6vw, 4.5rem) 0;
}

.band-layout {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
@media (max-width: 880px) {
  .band-layout { grid-template-columns: 1fr; }
}

.band-statement {
  font-size: clamp(1.3rem, 2.6vw, 1.8rem);
  line-height: 1.35;
  letter-spacing: -0.02em;
  font-weight: 500;
  max-width: 26ch;
}

/* The four products, named quietly under the statement: they are what makes
   "4 AI products in production" checkable rather than a claim. */
.band-products {
  margin-top: 1.1rem;
  max-width: 34ch;
  font-size: 1.0625rem;
  line-height: 1.55;
  color: rgba(247, 245, 240, 0.72);
}
.band-products a {
  color: var(--paper);
  text-decoration: underline;
  text-decoration-color: rgba(247, 245, 240, 0.4);
  text-underline-offset: 0.2em;
}
.band-products a:hover { text-decoration-color: var(--paper); }

.band-link {
  margin-top: 1.35rem;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--paper);
  font-size: 1em;
  font-weight: 500;
}
.band-link svg { transition: transform 0.2s var(--ease); }
.band-link:hover svg { transform: translateX(3px); }

.band-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
}
@media (max-width: 520px) {
  .band-stats { grid-template-columns: 1fr; }
}
@media (max-width: 880px) {
  .band-stats { margin-top: 2rem; }
}
.band-stat {
  border-top: 1px solid rgba(247, 245, 240, 0.28);
  padding-top: 1rem;
}
.band-stat strong {
  display: block;
  font-size: clamp(1.6rem, 3.2vw, 2.2rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.1;
}
.band-stat span {
  display: block;
  margin-top: 0.4rem;
  font-size: 1rem;
  color: rgba(247, 245, 240, 0.75);
}

/* --------------------------------------------------------------------------
   The three doors
   -------------------------------------------------------------------------- */
.doors {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--rule-strong);
  border: 1px solid var(--rule-strong);
}
@media (max-width: 960px) {
  .doors { grid-template-columns: 1fr; }
}

.door {
  background: var(--paper);
  padding: clamp(1.75rem, 3.2vw, 2.5rem);
  display: flex;
  flex-direction: column;
}

/* Header, body and services each take a shared row, so the "Our services"
   label starts at the same height in all three columns however long the copy
   above it runs. Falls back to the flex column where subgrid is unsupported,
   where the labels simply sit wherever the copy leaves them. */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 961px) {
    .doors {
      grid-template-rows: auto auto auto auto;
      align-items: stretch;
    }
    .door {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: span 4;
    }
    /* Each block sits at the top of its shared row. The flex layout pushes the
       services to the bottom of the card, which here would drop the label to
       the bottom of the row and undo the alignment.

       Scoped to .door — the flex rules are defined later in this file, so a
       bare .ways selector loses to them on source order. */
    .door .door-head,
    .door .door-block,
    .door .ways {
      align-self: start;
    }
    .door .ways { margin-top: 0; }
  }
}

/* The head keeps its own breathing room, so the gap between the door sentence
   and the copy below it is the same in every column — without it, a two-line
   sentence runs straight into the paragraph while a one-line one doesn't. */
.door-head { padding-bottom: 1.5rem; }
.door-block { padding-bottom: 1.25rem; }
.section--alt .door { background: var(--paper); }

.door-index {
  font-size: 0.8125rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
}

.door-name {
  margin: 1.25rem 0 0.4rem;
  font-size: 0.8125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}

.door h3 {
  font-size: 1.55rem;
  line-height: 1.15;
  letter-spacing: -0.03em;
}

.door p {
  font-size: 1.125rem;
  color: var(--ink-2);
  line-height: 1.62;
}

.door-block p {
  font-size: 1.125rem;
  color: var(--ink-2);
  line-height: 1.62;
}

/* The why is the statement, the what is its explanation — the same ink/grey
   hierarchy the hero and section heads use, so it survives greyscale and
   spends no colour. */
.door-block--why p {
  font-size: 1.1875rem;
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--ink);
}

/* Services as a plain list rather than cards — a card implies a set of equal,
   interchangeable products, and these are engagements. Every entry is
   identical: one teal rule, a name and a line. */
.ways {
  align-self: end;
  margin: auto 0 0;
  padding-top: 1.75rem;
}


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

.rung { margin: 0; }
.rung a {
  display: block;
  padding: 1rem 0 1.1rem 1.15rem;
  border-left: 3px solid rgba(13, 82, 87, 0.35);
  color: var(--ink);
  transition: border-color 0.18s var(--ease), background 0.18s var(--ease);
}
.rung + .rung { margin-top: 0.9rem; }

.rung a:hover {
  text-decoration: none;
  border-left-color: var(--teal-700);
  background: rgba(13, 82, 87, 0.04);
}

.rung-name {
  display: block;
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin-bottom: 0.3rem;
}
.rung-note {
  display: block;
  font-size: 1.0625rem;
  line-height: 1.5;
  color: var(--ink-2);
}

/* Service cards. The homepage uses the ladder above; these are for the
   service pages and the /services index, where a card is the right metaphor —
   there they are a set of equal things to choose between, not rungs. */
.ways-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.75rem;
}

/* Same cards, laid out across the page rather than down a door column —
   used for the related services on a service page. */
.ways-list--wide {
  /* Three tracks so a pair of related services stays card-sized rather than
     stretching to half the new container each. */
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}

.ways-list--wide { grid-template-columns: repeat(2, 1fr); }

.ways-list--wide { grid-template-columns: 1fr; }

/* One box per service: the unit a reader counts when working out what we
   actually sell. The whole box is the target, not just the link in it. */
.ways-list li { margin: 0; }

/* Tick marks along the top edge — the same instrument motif as the section
   rules, marking each service as a measured unit of work. */
.way::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background-image: repeating-linear-gradient(to right, rgba(13, 82, 87, 0.45) 0 1px, transparent 1px 9px);
  z-index: 1;
}

/* Arriving from the router: mark the box the reader was sent to, so the jump
   lands on something visibly selected rather than mid-page. */
.ways-list li:target .way {
  border-color: var(--teal-700);
  box-shadow: 0 0 0 3px rgba(13, 82, 87, 0.12);
}

.way:hover,
.way:focus-visible {
  text-decoration: none;
  border-color: var(--teal-700);
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(13, 82, 87, 0.09);
}

/* The engagement type is chrome, not copy: it runs edge to edge as the card's
   header strip so it reads as a label on the box rather than a first line. */
.way-type {
  display: block;
  margin: -1.6rem -1.45rem 1.1rem;
  padding: 0.75rem 1.45rem 0.6rem;
  background: rgba(13, 82, 87, 0.055);
  border-bottom: 1px solid rgba(13, 82, 87, 0.18);
  font-size: 0.8125rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--accent);
}

/* A second paragraph is detail, not promise — held apart by a hairline and set
   a step down. */
.way p + p {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--rule);
  font-size: 1.1875rem;
  color: var(--ink-2);
}

/* Every card ends on the same action bar, so seven boxes offer the same
   gesture in the same place. */
.way-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 1.45rem -1.45rem -1.45rem;
  padding: 0.85rem 1.45rem;
  border-top: 1px solid rgba(13, 82, 87, 0.18);
  font-size: 1em;
  font-weight: 500;
  color: var(--accent);
  transition: background 0.18s var(--ease);
}

.way-action svg { transition: transform 0.18s var(--ease); }

.way:hover .way-action { background: rgba(13, 82, 87, 0.05); }

.way:hover .way-action svg { transform: translateX(3px); }

.way-name {
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.02em;
  margin-bottom: 0.5rem;
}

/* --------------------------------------------------------------------------
   Refusals
   -------------------------------------------------------------------------- */
.refusals {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}
@media (max-width: 780px) {
  .refusals { grid-template-columns: 1fr; }
}

.refusal {
  border-top: 1px solid var(--rule-dark);
  padding-top: 1.75rem;
}
.refusal h3 {
  font-size: clamp(1.3rem, 2.4vw, 1.7rem);
  line-height: 1.22;
  letter-spacing: -0.025em;
  margin-bottom: 0.9rem;
}
.refusal p { color: var(--dark-ink-2); font-size: 1.125rem; }

/* --------------------------------------------------------------------------
   Engagement arc
   -------------------------------------------------------------------------- */
.arc {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  border-top: 1px solid var(--rule-strong);
}
@media (max-width: 900px) {
  .arc { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .arc { grid-template-columns: 1fr; }
}

.step {
  padding: 2rem clamp(1rem, 2.5vw, 2.5rem) 0 0;
  position: relative;
}
.step::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 0;
  width: 2rem;
  height: 3px;
  background: var(--accent);
}
.step h3 {
  margin: 0 0 0.75rem;
  font-size: 1.35rem;
  letter-spacing: -0.025em;
}
.step p { font-size: 1.125rem; color: var(--ink-2); }

/* Customer quotes — plain, attributed, linked to the business that said it. */
.quotes {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3.5vw, 3rem);
}
@media (max-width: 900px) {
  .quotes { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  .quotes { grid-template-columns: 1fr; }
}

/* In an article the measure is ~68ch, too narrow to split. */
.quotes--stacked {
  grid-template-columns: 1fr;
  gap: 2rem;
}

.quote-card {
  margin: 0; /* <figure> defaults to 1em 40px, which knocked two of three cards out of line */
  border-top: 2px solid var(--teal-700);
  padding-top: 1.25rem;
}
.quote-metric {
  font-size: 0.8125rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--accent);
  margin-bottom: 0.9rem;
}
.quote-card blockquote,
.quote-body {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1.9vw, 1.2rem);
  line-height: 1.55;
  color: var(--ink);
}
.quote-attr {
  margin-top: 1rem;
  font-size: 1rem;
  color: var(--ink-2);
}
.quote-attr strong { color: var(--ink); font-weight: 600; }

/* --------------------------------------------------------------------------
   Insights
   -------------------------------------------------------------------------- */
.posts {
  display: grid;
  /* Three across at the new container width — auto-fit would fit four. */
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 2.2vw, 2.5rem);
}
@media (max-width: 900px) {
  .posts { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  .posts { grid-template-columns: 1fr; }
}

.post-card {
  display: flex;
  flex-direction: column;
  position: relative;
  border: 1px solid var(--rule-strong);
  background: var(--paper);
  padding: 1.5rem 1.6rem 1.6rem;
  color: var(--ink);
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
/* Tick marks and a labelled header strip, the same anatomy as a service box. */
.post-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background-image: repeating-linear-gradient(to right, rgba(13, 82, 87, 0.45) 0 1px, transparent 1px 9px);
  z-index: 1;
}
.post-card:hover {
  text-decoration: none;
  border-color: var(--accent);
  transform: translateY(-2px);
}
.post-tag {
  display: block;
  margin: -1.5rem -1.6rem 1.1rem;
  padding: 0.7rem 1.6rem 0.55rem;
  background: rgba(13, 82, 87, 0.055);
  border-bottom: 1px solid rgba(13, 82, 87, 0.18);
  font-size: 0.8125rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}

.post-date {
  font-size: 0.8rem;
  color: var(--ink-3);
  margin-bottom: 1.25rem;
}
.post-card h3 {
  margin: 0.9rem 0 0.75rem;
  font-size: 1.25rem;
  line-height: 1.25;
  letter-spacing: -0.025em;
}
.post-card p {
  font-size: 1.125rem;
  color: var(--ink-2);
  margin-bottom: 0.75rem;
}
.post-card .textlink { margin-top: auto; color: var(--accent); }

.insights-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.75rem;
  margin-top: clamp(2rem, 4vw, 2.75rem);
}

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */
.contact h2 {
    font-size: clamp(2rem, 3.6vw, 3.25rem);
  line-height: 1.05;
  max-width: 20ch;
}
.contact .standfirst {
  margin-top: 1.5rem;
  max-width: 56ch;
  font-family: var(--serif);
  font-size: 1.5rem;
  color: var(--dark-ink-2);
  line-height: 1.55;
}
.contact-note {
  margin-top: 1.5rem;
  max-width: 52ch;
  font-size: 1.125rem;
  color: var(--dark-ink-2);
}

.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  align-items: center;
  margin-top: clamp(2rem, 4vw, 2.75rem);
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--paper);
  border-top: 1px solid var(--rule);
  padding: clamp(3rem, 6vw, 4.5rem) 0 2.5rem;
  font-size: 1rem;
  color: var(--ink-2);
}

.footer-top {
  display: grid;
  grid-template-columns: 1.2fr 1fr 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
}
@media (max-width: 780px) {
  .footer-top { grid-template-columns: 1fr 1fr; }
  .footer-brand-col { grid-column: 1 / -1; }
}

.footer-brand-col p { max-width: 34ch; margin-top: 1rem; }

.footer-col h3 {
  font-size: 0.8125rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 1.1rem;
  font-weight: 600;
}
.footer-col a {
  display: block;
  color: var(--ink-2);
  padding: 0.3rem 0;
}
.footer-col a:hover { color: var(--accent); }

.footer-social {
  display: flex;
  gap: 1.25rem;
  margin-top: 1.5rem;
}
.footer-social a { color: var(--ink-3); }
.footer-social a:hover { color: var(--accent); }

.footer-bottom {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  justify-content: space-between;
  font-size: 0.85rem;
  color: var(--ink-3);
}

/* --------------------------------------------------------------------------
   Subpages — company, insights index, articles
   -------------------------------------------------------------------------- */
.page-head {
  padding: clamp(3.5rem, 7vw, 6rem) 0 clamp(2rem, 4vw, 3rem);
  position: relative;
  overflow: hidden;
}
.page-head .wrap { position: relative; z-index: 1; }
.page-head h1 {
  font-size: clamp(2.25rem, 5.4vw, 3.9rem);
  line-height: 1.03;
  letter-spacing: -0.035em;
  max-width: 900px;
}
.page-head .lead {
  margin-top: 1.75rem;
  font-family: var(--serif);
  font-size: 1.5rem;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 900px;
}

.prose { max-width: 760px; }
.prose h2 {
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  margin: clamp(2.5rem, 5vw, 3.25rem) 0 1rem;
}
.prose h3 {
  font-size: 1.375rem;
  margin: 2rem 0 0.75rem;
}
.prose p, .prose li {
  color: var(--ink-2);
  font-size: 1.125rem;
  line-height: 1.7;
}

.values {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--rule-strong);
  border: 1px solid var(--rule-strong);
}
@media (max-width: 880px) { .values { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .values { grid-template-columns: 1fr; } }

.value {
  background: var(--paper);
  padding: clamp(1.5rem, 3vw, 2rem);
}
.section--alt .value { background: var(--paper); }
.value h3 {
  font-size: 1.1875rem;
  letter-spacing: -0.02em;
  margin-bottom: 0.65rem;
}
.value p { font-size: 1.125rem; color: var(--ink-2); }

.people {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(2rem, 5vw, 3.5rem);
}
@media (max-width: 840px) { .people { grid-template-columns: 1fr; } }

.person { border-top: 1px solid var(--rule-strong); padding-top: 2rem; }
.person-head {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin-bottom: 1.5rem;
}
.person-head img {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05);
}
.person-head h3 { font-size: 1.3rem; letter-spacing: -0.025em; }
.person-role {
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
  margin-top: 0.35rem;
}
.person p { font-size: 1.125rem; color: var(--ink-2); }
.person p.person-summary { color: var(--ink); }

/* Service pages — body copy with a narrow column beside it naming what the
   service is built on. */
.service-layout {
  display: grid;
  grid-template-columns: minmax(0, 760px) 280px;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 900px) {
  .service-layout { grid-template-columns: 1fr; }
}

.service-aside {
  border-top: 2px solid var(--teal-700);
  padding-top: 1.25rem;
}
/* The related-insights rail reuses the one the posts carry, pointing the other
   way. .rail-label draws its own teal rule, so where the rail follows the
   "Behind this service" block it needs the gap between two rails, and where it
   is the only thing in the column the aside drops its rule rather than doubling
   it. */
.service-aside .rail { margin-top: 2.5rem; }
.service-aside--rails {
  border-top: 0;
  padding-top: 0;
}
.service-aside--rails .rail { margin-top: 0; }
.aside-label {
  font-size: 0.8125rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  margin-bottom: 0.6rem;
}
.aside-name {
  font-size: 1.2rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-bottom: 0.6rem;
}
.service-aside p {
  font-size: 1.0625rem;
  line-height: 1.55;
  color: var(--ink-2);
}
.service-aside .textlink { margin-top: 0.4rem; }

/* A line worth stopping on, lifted out of the prose. */
.article-pull {
  margin: 2.25rem 0;
  padding-left: clamp(1.1rem, 2.5vw, 1.75rem);
  border-left: 3px solid var(--teal-700);
  font-family: var(--serif);
  font-size: clamp(1.35rem, 2.7vw, 1.9rem);
  line-height: 1.4;
  color: var(--ink);
}

.article ul {
  margin: 0 0 1.5rem;
  padding-left: 1.1rem;
}
.article li { margin-bottom: 0.6rem; }
.article li strong { color: var(--ink); }

/* Tables inside an article. The site had none until the methodology page: this
   is the first thing that needed one, so it follows the page's own habits —
   hairlines and a muted header rather than a boxed grid, and no zebra fill.
   Wide ones scroll inside their own frame like .figure does, rather than
   squashing the type or wrapping every cell to one word per line. */
.table-scroll {
  margin: 2rem 0;
  overflow-x: auto;
}
.article table {
  width: 100%;
  border-collapse: collapse;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink-2);
}
.article th,
.article td {
  padding: 0.9rem 1.5rem 0.9rem 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--rule);
}
.article th:last-child,
.article td:last-child { padding-right: 0; }
.article thead th {
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 1px solid var(--rule-strong);
}
.article tbody th { color: var(--ink); font-weight: 600; }
/* The five-column table. Below this the columns stop being readable, so the
   frame scrolls instead. Kept under the 900px article so it only scrolls where
   it has to — on a phone, not on a desktop. */
.table-scroll--wide table { min-width: 54rem; }

/* Fine print at the foot of an article — when it was last checked, not who
   wrote it. */
.article-note {
  margin-top: clamp(2rem, 4vw, 2.5rem);
  font-size: 0.8125rem;
  color: var(--ink-3);
}

/* Diagrams inside articles — flat, teal on white, no shadows. Wide ones
   scroll inside their own frame rather than squashing the type. */
.figure {
  margin: 2rem 0;
  border: 1px solid var(--rule-strong);
  background: #fff;
  padding: 1.25rem;
  overflow-x: auto;
}
.figure svg {
  display: block;
  min-width: 500px;
  width: 100%;
  height: auto;
}
.figure figcaption {
  margin-top: 1rem;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--ink-3);
}

.dg-box { fill: #fff; stroke: var(--teal-700); stroke-width: 1.5; }
.dg-box--soft { stroke-dasharray: 5 4; }
.dg-solid { fill: var(--teal-700); }
.dg-ink { fill: var(--ink); }
.dg-line { stroke: var(--rule-strong); stroke-width: 1.5; fill: none; }
.dg-label { font-size: 13px; font-weight: 500; fill: var(--ink); }
.dg-label--sm { font-size: 12px; }
.dg-label--on { fill: #fff; }
.dg-sub { font-size: 11px; fill: var(--ink-3); }
.dg-sub--on { fill: rgba(255, 255, 255, 0.85); }
.dg-key { font-size: 11px; fill: var(--ink-2); }

/* An ordinal ramp for a stacked share bar. The palette has no blue and no
   three-step scale, so the steps are one hue — the brand teal — mixed down
   towards the white the figures sit on: 100%, 70%, 45%. Lightness is monotone
   (0.07 / 0.21 / 0.41 relative), and the lightest step is 2.29:1 against that
   surface, so the largest share still reads as a shape and not as a gap. */
.dg-tier-1 { fill: var(--teal-700); }
.dg-tier-2 { fill: color-mix(in srgb, var(--teal-700) 70%, #fff); }
.dg-tier-3 { fill: color-mix(in srgb, var(--teal-700) 45%, #fff); }
/* A category the ordinal scale does not apply to — organisations not using AI
   at all. Outlined rather than filled: a pale fill would read as another step
   on the ramp and would have to clear the same contrast bar to do it. */
.dg-tier-out { fill: none; stroke: var(--rule-strong); stroke-width: 1.5; }

/* A figure that needs to say what the reader is looking at before they look at
   it. The diagrams so far were self-evident enough to go straight to the
   caption; a chart of shares is not. */
.article .fig-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 0.25rem;
}
.article .fig-sub {
  font-size: 0.8125rem;
  color: var(--ink-2);
  margin: 0 0 1.25rem;
}

/* Two columns of a ledger, split by the line nobody's budget crosses. */
.ledger { margin: 0; }
.article .led-head {
  margin: 0 0 0.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.article .led-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.article .led-list li {
  margin: 0;
  padding: 0.5rem 0;
  font-size: 1rem;
  line-height: 1.5;
  border-bottom: 1px solid var(--rule);
}
.article .led-list li:last-child { border-bottom: 0; }
.led-note { color: var(--ink-3); font-size: 0.8125rem; }
.budget-line {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0;
}
.budget-line::before,
.budget-line::after {
  content: "";
  flex: 1;
  border-top: 2px dashed var(--rule-strong);
}
.budget-line span {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}

/* Three verdicts, side by side. The colour is the third signal, after the icon
   and the label — the palette has no status scale, so back/fix/stop take teal,
   the flame accent and ink, which are three values a reader can tell apart
   without being asked to know what any of them means. */
.verdicts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
}
.verdict {
  padding: 0.85rem 0.9rem 1rem;
  border: 1px solid var(--rule);
  border-top: 4px solid var(--rule-strong);
}
.verdict--back { border-top-color: var(--teal-700); }
.verdict--fix { border-top-color: var(--flame-500); }
.verdict--stop { border-top-color: var(--ink); }
.article .verdict-head {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0 0 0.35rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--ink);
}
.article .verdict-body {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ink-2);
}
@media (max-width: 560px) {
  .verdicts { grid-template-columns: 1fr; }
}

/* Migrated posts: body copy with a rail beside it — the series it belongs to,
   and the services it relates to. */
.post-layout {
  display: grid;
  grid-template-columns: minmax(0, 900px) 280px;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
/* A grid item's automatic minimum is its min-content width, and a <video> with
   width:100% contributes its intrinsic width to that — percentages are treated
   as auto when sizing intrinsically. The demo videos are 1600 and 1920 wide, so
   the column could not shrink below them and the whole page laid out that wide
   on a phone: headings and body text wrapped to 1600px, not to the screen. */
.post-layout > * { min-width: 0; }
@media (max-width: 1000px) {
  .post-layout { grid-template-columns: 1fr; }
}

.post-rails { position: sticky; top: 7rem; }
.rail + .rail { margin-top: 2.5rem; }
.rail-label {
  font-size: 0.8125rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  border-top: 2px solid var(--teal-700);
  padding-top: 1rem;
  margin-bottom: 1rem;
}
.rail-list { list-style: none; margin: 0; padding: 0; }
.rail-list li {
  margin: 0;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: 1rem;
  line-height: 1.45;
}
.rail-list a { color: var(--ink); }
.rail-list a:hover { color: var(--accent); }
.rail-here span {
  color: var(--ink);
  font-weight: 600;
  border-left: 3px solid var(--flame-500);
  padding-left: 0.6rem;
  margin-left: -0.75rem;
  display: block;
}
.rail-coming span { color: var(--ink-3); }
.rail-coming em {
  font-style: normal;
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.rail-list--plain a { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--accent); }

/* Byline with the author's face, on every post. */
.post-byline {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-bottom: 1.75rem;
}
/* Scoped past .article img, which sets every image in a post to full width. */
.article .post-byline img,
.post-byline img {
  flex: none;
  width: 44px;
  height: 44px;
  margin: 0;
  border: 0;
  border-radius: 50%;
  object-fit: cover;
  filter: grayscale(1);
}
.post-byline-name { display: block; font-weight: 600; color: var(--ink); }
.post-byline-facts {
  display: block;
  font-size: 0.9375rem;
  color: var(--ink-3);
}

/* A captured walkthrough: numbered steps, each with the screenshot that
   produced it. Replaces the source site's D3 lightbox with plain markup. */
.walkthrough {
  list-style: none;
  margin: 2rem 0;
  padding: 0;
  counter-reset: none;
}
.walkthrough > li + li {
  margin-top: 2.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--rule);
}
.walkthrough-step {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  margin: 0 0 0.4rem;
  font-weight: 600;
  color: var(--ink);
}
.walkthrough-step span {
  font-size: 0.8125rem;
  letter-spacing: 0.12em;
  color: var(--teal-700);
}
.walkthrough > li > p + p {
  margin: 0;
  color: var(--ink-2);
}

/* Numbered build steps inside an article. */
.article ol.steps {
  margin: 1.75rem 0;
  padding-left: 1.4rem;
}
.article ol.steps > li + li { margin-top: 0.7rem; }

/* One video, several languages. Without JS the first language still plays and
   the download links below it reach the rest. */
.lang-player { margin: 2rem 0; }
.lang-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.9rem;
}
.lang-tab {
  padding: 0.5rem 1rem;
  font: inherit;
  font-size: 0.9375rem;
  color: var(--ink-3);
  background: transparent;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  cursor: pointer;
}
.lang-tab:hover { color: var(--ink); }
.lang-tab[aria-selected="true"] {
  color: var(--teal-700);
  border-color: var(--teal-700);
  background: rgba(13, 82, 87, 0.06);
}
.lang-player video { margin: 0; }

/* Reference links in the technical posts are bare URLs over 100 characters,
   used as their own link text. break-word will not split them, because they
   contain no break opportunity; anywhere will. */
.article a,
.article code,
.rail-list a {
  overflow-wrap: anywhere;
}

/* Code, which the site had no styles for until posts arrived with it. */
.article pre {
  margin: 1.75rem 0;
  padding: 1.25rem 1.4rem;
  background: var(--dark);
  color: var(--dark-ink);
  overflow-x: auto;
  font-size: 0.9375rem;
  line-height: 1.6;
  border-left: 3px solid var(--teal-700);
}
.article pre code { background: none; padding: 0; color: inherit; font-size: inherit; }
.article code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
  background: rgba(13, 82, 87, 0.07);
  padding: 0.12em 0.4em;
  border-radius: 2px;
}
.article img, .article video {
  width: 100%;
  max-width: 100%;
  height: auto;
  margin: 1.75rem 0;
  border: 1px solid var(--rule-strong);
}

/* Callouts, which the site had no styles for either, so they were arriving as
   bare indented text. The posts use a blockquote for two different jobs and
   they read differently, so they get two treatments.

   A top-level one is an aside in our own voice, the NOTE: convention and the
   source-code line, and it takes the same teal left rule a code block does,
   because it is the same gesture of setting something apart from the argument.

   A nested one is somebody else's words, in practice a quotation from AWS's
   documentation inside one of our notes. It drops the rule and the fill and
   goes to the serif the site already uses for pull-quotes, so a reader can see
   at a glance that the voice changed. */
.article blockquote {
  margin: 1.75rem 0;
  padding: 1rem 1.4rem;
  background: var(--paper-warm);
  border-left: 3px solid var(--teal-700);
}
.article blockquote > p { margin: 0; }
.article blockquote > p + p { margin-top: 0.75rem; }
.article blockquote blockquote {
  margin: 0.9rem 0 0;
  padding: 0 0 0 1.15rem;
  background: none;
  border-left: 1px solid var(--rule-strong);
}
.article blockquote blockquote p {
  font-family: var(--serif);
  color: var(--ink-3);
}

/* Article */
/* Left-aligned like the rest of the page, but wider than the 760px used on
   service pages — a post is the one place the reader stays for a while. */
.article { max-width: 900px; }
.article-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.25rem;
  align-items: center;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-bottom: 1.5rem;
  margin-bottom: clamp(2rem, 4vw, 2.75rem);
  border-bottom: 1px solid var(--rule);
}
.article h1 {
  font-size: clamp(2rem, 3.6vw, 3.25rem);
  line-height: 1.06;
  letter-spacing: -0.035em;
  margin-bottom: 1.75rem;
}
.article .lead {
  font-family: var(--serif);
  font-size: 1.5rem;
  line-height: 1.55;
  color: var(--ink-2);
  margin-bottom: 2rem;
}
.article h2 {
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  margin: clamp(2.5rem, 5vw, 3rem) 0 1rem;
}
/* An appendix is a reference block, not the next move in the argument. The
   markdown separated it with a rule; the page separates it with space instead,
   at the interval .article-cta already uses to break off from the body — its
   margin and padding added together, without the hairline. */
.article h2.appendix { margin-top: clamp(4.5rem, 9vw, 5.75rem); }
.article p, .article li { font-size: 1.125rem; line-height: 1.7; color: var(--ink-2); }

.article-cta {
  margin-top: clamp(2.5rem, 5vw, 3.25rem);
  padding-top: clamp(2rem, 4vw, 2.5rem);
  border-top: 1px solid var(--rule);
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 2rem;
  font-weight: 500;
}
.back-link:hover { color: var(--accent); text-decoration: none; }

/* --------------------------------------------------------------------------
   Case-study posts
   The engagement write-ups needed components the site had no styles for: the
   definition panel, a callout that is a line worth stopping on rather than a
   NOTE: aside, the tick rule as a section break, and the three beats of the
   AI-first loop as repeating labels. Teal and the hairlines are the site's
   own; nothing here introduces a colour.
   -------------------------------------------------------------------------- */

/* A definition panel, not a data table: the first column is the term and the
   second is what it means, so a header row would say nothing and is left out.
   The rows keep the article's hairlines and take a heavier rule at the top,
   which is what makes four rows read as one block. */
.article table.deflist { margin: 1.5rem 0 2rem; }
.article table.deflist td { padding: 0.9rem 0; }
.article table.deflist td:first-child {
  width: 10rem;
  padding-right: 1.15rem;
  color: var(--ink);
  font-weight: 600;
  /* The label is the term being defined, so it reads as one thing or not at
     all. Auto table layout widens the column to fit rather than clipping. */
  white-space: nowrap;
}
.article table.deflist tr:first-child td { border-top: 1px solid var(--rule-strong); }
/* On a phone a term that will not wrap leaves the definition one word wide, so
   below this the labels wrap and the column stops holding a fixed width. */
@media (max-width: 560px) {
  .article table.deflist td:first-child { width: 7.5rem; white-space: normal; }
}

/* The same rows, boxed — a white panel with the teal edge the site already
   uses to set something apart from the argument. The panel draws the outer
   rules, so the first and last rows drop theirs. */
.panel {
  background: #fff;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--teal-700);
  padding: 0.25rem 1.5rem;
  margin: 1.5rem 0 2rem;
}
.article .panel table.deflist { margin: 0; }
.article .panel table.deflist tr:first-child td { border-top: 0; }
.article .panel table.deflist tr:last-child td { border-bottom: 0; }

/* A callout carries a line from the argument rather than an aside beside it,
   so it takes the panel's white fill and border instead of the warm block
   .article blockquote gives a NOTE:. The bold lead-in goes teal — it is a
   label on the callout, not emphasis inside it. */
.article blockquote.callout {
  background: #fff;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--teal-700);
  padding: 0.9rem 1.4rem;
  margin: 2rem 0;
}
.article blockquote.callout > p {
  font-size: 1.1875rem;
  line-height: 1.55;
  color: var(--ink);
}
.article blockquote.callout strong { color: var(--accent); }

/* The instrument motif as a section break: finer and teal, where .ticks is a
   full-bleed band in the rule colour. */
.article hr.tickrule {
  border: 0;
  height: 9px;
  margin: clamp(2.5rem, 5vw, 3rem) 0 1.75rem;
  background: repeating-linear-gradient(90deg, var(--teal-700) 0 1.5px, transparent 1.5px 9px);
  opacity: 0.85;
}

/* The three beats of the loop repeat once per phase, so they read as labels
   rather than as the next move in the argument: the eyebrow treatment, with
   the icon that tells the beats apart without reading them. */
.article h3.beat {
  display: flex;
  align-items: center;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 2rem 0 0.5rem;
}
.h3i { width: 15px; height: 15px; flex: none; margin-right: 8px; }

/* Diagrams that paint their own paper ground and carry their own labels, so
   they take neither the frame nor the caption .figure gives a chart. Narrow
   screens scroll them rather than shrinking the type past reading.

   The margin matches .article img rather than the 2rem a framed .figure takes:
   a diagram cropped to its artwork has no border to hold it off the text, so
   the gap here is the whole gap, and 2rem read as a break in the run. */
.diagram { margin: 1.75rem 0; overflow-x: auto; }
.diagram svg { display: block; width: 100%; height: auto; min-width: 30rem; }

/* The phase strip belongs to the "Phase one" heading that follows it — it is
   the contents page for the three sections, not a figure in its own right, so
   it sits tight above the first one. */
.diagram--strip { margin: 1.625rem 0 0.375rem; }

/* A phase reads as a flow diagram held beside its own prose: the diagram stays
   put while the three beats scroll past it, so the reader can see which beat
   they are in without scrolling back. The H2 stays full width above the grid;
   the grid runs to the next H2.

   The left column is 200px because that is the width the flow SVGs were drawn
   at — scaling them up would only enlarge 8px lane labels past the size they
   were spaced for. */
.phase {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: 1.875rem;
  align-items: start;
  margin: 0.5rem 0 0;
}
/* 7rem matches .post-rails rather than the reference's 24px: this page has a
   sticky header, and 24px would park the diagram underneath it. */
.phase-flow { position: sticky; top: 7rem; }
.phase-flow svg { display: block; width: 100%; height: auto; }
/* The beat labels are the top of the column, so the first one loses the space
   it would otherwise hold off the paragraph above it. */
.article .phase-body > h3.beat:first-child { margin-top: 0.125rem; }
/* A narrower measure takes a smaller size, at the same step down the reference
   uses. The callout keeps a size above the body text around it. */
.article .phase-body p,
.article .phase-body li { font-size: 1.0625rem; }
.article .phase-body blockquote.callout > p { font-size: 1.125rem; }

/* One column below this: the flow first, capped so it does not stretch to a
   width its type was never drawn for, and released from sticky — there is no
   second column left for it to stay beside. */
@media (max-width: 760px) {
  .phase { grid-template-columns: minmax(0, 1fr); gap: 0.5rem; }
  .phase-flow { position: static; max-width: 240px; }
}

/* Bold in the body is ink at 600, not the browser's 700 — the variable face
   has the weight, and 700 alongside 600 headings reads as a different family.
   Scoped past the teal lead-in a callout gives its first few words. */
.article p strong,
.article .phase-body strong { font-weight: 600; color: var(--ink); }

.article--case li::marker { color: var(--accent); }

/* --------------------------------------------------------------------------
   Reveal on scroll — restrained
   -------------------------------------------------------------------------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
}
[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
}

/* No-JS safety: never hide content if the observer never runs. */
.no-js [data-reveal] { opacity: 1; transform: none; }
.no-js .gauge-fill { width: var(--value); }
