/* Caladea (Apache 2.0, Huerta Tipografica) and Carlito (SIL OFL 1.1, Lukasz
   Dziedzic). Metric-compatible substitutes for Cambria and Calibri. Self-hosted:
   no third-party request, no cookie, no consent banner.

   Generated by tools/fetch-fonts.py. Do not hand-edit. */

@font-face {
  font-family: 'Caladea';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/caladea-400-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Caladea';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/caladea-400-italic-latin.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: 'Caladea';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/caladea-700-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Caladea';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/caladea-700-italic-latin.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: 'Caladea';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/caladea-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Caladea';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/caladea-400-latin.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: 'Caladea';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/caladea-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Caladea';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/caladea-700-latin.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: 'Carlito';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/carlito-400-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Carlito';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/carlito-400-italic-latin.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: 'Carlito';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/carlito-700-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Carlito';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/carlito-700-italic-latin.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: 'Carlito';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/carlito-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Carlito';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/carlito-400-latin.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: 'Carlito';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/carlito-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Carlito';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/carlito-700-latin.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;
}

/* ==========================================================================
   koppel-consulting.com
   Colours are the sampled logo palette in design-tokens.md and nothing else.
   Separation is a hairline, never a card with a radius and a shadow.
   ========================================================================== */

:root {
  /* Colour: verbatim from design-tokens.md. Do not add to this set. */
  --ink: #010D25;
  --paper: #FFFFFF;
  --cream: #F0E3D4;
  --copper-light: #C67D50;   /* accent on dark only */
  --copper-deep: #A85428;    /* accent on light only */
  --slate: #474D57;
  --muted: #878E99;
  --rule: #D6D9DE;
  --rule-dark: #2A3448;
  --dim-text: #A9B0BC;
  --tint-light: #EFF1F5;
  --tint-mid: #E1E5EC;
  /* Linen. The one ground that is not in design-tokens.md, added because the
     cool tints fight the copper and fail AA behind it. See DECISIONS.md 16. */
  --canvas: #F4EEE4;

  /* --muted is 3.3:1 on paper and fails AA for text. Per the brief, darken
     rather than shrink: captions and sources use --slate (8.4:1). --muted is
     kept for non-text use only. */
  --caption: var(--slate);

  --serif: 'Caladea', Cambria, Georgia, 'Times New Roman', serif;
  --sans: 'Carlito', Calibri, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;

  /* Layout rhythm: 0.6in margin of a 13.333in slide is 4.5%. */
  --gutter: 4.5vw;
  --measure: 1420px;

  --step: clamp(4.5rem, 8.5vw, 9.5rem);  /* vertical section rhythm */
  --hair: 1px;
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--slate);
  font-family: var(--sans);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block; }
ul, ol { margin: 0; padding: 0; list-style: none; }
p { margin: 0; }
h1, h2, h3 { margin: 0; font-weight: 700; font-family: var(--serif); line-height: 1.1; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--copper-deep);
  outline-offset: 3px;
}
.plate :focus-visible,
.contact :focus-visible,
.footer :focus-visible,
.nav :focus-visible {
  outline-color: var(--copper-light);
}

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

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

/* --------------------------------------------------------------- layout -- */

.wrap {
  width: min(100% - 2 * var(--gutter), var(--measure));
  margin-inline: auto;
}
/* A narrow column stays flush with the left edge of the wide grid rather than
   centring on its own, so section starts line up down the page. */
.wrap--narrow > * { max-width: 780px; }

/* The ground is ink on <body> so the filament field can show through. Every
   paper section therefore has to paint itself, or it inherits the ink. */
.section { padding-block: var(--step); background: var(--paper); }
.section--tint { background: var(--tint-light); }
.section + .section:not(.section--tint) { padding-top: 0; }
.section--tint + .section { padding-top: var(--step); }

/* ----------------------------------------------------------- typography -- */

.eyebrow {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--copper-deep);
  line-height: 1.4;
  margin-bottom: 1.35rem;
}
.eyebrow--dark { color: var(--copper-light); }
.eyebrow--sm { font-size: 0.6875rem; margin-bottom: 0.9rem; }

/* The opening label carries two things: what kind of practice this is, and
   what it does. Wide, that is one line with a middot between them. Narrow, the
   whole line is 443 pixels in a column of 327 and the browser breaks it
   wherever it runs out, which put "Strategy and" on the first line and left
   the label reading as a sentence cut in half. Stacked at the seam instead,
   with the middot gone, because a separator between two lines is a mark
   waiting to be misread as a bullet. */
.eyebrow__field::before { content: "\00a0\00a0\00b7\00a0\00a0"; }
@media (max-width: 56rem) {
  .eyebrow--pair .eyebrow__kind { display: block; }
  .eyebrow--pair .eyebrow__field::before { content: none; }
}

.headline {
  font-size: clamp(1.75rem, 1.15rem + 2.5vw, 3rem);
  color: var(--ink);
  max-width: 23ch;
  text-wrap: balance;
}
.headline--sm { font-size: clamp(1.4rem, 1.05rem + 1.5vw, 2.05rem); max-width: 26ch; }

.standfirst {
  margin-top: 1.9rem;
  max-width: 62ch;
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.3rem);
  color: var(--slate);
}

.body { max-width: 62ch; }
/* Two paragraphs of body copy in a row had nothing between them and read as one
   block. Every other section on the site sets one paragraph against something
   else, so this had never come up until the closing note ran to three. */
.body + .body { margin-top: 1.25rem; }
.headline + .body, .headline + .ticks { margin-top: 1.5rem; }
.body--wide { max-width: 74ch; margin-top: 2rem; }
.more { margin-top: 1.5rem; }
.body--lead { margin-top: 1.5rem; font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem); }

/* takeaway: the "closer" that sits under a hairline at the foot of a section */
.closer {
  margin-top: var(--step);
  padding-top: 2.1rem;
  /* the takeaway earns a full-strength rule, not an incidental one */
  border-top: var(--hair) solid var(--ink);
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.125rem, 1rem + 0.7vw, 1.45rem);
  line-height: 1.35;
  color: var(--ink);
  max-width: 46ch;
  text-wrap: balance;
}

.source {
  margin-top: 1.4rem;
  font-size: 0.875rem;
  font-style: italic;
  line-height: 1.55;
  color: var(--caption);
  max-width: 88ch;
}

.link {
  font-weight: 700;
  color: var(--copper-deep);
  text-decoration: none;
  border-bottom: var(--hair) solid var(--copper-deep);
  padding-bottom: 2px;
}
.link:hover { color: var(--ink); border-color: var(--ink); }

.btn {
  display: inline-block;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.95rem 1.9rem;
  color: var(--ink);
  background: var(--cream);
  border: var(--hair) solid var(--cream);
  transition: background 160ms ease, color 160ms ease;
}
.btn:hover { background: transparent; color: var(--cream); }

/* Open decisions are rendered, not hidden. build.py --check lists them. */
.todo {
  margin-block: 1.5rem;
  padding: 0.9rem 1.1rem;
  border-left: 3px solid var(--copper-deep);
  background: var(--tint-light);
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--ink);
  max-width: 78ch;
}
.todo--dark {
  background: transparent;
  border-left-color: var(--copper-light);
  color: var(--dim-text);
}
.todo--inline {
  display: inline;
  padding: 0.1rem 0.4rem;
  margin: 0;
  border-left: 2px solid var(--copper-light);
  background: transparent;
  color: var(--dim-text);
  font-size: inherit;
}

/* ------------------------------------------------------ numbered columns -- */

.cols {
  display: grid;
  gap: 3.5rem 3rem;
  margin-top: 4.25rem;
}
.cols--2 { grid-template-columns: repeat(2, 1fr); }
.cols--3 { grid-template-columns: repeat(3, 1fr); }
.cols--4 { grid-template-columns: repeat(4, 1fr); }

.col { position: relative; padding-top: 1.5rem; border-top: var(--hair) solid var(--ink); }
.col--emphasis { border-top-width: 2px; border-top-color: var(--copper-deep); }

/* the short vertical tick above the rule */
.col::before {
  content: "";
  position: absolute;
  top: -9px; left: 0;
  width: var(--hair); height: 9px;
  background: var(--ink);
}
.col--emphasis::before { background: var(--copper-deep); width: 2px; }

.col__n {
  display: block;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--copper-deep);
  margin-bottom: 0.6rem;
}
.col__label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--slate);
  margin-bottom: 0.5rem;
}
.col__title {
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.2rem);
  line-height: 1.32;
  color: var(--ink);
  margin-bottom: 0.95rem;
  text-wrap: balance;
}
.col__title--lg { font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.6rem); }
.col__body { font-size: 0.9375rem; line-height: 1.6; }
.col__outcome {
  margin-top: 1.25rem;
  padding-top: 0.95rem;
  border-top: var(--hair) solid var(--rule);
  font-family: var(--serif);
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--ink);
}

.ticks { margin-top: 0.25rem; }
.ticks li {
  position: relative;
  padding-left: 1.1rem;
  margin-bottom: 0.7rem;
  font-size: 0.9375rem;
  line-height: 1.55;
}
.ticks li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 0.5rem; height: var(--hair);
  background: var(--copper-deep);
}

/* -------------------------------------------------------------- the nav -- */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--ink);
  border-bottom: var(--hair) solid var(--rule-dark);
}
.nav__inner {
  width: min(100% - 2 * var(--gutter), var(--measure));
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 4.25rem;
}
.nav__brand { display: flex; align-items: center; gap: 0.85rem; text-decoration: none; }
.nav__mark { width: auto; height: 1.75rem; }
.nav__names { display: flex; flex-direction: column; line-height: 1.15; }
.nav__person {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 1rem;
  color: var(--cream);
}
.nav__entity {
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--copper-light);
}
.nav__links { display: flex; align-items: center; gap: 1.75rem; }
.nav__link {
  font-size: 0.875rem;
  text-decoration: none;
  color: var(--dim-text);
  padding-block: 0.4rem;
  border-bottom: var(--hair) solid transparent;
  white-space: nowrap;
}
.nav__link:hover { color: var(--cream); border-bottom-color: var(--copper-light); }

/* The language switch is a control, not a place. The bar already says which
   page you are on, in cream with a hairline under it, and that is the one
   persistent highlight it can carry. So this does not compete for that
   reading: the language you are in is dimmed and is not a link, because there
   is nothing to do there, and the one you can move to takes the weight. */
.nav__lang {
  display: flex;
  align-items: center;
  margin: 0 0 0 1.75rem;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
}
.nav__lang > * { padding: 0 0.55rem; }
.nav__lang > * + * { border-left: var(--hair) solid var(--rule-dark); }
.nav__lang > :last-child { padding-right: 0; }
/* Lit is where you are, the same as the page links beside it. The first
   version marked the language you could move to instead, on the reasoning
   that a control should show the action; consistency inside one bar beats
   that argument, because a reader learns one rule for the bar, not two. */
.nav__lang span { color: var(--cream); }
.nav__lang a { color: var(--dim-text); text-decoration: none; }
.nav__lang a:hover { color: var(--cream); }
/* Contact gets no mark of its own.

   It has now been tried bold and it has been tried copper, and both had the
   same fault from the reader's side: the bar carries one persistent highlight,
   and the only thing a persistent highlight can sensibly mean there is which
   page you are on. Anything else competing for that reading costs more than a
   call to action gains. Cream plus the hairline is the current page, and
   nothing else in the bar is allowed to say anything. */

/* ------------------------------------------------- plates: hero and band -- */

/* The photographic plate itself lives in motion.css as .plate__img, so it can
   be transformed. This is only the ground it sits on. */
.plate {
  position: relative;
  background-color: var(--ink);
  color: var(--dim-text);
}

.plate__credit {
  position: absolute;
  right: var(--gutter);
  bottom: 1.25rem;
  font-size: 0.6875rem;
  font-style: italic;
  color: var(--dim-text);
}

.hero { display: flex; align-items: center; min-height: clamp(30rem, 78vh, 50rem); }
.hero--sub { min-height: clamp(24rem, 58vh, 36rem); }
/* A standing photograph is given a column rather than cropped into a band, so
   the hero grows to have something to stand in. The type keeps the left edge
   it shares with every section below it. */
.hero--portrait { min-height: clamp(30rem, 80vh, 48rem); }
.hero__inner { padding-block: var(--step); max-width: 100%; }

.hero__headline {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  font-size: clamp(2rem, 1.1rem + 3.9vw, 4rem);
  line-height: 1.08;
  color: var(--cream);
  max-width: 17ch;
  text-wrap: balance;
}
.hero--sub .hero__headline { font-size: clamp(1.75rem, 1.1rem + 2.9vw, 3.1rem); max-width: 20ch; }

.hero__sub {
  margin-top: 1.9rem;
  max-width: 44ch;
  font-size: clamp(1.0625rem, 1rem + 0.45vw, 1.35rem);
  color: var(--dim-text);
}
.hero__cta { margin-top: 2.75rem; display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap; }
.hero__note { font-size: 0.875rem; color: var(--dim-text); }

.statement { display: flex; align-items: center; min-height: clamp(24rem, 62vh, 38rem); }
.statement__inner { padding-block: var(--step); }
.statement__text {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.75rem, 1.1rem + 2.9vw, 3.1rem);
  line-height: 1.12;
  color: var(--cream);
  max-width: 17ch;
  text-wrap: balance;
}
.statement__body {
  margin-top: 1.9rem;
  max-width: 46ch;
  color: var(--dim-text);
}

/* On a narrow screen the baked scrim no longer covers the column, so the
   type sits on solid ink and the photographic half becomes a band below. */
/* On a narrow screen the baked scrim no longer covers the column, so the type
   sits on solid ink and the photographic half becomes a band below it. The
   crop itself is in motion.css, on .plate__img. */
@media (max-width: 56rem) {
  /* The height of the band and the room reserved above it are one number, not
     two. They were two - a 34vh reservation against a band sized separately in
     motion.css - and the moment the band was reframed it grew past what had
     been kept clear and swallowed the subtitle on the about page. Anything the
     band's height is used for reads it from here. */
  .hero, .statement { --band: 440px; display: block; padding-bottom: calc(var(--band) + 1.25rem); }
  .plate__credit { bottom: calc(var(--band) + 0.75rem); }
}

/* Upright, the band is a fixed 440, which is the number its crop was worked
   out for. Turned on its side a phone is 375 tall and 440 is more than the
   whole screen, which put three screens of hero in front of the reader before
   a word of the argument. Landscape takes a share of the height instead.

   The frame is then wider than it is tall, and at that aspect cover shows the
   whole source including the scrim, which no crop can avoid: to cut the width
   away the band would have to be taller than the screen it is on. As a wide
   band with the building coming in from the right that reads as a composition,
   which is what it is on a desktop. It was only a seam in a tall narrow one. */
@media (max-width: 56rem) and (orientation: landscape) {
  .hero, .statement { --band: 46vh; }
}
/* On the standing hero the photograph owns the right of the frame, and the lit
   tower runs down the middle of it, so a credit set flush right in one line
   starts on the building and cannot be read. Sent to the left gutter it was
   legible but landed directly under the scroll cue, which is the one place in
   the frame already spoken for.

   It goes where the picture is actually black: the foreground silhouette down
   the right edge, which measures zero luminance from about 1155px across at
   this size. That band is 125px wide and the credit is 146px in one line, so
   it is set in two, right-aligned, with the name held together by hard spaces
   in the copy. The measure is the constraint here, not the taste. */
@media (min-width: 56rem) {
  .hero--portrait .plate__credit {
    right: 1.5rem;
    max-width: 6.6rem;
    text-align: right;
    line-height: 1.4;
  }
}

/* The standing hero keeps a band of its own. Its plate is a portrait frame
   with a crop reasoned separately in motion.css, so it does not want the
   440 the landscape plates take - but the reservation still has to be the
   same number as the band, which is what this sets. */
@media (max-width: 56rem) {
  .hero--portrait { --band: 44vh; }
}

/* Rules that line up across the columns.

   The hairline above a column's closing line is the top border of that line,
   so it sat wherever the body copy above it happened to stop. Two lines in one
   column and three in the next put the two rules at different heights, which
   in a layout built on hairlines reads as a mistake rather than as a
   difference in length.

   Subgrid hands each column the same four rows, so the closing line starts at
   the same place in all of them whatever the body did. The body row takes the
   slack. Row gap goes to zero because the parent's 3.5rem is the gap between
   stacked columns, not between the parts of one, and the parts already carry
   their own margins. Below 56rem the columns stack and there is nothing to
   line up, so none of this applies there. */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 56rem) {
    .cols--3:has(.col__outcome),
    .cols--2:has(.col__outcome) {
      grid-template-rows: auto auto 1fr auto;
      row-gap: 0;
    }
    .cols--3:has(.col__outcome) > .col,
    .cols--2:has(.col__outcome) > .col {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: span 4;
    }
  }
}

/* The one photograph of the man on the page that says what he does.

   Not given the treatment the paintings get: that mask is for a picture
   pretending to have been laid onto the page, and a portrait that dissolves at
   the edges reads as a memorial rather than as a person you could ring. It is
   a plain standing frame in the corner beside the headline, on the navy, where
   the grey wall behind him is close enough to the ground to sit on it.

   Held to the space the headline leaves: below 62rem the columns are already
   fighting for width and a portrait would take the last of it, so it goes. */
/* Anchored to the content, not to the section. The section's own padding is
   not the distance from its edge to the first line, so measuring from there
   put the frame most of a hundred pixels low and into the columns. */
.spine .wrap { position: relative; }
.portrait { display: none; }

@media (min-width: 62rem) {
  .portrait {
    display: block;
    position: absolute;
    right: 0;
    top: 0;
    width: clamp(150px, 13vw, 200px);
    margin: 0;
    /* A hairline in copper, held off the photograph so it reads as a frame
       rather than as an outline drawn on it. The only frame on the site, on
       the only photograph of a person. */
    padding: 0.6rem;
    border: var(--hair) solid var(--copper-light);
  }
  .portrait img { display: block; width: 100%; height: auto; }

  /* The headline gives up exactly the width the frame needs and no more: the
     frame's offset plus its own width plus air. A flat character count would
     have to assume the tightest case at every width. */
  .spine .headline { max-width: min(20ch, 100% - 27rem); }
}

/* Clear of the contents rail. The rail is fixed to the viewport at 56px with a
   box 199px across, so its left edge falls (255px minus the gutter) inside the
   text column: 178px at the width it first appears, less as the gutter grows.
   It only exists from 80rem, and neither does this. */
@media (min-width: 80rem) {
  .portrait { right: 12.5rem; }
}

/* ------------------------------------------------------------ the stats -- */

.split {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: 3.5rem 4.5rem;
  margin-top: 4.25rem;
  padding-top: 2.5rem;
  border-top: var(--hair) solid var(--ink);
}
.split--even { grid-template-columns: 1fr 1fr; }

.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2.5rem; margin: 0; }
.stat { border-top: var(--hair) solid var(--ink); padding-top: 1.35rem; }
.stat:last-child { border-top-color: var(--copper-deep); border-top-width: 2px; }
.stat__figure {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.9rem, 1.3rem + 2.2vw, 2.9rem);
  line-height: 1;
  color: var(--ink);
}
.stat:last-child .stat__figure { color: var(--copper-deep); }
.stat__line { margin: 0.85rem 0 0; font-size: 0.875rem; line-height: 1.5; }

.refused {
  margin-top: 3.5rem;
  padding: 2rem 0 0;
  border-top: 2px solid var(--copper-deep);
}
.refused__body { max-width: 78ch; font-size: 0.9375rem; color: var(--slate); }

/* ---------------------------------------------------------- 10/20/70 bar -- */

.bars { display: flex; margin-top: 4.25rem; gap: 2px; }
.bar { flex: var(--share) 1 0; min-width: 0; }
.bar__figure {
  display: block;
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.4rem, 1rem + 1.6vw, 2.4rem);
  line-height: 1;
  color: var(--ink);
  margin-bottom: 0.75rem;
}
.bar--emphasis .bar__figure { color: var(--copper-deep); }
.bar__track { display: block; height: 3.25rem; background: var(--tint-mid); }
.bar__fill {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--ink);
  transform-origin: left center;
}
.bar--emphasis .bar__fill { background: var(--copper-deep); }

/* The reveal for these bars lives in motion.css, gated on .kc-js, so a
   browser without script sees the finished 10/20/70 split. */

.bars__legend { margin-top: 3.25rem; }

/* --------------------------------------------------------- the matrix -- */

.matrix { margin-top: 4.25rem; }

.matrix__legend { display: flex; flex-wrap: wrap; gap: 2.25rem; margin-bottom: 2.75rem; }
.matrix__key {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.8125rem;
  color: var(--slate);
}

.cell { width: 0.85rem; height: 0.85rem; display: block; flex: none; }
.cell--person { background: var(--ink); }
.cell--machine { background: var(--copper-deep); }
.cell--bounded { background: transparent; box-shadow: inset 0 0 0 2px var(--copper-deep); }

.matrix__steps,
.state__cells {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 0.75rem;
}
.matrix__steps {
  margin-left: var(--matrix-gutter, 16rem);
  margin-bottom: 0.9rem;
}
.matrix__step {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--slate);
  text-align: center;
}

.state {
  display: grid;
  grid-template-columns: var(--matrix-gutter, 16rem) 1fr;
  align-items: start;
  gap: 0 0;
  padding-top: 1.5rem;
  border-top: var(--hair) solid var(--ink);
}
.state + .state { margin-top: 2.25rem; }
.state--emphasis { border-top-width: 2px; border-top-color: var(--copper-deep); }

.state__name {
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
  color: var(--ink);
  padding-right: 2rem;
}
.state--emphasis .state__name { color: var(--copper-deep); }
.state__sub {
  display: block;
  margin-top: 0.35rem;
  font-family: var(--sans);
  font-weight: 400;
  font-size: 0.875rem;
  color: var(--slate);
}
.state__cells { align-items: center; justify-items: center; padding-top: 0.3rem; }
.state__cells .cell { width: 1.1rem; height: 1.1rem; }
.state__body {
  grid-column: 2;
  margin-top: 1.9rem;
  font-size: 0.9375rem;
  line-height: 1.6;
  max-width: 72ch;
}

/* enhanced: one state at a time, stepped through by the visitor */
.matrix.is-enhanced .matrix__tabs {
  display: flex;
  gap: 0;
  margin-bottom: 2rem;
  border-bottom: var(--hair) solid var(--rule);
}
.matrix__tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 0.7rem 1.4rem 0.7rem 0;
  margin-right: 2rem;
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--slate);
  cursor: pointer;
}
.matrix__tab:hover { color: var(--ink); }
.matrix__tab[aria-selected="true"] { color: var(--copper-deep); border-bottom-color: var(--copper-deep); }
.matrix.is-enhanced .state[hidden] { display: none; }
.matrix.is-enhanced .state + .state { margin-top: 0; }

/* ------------------------------------------- the fourth outcome, fatigue -- */

.fourth, .fatigue {
  margin-top: 4rem;
  padding: 2.9rem 3rem;
  background: var(--ink);
  color: var(--dim-text);
}
.section--tint .fourth { margin-top: 3.5rem; }
.fourth__title, .fatigue__body {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.15rem, 1rem + 0.8vw, 1.5rem);
  line-height: 1.25;
  color: var(--cream);
  max-width: 34ch;
}
.fourth__body { margin-top: 1rem; max-width: 72ch; font-size: 0.9375rem; }
.fatigue__body { max-width: 72ch; }
.fatigue__note {
  margin-top: 1rem;
  max-width: 92ch;
  font-size: 0.9375rem;
  font-style: italic;
}

.pull {
  margin: 4.25rem 0 0;
  padding: 2.5rem 0 0;
  border-top: 2px solid var(--copper-deep);
}
.pull p {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.25rem, 1.05rem + 1.1vw, 1.85rem);
  line-height: 1.3;
  color: var(--ink);
  max-width: 40ch;
  text-wrap: balance;
}

.proved {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.125rem, 1rem + 0.7vw, 1.4rem);
  line-height: 1.35;
  color: var(--ink);
  max-width: 40ch;
}

.offers .offer { display: flex; flex-direction: column; }
.offer__terms {
  margin-top: 1.25rem;
  padding-top: 0.85rem;
  border-top: var(--hair) solid var(--rule);
  font-family: var(--serif);
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--ink);
}
.offer__link { margin-top: 1rem; font-size: 0.9375rem; }

.price { margin-top: 4rem; padding-top: 2rem; border-top: var(--hair) solid var(--ink); }

.clients { display: grid; grid-template-columns: repeat(2, 1fr); gap: 3.5rem; margin-top: 3.25rem; }
.clients__group { border-top: var(--hair) solid var(--ink); padding-top: 1.5rem; }
.clients__names {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.3rem);
  line-height: 1.5;
  color: var(--ink);
}

/* ------------------------------------------------------------- contact -- */

.contact { background: var(--ink); color: var(--dim-text); padding-block: var(--step); }
.contact__statement {
  font-size: clamp(1.75rem, 1.1rem + 2.9vw, 3.1rem);
  line-height: 1.1;
  color: var(--cream);
  max-width: 17ch;
  text-wrap: balance;
}
.contact__grid {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 3.5rem 4.5rem;
  margin-top: 4.25rem;
  padding-top: 2.75rem;
  border-top: var(--hair) solid var(--rule-dark);
}
.contact__body { max-width: 60ch; }
.contact__note {
  margin-top: 1.5rem;
  max-width: 60ch;
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.3rem);
  line-height: 1.35;
  color: var(--cream);
}
.contact__line {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.0625rem, 1rem + 0.6vw, 1.35rem);
  margin-bottom: 0.5rem;
}
.contact__line a { color: var(--cream); text-decoration: none; border-bottom: var(--hair) solid var(--copper-light); }
.contact__line a:hover { color: var(--copper-light); }
.contact__meta { margin-top: 1.5rem; font-size: 0.8125rem; color: var(--dim-text); }

/* -------------------------------------------------------------- footer -- */

.footer { background: var(--ink); color: var(--dim-text); padding-block: 4rem 2.5rem; border-top: var(--hair) solid var(--rule-dark); }
.contact + .footer { border-top-color: var(--rule-dark); }
.footer__top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 1.5rem 2.5rem; padding-bottom: 2.25rem; border-bottom: var(--hair) solid var(--rule-dark); }
.footer__lockup { width: auto; height: 2.75rem; }
.footer__line { font-size: 0.8125rem; }
.footer__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2.5rem; padding-block: 2.5rem; }
.footer__contact a, .footer__nav a { color: var(--cream); text-decoration: none; border-bottom: var(--hair) solid transparent; }
.footer__contact a:hover, .footer__nav a:hover { border-bottom-color: var(--copper-light); }
.footer__contact, .footer__meta, .footer__nav { font-size: 0.9375rem; line-height: 1.9; }
.footer__nav a { display: block; }
.footer__base {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  justify-content: space-between;
  padding-top: 1.75rem;
  border-top: var(--hair) solid var(--rule-dark);
  font-size: 0.75rem;
  font-style: italic;
}

/* ---------------------------------------------------------- responsive -- */

@media (max-width: 72rem) {
  .cols--4 { grid-template-columns: repeat(2, 1fr); }
  .matrix__steps { margin-left: 0; }
  .state { grid-template-columns: 1fr; }
  .state__name { padding-right: 0; margin-bottom: 1rem; }
  .state__body { grid-column: 1; }
}

@media (max-width: 56rem) {
  :root { --gutter: 6vw; }
  .cols--3, .cols--2 { grid-template-columns: 1fr; }
  .split, .split--even, .contact__grid { grid-template-columns: 1fr; }
  .stats { grid-template-columns: 1fr; gap: 1.25rem; }
  .clients { grid-template-columns: 1fr; }
  .footer__grid { grid-template-columns: 1fr; gap: 2rem; }
  .nav__names { display: none; }
  .nav__links { gap: 1.15rem; }
  .nav__link { font-size: 0.8125rem; }
  /* On a phone the bar has no room to say both which language you are in and
     which you could move to. The one you are in is already the page you are
     reading, so what is left is the one thing there is to do. This was pushing
     the whole bar past the edge of the screen and giving the site a sideways
     scroll it had no business having. */
  /* The bar carries a mark, four links and a language switch, and on a phone
     that is 343 pixels of content in 327 of room. Everything below is the
     margin taken back; measured, 375 fits with twelve to spare and 320 cannot
     fit at all, which is what the wrap rule further down is for. */
  .nav__links { gap: 0.85rem; }
  .nav__lang { margin-left: 0.35rem; }
  .nav__lang > * + * { border-left: 0; }
  .nav__lang > * { padding-inline: 0.22rem; }

  /* A finger is not a cursor. The bar's links were 35px tall and the language
     switch 21 by 20, against the 44 a thumb needs to hit reliably. The type
     stays the size it was; what grows is the area around it, which costs
     nothing visually and is the difference between tapping and aiming. */
  .nav__link { padding-block: 0.75rem; }
  .nav__lang > * { padding: 0.75rem 0 0.75rem 0.5rem; }
  .nav__inner { align-items: center; }
  .bars { gap: 1px; }
  .bar__figure { font-size: 1.15rem; }
}

/* Narrower than any arrangement of one row can hold. The links take a line of
   their own rather than being squeezed past legibility or pushed off the edge,
   which is what they were doing. */
@media (max-width: 23rem) {
  .nav__inner { flex-wrap: wrap; row-gap: 0.2rem; }
  .nav__links { order: 3; width: 100%; justify-content: flex-start; }
  .nav__lang { margin-left: auto; }
}

/* ------------------------------------------------ the narrow interface -- */

/* Two changes, and one rule behind both of them.

   A hairline in this system carries structure, which is why there are no cards
   and no shadows anywhere. But most of them separate columns, and a column that
   has stacked is already separated by the stacking. Counted on the front page a
   phone was drawing sixty-nine of them, twenty-two of which were the tops of
   columns standing one above the other: side by side those twenty-two read as
   seven lines across seven rows, stacked they read as a ladder. So the rule a
   group opens with stays, because it still announces the group, and the rules
   on the columns under it go. Nothing that marks a change of state goes: the
   closing line of a section, the seam between grounds, the division inside a
   column above its outcome. Those still separate something the layout does not.

   The second is that a thumb is not a cursor. Thirteen of the seventeen things
   worth tapping were under the forty-four pixels a thumb needs in at least one
   direction: the language switch at twenty-three across, the footer links at
   thirty tall, the address at twenty-two. They keep their type and their
   spacing and grow only the area that answers. */
@media (max-width: 56rem) {
  .cols > .col:not(:first-child) { border-top-color: transparent; }
  .cols > .col:not(:first-child)::before,
  .cols > .col:not(:first-child)::after { display: none; }

  /* The underlines are positioned from the bottom of the padding box, so the
     padding that grows the target would drop them off the words. One value
     moves both, rather than two that have to be remembered together. */
  .contact__line a, .footer__contact a, .footer__nav a, .link {
    --tap: 0.8rem;
    padding-block: var(--tap);
  }
  .contact__line a::after,
  .footer__contact a::after,
  .footer__nav a::after { bottom: calc(var(--tap) - 2px); }
  .link::before, .link::after { bottom: var(--tap); }

  /* The switch has three pixels of room to its right, so it grows to the left
     and downward with an overlay instead of with padding, which would push it
     off the edge. */
  /* The address is firstname.lastname at a hyphenated domain, which is 37
     characters, and at its own size that wrapped after the hyphen: the line
     ended on "koppel-" and read as though the address stopped there. It is one
     value serving both the link and the words, so a break opportunity cannot be
     hidden inside it without that character travelling along when somebody
     copies the address, which is worse than an ugly wrap. It is set slightly
     smaller here instead, and fits on one line. */
  .contact__line a { font-size: 1rem; }

  .nav__lang a { position: relative; }
  .nav__lang a::after {
    content: "";
    position: absolute;
    inset: -13px 0 -13px -15px;
  }
}

@media (max-width: 34rem) {
  .cols--4 { grid-template-columns: 1fr; }
  .state__cells { gap: 0.4rem; }
  .matrix__steps { gap: 0.4rem; }
  .matrix__step { font-size: 0.5625rem; letter-spacing: 0.08em; }
  .fourth, .fatigue { padding: 1.5rem 1.35rem; }

  /* A tab carries 1.4rem of padding and 2rem of margin after it, which is
     three and a half rems of trailing air each. At 320 across that put the
     third state 11 pixels past the edge of the screen, and the page does not
     scroll sideways, so it could not be reached or read. The words keep their
     size; the air between them is what gives way, and they may wrap if a
     narrower screen than this turns up. */
  .matrix.is-enhanced .matrix__tabs { flex-wrap: wrap; }
  .matrix__tab { padding-right: 0; margin-right: 1.1rem; }
  .matrix__tab:last-child { margin-right: 0; }

  /* A 1fr track will not go below the width of its own longest word, so five
     of them ran the row past the edge. */
  .matrix__steps, .state__cells { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ====================================================================== */
/* A third ground.                                                        */
/*                                                                        */
/* The argument opens and closes on ink with the filament field running   */
/* behind it, and the document passages in between stay on paper. Ink     */
/* sections are transparent rather than navy: the ground is on <body>,    */
/* so the field shows through wherever a section does not paint over it.  */
/* ====================================================================== */

.section--ink { background: transparent; color: var(--dim-text); }

.section--ink .headline,
.headline--dark { color: var(--cream); }
.section--ink .standfirst,
.standfirst--dark { color: var(--dim-text); }
.section--ink .body,
.body--dark { color: var(--dim-text); }
.section--ink .source,
.source--dark { color: var(--dim-text); }

.section--ink .col,
.col--dark { border-top-color: var(--rule-dark); }
.section--ink .col::before,
.col--dark::before { background: var(--copper-light); }
.section--ink .col__n,
.col--dark .col__n { color: var(--copper-light); }
.section--ink .col__title,
.col--dark .col__title { color: var(--cream); }
.section--ink .col__label,
.col--dark .col__label { color: var(--dim-text); }
.section--ink .col__outcome,
.col--dark .col__outcome { border-top-color: var(--rule-dark); color: var(--cream); }

.section--ink .closer,
.closer--dark { border-top-color: var(--rule-dark); color: var(--cream); }
.section--ink .split,
.split--dark { border-top-color: var(--rule-dark); }
.section--ink .ticks li::before { background: var(--copper-light); }

/* the pull quote on /about, set as speech rather than as a statement */
.quote {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 700;
  font-size: clamp(1.15rem, 1rem + 0.9vw, 1.6rem);
  line-height: 1.35;
  color: var(--cream);
  max-width: 30ch;
  padding-left: 1.6rem;
  border-left: 2px solid var(--copper-light);
}

/* an open decision rendered on the ink ground rather than the paper one */
.section--ink .todo {
  background: transparent;
  border-left-color: var(--copper-light);
  color: var(--dim-text);
}

/* ====================================================================== */
/* Weight, air and grid.                                                  */
/*                                                                        */
/* Three corrections to the first pass. The type was too small to carry a */
/* page this wide. Consecutive sections collapsed their top padding, so   */
/* a headline started immediately after the block above it ended. And a   */
/* column had a rule above it and nothing beside it, which left the text  */
/* floating rather than set into a grid.                                  */
/* ====================================================================== */

/* --- air ---------------------------------------------------------------- */

:root { --step: clamp(5rem, 8.2vw, 9.5rem); }

/* Every section pays its own padding. Where two meet, the space doubles,
   which is exactly what a change of ground should be worth. */
.section + .section:not(.section--tint) { padding-top: var(--step); }
.section--tint + .section { padding-top: var(--step); }

/* A change of ground gets more still, and a hairline to mark the seam. */
.section--ink + .section,
.section + .section--ink,
.plate + .section,
.section + .plate,
.statement + .section { padding-top: calc(var(--step) * 1.15); }

/* --- weight ------------------------------------------------------------- */

.headline { font-size: clamp(2.125rem, 1.15rem + 4.3vw, 4.5rem); line-height: 1.06; max-width: 20ch; }
.hero__headline { font-size: clamp(2.4rem, 1.1rem + 6.1vw, 5.75rem); line-height: 1.04; }
.statement__text { font-size: clamp(2.125rem, 1.1rem + 4.5vw, 4.75rem); line-height: 1.06; }
.standfirst { margin-top: 2.4rem; font-size: clamp(1.125rem, 1rem + 0.55vw, 1.5rem); line-height: 1.55; }
.closer { font-size: clamp(1.25rem, 1rem + 1.15vw, 2rem); line-height: 1.25; }
.col__title { font-size: clamp(1.0625rem, 1rem + 0.42vw, 1.3rem); }
.col__title--lg { font-size: clamp(1.15rem, 1rem + 0.62vw, 1.5rem); }
.col__n { font-size: 1.0625rem; }
.stat__figure { font-size: clamp(2.75rem, 1.6rem + 4.6vw, 5.25rem); line-height: 1; }

/* Structure carries 2px. A 1px navy rule reads as a scratch at this scale;
   the fine hairlines are kept for the secondary divisions inside a column. */
.col { border-top-width: 2px; padding-top: 1.9rem; }
.col::before { width: 2px; height: 12px; top: -12px; }
.closer { border-top-width: 2px; }
.split { border-top-width: 2px; }

/* --- the grid ----------------------------------------------------------- */

/* Columns are set into a table of hairlines rather than floated in space.
   The vertical rule sits in the gutter, so the row reads as one object. */
.cols {
  gap: 3.75rem 0;
  margin-top: 5rem;
  --colpad: clamp(1.4rem, 2.2vw, 2.6rem);
}
.cols > .col { padding-inline: var(--colpad); }
.cols > .col:first-child { padding-left: 0; }
.cols > .col:last-child { padding-right: 0; }
.cols > .col + .col { border-left: var(--hair) solid var(--rule); }
.section--ink .cols > .col + .col { border-left-color: var(--rule-dark); }

/* On two rows of a four-up the left border of the wrapped item would start a
   second table; the grid handles it, but the first of each row must not. */
@media (max-width: 68rem) {
  .cols--4 { grid-template-columns: repeat(2, 1fr); }
  .cols--4 > .col:nth-child(odd) { border-left: 0; padding-left: 0; }
  .cols--4 > .col:nth-child(even) { padding-right: 0; }
}
@media (max-width: 52rem) {
  .cols--2, .cols--3, .cols--4 { grid-template-columns: 1fr; }
  .cols > .col { border-left: 0; padding-inline: 0; }
}

/* A narrower measure. 1420px was too wide to read comfortably and left no
   margin for the light to run in. The column now sits inside its page. */
:root { --measure: 1280px; --gutter: clamp(1.5rem, 6vw, 7rem); }

/* A change of ground is marked rather than left to happen. One copper hairline
   at the seam, full bleed, in the copper that belongs to the ground it lands
   on. Without it the page simply stops being dark, which reads as an accident. */
.section--ink + .section { border-top: 2px solid var(--copper-deep); }
.section + .section--ink,
.plate + .section--ink { border-top: 2px solid var(--copper-light); }
.statement + .section,
.hero + .section:not(.section--ink) { border-top: 2px solid var(--copper-deep); }
.section--ink + .contact { border-top: 0; }


/* ====================================================================== */
/* The chain, at the size it deserves.                                    */
/*                                                                        */
/* This is the only interactive thing on the site and the strongest piece */
/* of evidence on the page, and it was set at the size of a footnote. The */
/* squares are now the object, the labels sit over them like a table      */
/* head, and the reading sits underneath at full measure.                 */
/* ====================================================================== */

.matrix { --matrix-gutter: clamp(11rem, 17vw, 15rem); margin-top: 4.5rem; }

.matrix__steps, .state__cells { gap: 1.25rem; }
.matrix__steps { margin-bottom: 1.5rem; }
.matrix__step { font-size: 0.75rem; letter-spacing: 0.16em; color: var(--ink); }

.state { padding-top: 2.5rem; border-top-width: 2px; }
.state__name { font-size: clamp(1.3rem, 1rem + 1.05vw, 1.9rem); }
.state__sub { margin-top: 0.55rem; font-size: 0.9375rem; }

/* The squares carry the argument, so they are drawn at the size of a
   decision rather than the size of a bullet. */
.state__cells { padding-top: 0.55rem; }
.state__cells .cell { width: clamp(1.5rem, 2.4vw, 2.15rem); height: clamp(1.5rem, 2.4vw, 2.15rem); }
.cell--bounded { box-shadow: inset 0 0 0 3px var(--copper-deep); }
.matrix__legend .cell { width: 0.9rem; height: 0.9rem; }
.matrix__legend .cell--bounded { box-shadow: inset 0 0 0 2px var(--copper-deep); }

/* The reading runs the full width under the whole diagram, not tucked into
   the column the squares happen to start in. */
.state__body {
  grid-column: 1 / -1;
  margin-top: 2.6rem;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  line-height: 1.65;
  max-width: 68ch;
}

.matrix__tabs { gap: 2.5rem; margin-bottom: 2.25rem; }
.matrix__tab { font-size: 0.8125rem; letter-spacing: 0.16em; padding-bottom: 0.9rem; }
.matrix__legend { gap: 2.25rem; margin-bottom: 3rem; }

@media (max-width: 72rem) {
  .matrix { --matrix-gutter: 0; }
  .state__body { margin-top: 2rem; }
}

/* --- more daylight between the two light grounds ----------------------- */

/* The second light ground is linen: the colour of the cloth you paint on.
   --tint-light was a two per cent difference from paper and read as a printing
   fault; --tint-mid registered but it is a cool blue-grey, which fights both
   the copper and the paint.

   It is also the only one of the three that is accessible. On --tint-mid the
   copper eyebrow measures 4.19:1 and on full --cream 4.20:1, both under AA.
   On linen it is 4.59:1. The warm ground is not a compromise here; it is the
   fix. */
.section--tint { background: var(--canvas); }
.section--tint .col + .col { border-left-color: var(--rule); }

/* The pull quote runs to two paragraphs where one block of it was too solid
   to read as a statement. Held tighter than body copy: they are two halves of
   one sentence of thought, not two points. */
.pull p + p { margin-top: 1.1rem; }

/* One closer width across the page, so the rule above them is always the
   same length and reads as the same device. */
.closer { max-width: 38ch; padding-top: 2.1rem; margin-top: 4.5rem; }

/* The five squares are one chain, so a hairline runs through them. Without it
   they read as five unrelated states rather than as one piece of work moving
   from intake to learning. */
.state__cells { position: relative; padding-top: 0; margin-top: 0.55rem; }
.state__cells::before {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  top: 50%;
  height: var(--hair);
  background: var(--rule);
  z-index: 0;
}
.section--ink .state__cells::before { background: var(--rule-dark); }
.state__cells .cell { position: relative; z-index: 1; }

/* --- final weight pass -------------------------------------------------- */

/* The withheld-sequence line is the most valuable sentence on the page and it
   was set at the size of a caption with a note. It is a statement. */
.pull { margin-top: 5rem; padding-top: 3rem; max-width: min(100%, 46rem); }
.pull p { font-size: clamp(1.4rem, 1.05rem + 1.5vw, 2.25rem); line-height: 1.24; }

/* The close of the whole argument, at the size of a close. */
.contact__statement { font-size: clamp(2.125rem, 1.1rem + 4.4vw, 4.5rem); line-height: 1.05; max-width: 15ch; }

/* Dark columns need more than a 1px navy-on-navy rule to read as structure. */
.section--ink .col,
.col--dark { border-top-width: 2px; }

/* A closer that already sits at the foot of a section does not need to add a
   full step of its own on top of the section padding. */
.closer { margin-top: 4.5rem; }
.section--ink .closer { margin-top: 4rem; }

/* The contact block closes the page, so the seam above it is air rather than
   another doubled step. */
.section--ink + .contact { padding-top: calc(var(--step) * 0.55); }

/* ====================================================================== */
/* From all the work to a number in the accounts.                         */
/*                                                                        */
/* The three destinations answer where freed capacity goes. This answers  */
/* the question after it: what any of that is worth. Same hairline        */
/* vocabulary, read top to bottom, ending on the only line a CFO cares    */
/* about.                                                                 */
/* ====================================================================== */

.flow {
  list-style: none;
  margin: 5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0;
  max-width: 46rem;
}
.flow__node {
  position: relative;
  padding: 1.5rem 0 1.5rem 2.25rem;
  border-top: var(--hair) solid var(--rule);
}
.flow__node:first-child { border-top-width: 2px; border-top-color: var(--ink); }
.flow__node:last-child { border-bottom: 2px solid var(--copper-deep); }

/* the spine of the flow, and a tick where each stage sits on it */
.flow__node::before {
  content: "";
  position: absolute;
  left: 0.4rem;
  top: 0;
  bottom: 0;
  width: var(--hair);
  background: var(--rule);
}
.flow__node:first-child::before { top: 50%; }
.flow__node:last-child::before { bottom: 50%; }
.flow__node::after {
  content: "";
  position: absolute;
  left: 0;
  top: calc(50% - 0.3rem);
  width: 0.6rem;
  height: 0.6rem;
  background: var(--ink);
}
.flow__node--end::after { background: var(--copper-deep); }

.flow__label {
  display: block;
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.05rem, 1rem + 0.5vw, 1.35rem);
  color: var(--ink);
}
.flow__node--end:last-child .flow__label {
  color: var(--copper-deep);
  font-size: clamp(1.25rem, 1rem + 1vw, 1.85rem);
}
.flow__body { display: block; margin-top: 0.35rem; font-size: 0.9375rem; color: var(--slate); }

.section--ink .flow__node { border-top-color: var(--rule-dark); }
.section--ink .flow__node::before { background: var(--rule-dark); }
.section--ink .flow__label { color: var(--cream); }
.section--ink .flow__body { color: var(--dim-text); }

/* the hero's closing line, in the copper that carries the argument */
.hero__kicker {
  margin-top: 1.4rem;
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.15rem, 1rem + 0.8vw, 1.6rem);
  color: var(--copper-light);
}

/* ====================================================================== */
/* The navy runs the whole height of the page.                            */
/*                                                                        */
/* The light sections are sheets laid on it rather than full-bleed bands, */
/* so the ground never disappears and moving from one section to the next */
/* stops feeling like advancing a slide. The light also has somewhere to  */
/* live: the margins are where the swirl is visible.                      */
/* ====================================================================== */

:root { --frame: clamp(0px, 3.4vw, 78px); }

.section:not(.section--ink) { margin-inline: var(--frame); }

/* Full bleed stays full bleed: the plates and the ink passages are the ground
   itself, not sheets on it. */
.plate, .section--ink, .contact, .footer { margin-inline: 0; }

/* The contents rail now has a margin of its own to sit in. */
@media (min-width: 80rem) { .rail { right: clamp(1rem, 1.6vw, 1.9rem); } }

@media (max-width: 56rem) { :root { --frame: 0px; } }

/* ====================================================================== */
/* The painting.                                                          */
/*                                                                        */
/* One picture on the whole site that is not a place. It hangs in the      */
/* open right-hand column of a section whose type stops well short of it,  */
/* so it sits in the page rather than interrupting it.                     */
/* ====================================================================== */

.painting {
  margin: 0;
  position: absolute;
  top: 1.5rem;
  right: 0;
  width: clamp(220px, 28vw, 400px);
  z-index: 1;
}
/* [hidden] is display:none in the UA sheet, and a display declaration here
   would beat it. Script hides this image once the masked canvas replaces it,
   and without the guard the hidden image keeps its place in the flow and
   pushes the caption a picture's height down the page. */
/* A picture in the corner of a section whose content runs the full width
   underneath it. The picture keeps the corner, which is where it belongs, and
   what gives is the grid: it starts below the caption instead of running under
   it. Held narrower than the free-standing one so the gap it opens on the left
   stays reasonable. */
.painting--corner { width: clamp(220px, 25vw, 330px); }

/* The closing picture. Full width of its column and after the words rather than
   beside them, because it is the last thing on the page and nothing follows it
   that it could get in the way of. */
.painting--close {
  position: static;
  width: 100%;
  margin: 3.5rem 0 0;
}
.painting--close figcaption { margin-top: -1.2rem; }

@media (min-width: 56rem) {
  .painting--corner ~ .cols { margin-top: 12rem; }
  /* Clear of the contents rail. The rail is fixed and overlaps the right edge
     of the text column by about a hundred pixels at this width, which is fine
     over a photograph and not fine over a credit line. */
  .painting--corner { right: 6.5rem; }
}

.painting img { display: block; width: 100%; height: auto; }
.painting img[hidden] { display: none; }
/* An artwork title is set in italic, which is the only thing the caption does
   beyond stating the fact. */
.painting figcaption em { font-style: italic; }
/* The credit runs the width of the picture it belongs to. Held to thirty
   characters it broke into four ragged lines under a four-hundred pixel image,
   which reads as an accident rather than as a caption. */
/* The paint dissolves well before the bottom of its canvas, so a caption set
   flush to that edge floats away from the picture it belongs to. It is pulled
   back up to sit under the paint rather than under the file. */
.painting--corner figcaption { margin-top: -1.4rem; }

.painting figcaption {
  margin-top: -2.4rem;
  font-size: 0.75rem;
  font-style: italic;
  line-height: 1.6;
  color: var(--caption);
  max-width: none;
  text-wrap: pretty;
}

/* The section becomes the frame it hangs in. */
.section:has(.painting) > .wrap { position: relative; }

/* A picture standing in the right margin has to be paid for by the words.

   The figure is absolute, so it costs the text nothing by itself and the text
   simply ran underneath it - three blocks deep, up to eighty-seven pixels, on
   an ordinary laptop. Width rather than max-width, so each block keeps its own
   measure and takes whichever of the two is smaller. Only above the width at
   which the picture stops being in the margin at all. */
@media (min-width: 62rem) {
  .section--aside { --picture: clamp(220px, 28vw, 400px); }
  .section--aside .painting { width: var(--picture); }
  .section--aside > .wrap > .headline,
  .section--aside > .wrap > .standfirst,
  .section--aside > .wrap > .pull {
    width: calc(100% - var(--picture) - 2.5rem);
  }
}

@media (max-width: 62rem) {
  .painting {
    position: static;
    width: min(100%, 340px);
    margin: 3.5rem 0 0;
  }
}

/* The one number on the site. It is stated the way a fixed price should be:
   once, plainly, with nothing hedging it. */
.price__line {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.05rem, 1rem + 0.5vw, 1.35rem);
  color: var(--ink);
}
.price__figure {
  margin-top: 0.5rem;
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.9rem, 1.2rem + 2.4vw, 3.1rem);
  line-height: 1.05;
  color: var(--copper-deep);
}

/* An engagement's terms carry a price now, so the two halves are set apart
   rather than run together in one grey line. */
.offer__terms { font-weight: 700; color: var(--ink); }
.section--ink .offer__terms { color: var(--cream); }

/* The guarantee belongs with the number. A fixed price provokes exactly one
   question, and the answer should not be a footnote on another page. */
.price__label { margin-top: 2.25rem; }
.price__guarantee {
  margin-top: 0.6rem;
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.05rem, 1rem + 0.55vw, 1.4rem);
  line-height: 1.35;
  color: var(--ink);
  max-width: 26ch;
}

/* The closing statement on /assessment, set at statement scale on ink. */
#close .statement__text { max-width: 24ch; margin-top: 0.5rem; }
#close .body { margin-top: 2.25rem; max-width: 56ch; }

/* ------------------------------------------------------------- wrapping -- */

/* Headlines balance, which evens their lines out. Body copy gets `pretty`,
   which solves the other half of the same problem: a last line carrying one
   short word. Seven paragraphs on /assessment alone ended on a single word
   before this, and one of them ended on "serve."

   Every list item, not just the ticks: one on /about was ending on
   "stakeholders" by itself. */
.body, .body--lead, .standfirst, .hero__sub, .col__body, .col__outcome,
.closer, .refused__body, .contact__note, .source, .statement__body,
.fourth__body, main li, .painting figcaption {
  text-wrap: pretty;
}

/* ==========================================================================
   Motion.

   One rule governs everything here: the movement is made of the design system,
   not applied on top of it. A hairline draws itself. Type rises from behind a
   rule. A figure counts to its own number. Squares change hands along the
   chain. Nothing floats, bounces, blurs or slides in from the side, because
   none of those exist in the printed system either.

   Every animated element carries its own resting state and its own .is-in.
   Nothing is styled through a descendant of a section, so a column at the foot
   of a section cannot be triggered by the section's top edge arriving.

   Everything is gated on .kc-js, set synchronously by the inline script in
   <head>. No script means no resting states, so a browser without JavaScript
   gets the finished page rather than an empty one.
   ========================================================================== */

:root {
  /* The house curve: decisive on departure, long settle, no overshoot. */
  --ease: cubic-bezier(0.16, 1, 0.30, 1);
  --ease-io: cubic-bezier(0.76, 0, 0.24, 1);

  --t-rule: 820ms;     /* a hairline drawing across */
  --t-rise: 1000ms;    /* a line of type coming up from behind one */
  --t-fade: 700ms;
  --t-cell: 520ms;     /* a square changing hands */
  --stagger: 90ms;
}

/* Children of a staggered row take their delay from an index set by script. */
[data-stagger] > * { --d: calc(var(--i, 0) * var(--stagger)); }

/* ------------------------------------------------------ 1. type on a line -- */

/* Script wraps each word, measures which line it landed on, and groups the
   timing by line. The mask is per word, the delay is per line, so the eye
   reads whole lines rising from behind a rule. */

.kc-js .lines .wi {
  transform: translateY(115%);
  transition: transform var(--t-rise) var(--ease);
  transition-delay: calc(var(--line, 0) * var(--stagger) + var(--d, 0ms));
}
.kc-js .lines.is-in .wi { transform: translateY(0); }

.w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.16em;
  margin-bottom: -0.16em;
}
/* No will-change here. A page of headlines is a couple of hundred words, and
   promoting every one of them to its own compositor layer costs more than the
   transition it was meant to smooth. The transform composites on its own. */
.wi { display: inline-block; }

/* --------------------------------------------------------- 2. rule draw -- */

/* A border cannot be transformed, so every structural hairline becomes a
   pseudo-element that scales from the left. Same 1px, same colour, now with
   a direction of travel. */

.kc-js .col,
.kc-js .closer,
.kc-js .stat,
.kc-js .pull,
.kc-js .refused,
.kc-js .split,
.kc-js .state,
.kc-js .clients__group,
.kc-js .price,
.kc-js .footer__top,
.kc-js .contact__grid { border-top-color: transparent; }

.kc-js .col::after,
.kc-js .closer::before,
.kc-js .stat::after,
.kc-js .pull::before,
.kc-js .refused::before,
.kc-js .split::before,
.kc-js .state::after,
.kc-js .clients__group::after,
.kc-js .price::before,
.kc-js .footer__top::after,
.kc-js .contact__grid::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--rule-h, 1px);
  background: var(--rule-c, var(--ink));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--t-rule) var(--ease) var(--d, 0ms);
}

.closer, .pull, .refused, .split, .price,
.footer__top, .contact__grid, .clients__group, .stat, .state { position: relative; }

.kc-js .closer::before,
.kc-js .split::before,
.kc-js .price::before { --rule-c: var(--ink); }
.kc-js .section--ink .closer::before,
.kc-js .section--ink .split::before,
.kc-js .closer--dark::before,
.kc-js .split--dark::before { --rule-c: var(--rule-dark); }
.kc-js .section--ink .col::after,
.kc-js .col--dark::after { --rule-c: var(--rule-dark); }
.kc-js .section--ink .col::before,
.kc-js .col--dark::before { background: var(--copper-light); }
.kc-js .pull::before,
.kc-js .refused::before { --rule-c: var(--copper-deep); --rule-h: 2px; }
.kc-js .stat:last-child::after,
.kc-js .col--emphasis::after,
.kc-js .state--emphasis::after { --rule-c: var(--copper-deep); --rule-h: 2px; }
.kc-js .footer__top::after,
.kc-js .contact__grid::before { --rule-c: var(--rule-dark); }

.kc-js .col.is-in::after,
.kc-js .closer.is-in::before,
.kc-js .stat.is-in::after,
.kc-js .pull.is-in::before,
.kc-js .refused.is-in::before,
.kc-js .split.is-in::before,
.kc-js .state.is-in::after,
.kc-js .clients__group.is-in::after,
.kc-js .price.is-in::before,
.kc-js .footer__top.is-in::after,
.kc-js .contact__grid.is-in::before { transform: scaleX(1); }

/* the short vertical tick drops once its rule has arrived */
.kc-js .col::before {
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 420ms var(--ease) calc(var(--d, 0ms) + 300ms);
}
.kc-js .col.is-in::before { transform: scaleY(1); }

/* ---------------------------------------------------------- 3. settle -- */

/* Everything that is not display type and not a rule. A short rise and a
   fade, on the element itself so its own position decides when it plays. */

.kc-js .col,
.kc-js .stat__figure,
.kc-js .stat__line,
.kc-js .standfirst,
.kc-js .body,
.kc-js .source,
.kc-js .hero__sub,
.kc-js .hero__cta,
.kc-js .statement__body,
.kc-js .contact__body,
.kc-js .contact__note,
.kc-js .contact__line,
.kc-js .contact__meta,
.kc-js .clients__names,
.kc-js .refused__body,
.kc-js .footer__col,
.kc-js .footer__base {
  opacity: 0;
  transform: translateY(0.9rem);
  transition:
    opacity var(--t-fade) var(--ease) var(--d, 0ms),
    transform var(--t-fade) var(--ease) var(--d, 0ms);
}
.kc-js .col.is-in,
.kc-js .stat.is-in .stat__figure,
.kc-js .stat.is-in .stat__line,
.kc-js .standfirst.is-in,
.kc-js .body.is-in,
.kc-js .source.is-in,
.kc-js .hero__sub.is-in,
.kc-js .hero__cta.is-in,
.kc-js .statement__body.is-in,
.kc-js .contact__body.is-in,
.kc-js .contact__note.is-in,
.kc-js .contact__line.is-in,
.kc-js .contact__meta.is-in,
.kc-js .clients__group.is-in .clients__names,
.kc-js .refused.is-in .refused__body,
.kc-js .footer__col.is-in,
.kc-js .footer__base.is-in { opacity: 1; transform: translateY(0); }

.kc-js .stat .stat__line { --d: 120ms; }

/* tick lists cascade item by item */
.kc-js .ticks li {
  opacity: 0;
  transform: translateY(0.6rem);
  transition:
    opacity 520ms var(--ease) calc(var(--i, 0) * 70ms),
    transform 520ms var(--ease) calc(var(--i, 0) * 70ms);
}
.kc-js .ticks.is-in li { opacity: 1; transform: translateY(0); }
.kc-js .ticks li::before { transform: scaleX(0); transform-origin: left; transition: transform 420ms var(--ease) calc(var(--i, 0) * 70ms + 140ms); }
.kc-js .ticks.is-in li::before { transform: scaleX(1); }

/* the two navy bands carry their own contents */
.kc-js .fourth__body,
.kc-js .fatigue__note {
  opacity: 0;
  transform: translateY(0.7rem);
  transition: opacity var(--t-fade) var(--ease) 220ms, transform var(--t-fade) var(--ease) 220ms;
}
.kc-js .fourth.is-in .fourth__body,
.kc-js .fatigue.is-in .fatigue__note { opacity: 1; transform: translateY(0); }

/* ---------------------------------------------------- 4. section marker -- */

/* The document outline made visible. A numeral, a rule that draws out to meet
   the label, then the label. The page-number device from the decks. */

.marker {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-bottom: 1.6rem;
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--copper-deep);
}
.marker--dark { color: var(--copper-light); }
.marker__n {
  font-family: var(--serif);
  font-size: 0.875rem;
  letter-spacing: 0.02em;
  flex: none;
}
.marker__rule {
  display: block;
  flex: none;
  width: 3.25rem;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
}
.kc-js .marker__n { opacity: 0; transition: opacity var(--t-fade) var(--ease); }
.kc-js .marker__rule { transform: scaleX(0); transition: transform var(--t-rule) var(--ease) 90ms; }
.kc-js .marker__label {
  opacity: 0;
  transform: translateX(-0.5rem);
  transition: opacity var(--t-fade) var(--ease) 280ms, transform var(--t-fade) var(--ease) 280ms;
}
.kc-js .marker.is-in .marker__n { opacity: 1; }
.kc-js .marker.is-in .marker__rule { transform: scaleX(1); }
.kc-js .marker.is-in .marker__label { opacity: 1; transform: translateX(0); }

/* ------------------------------------------------------- 5. the plates -- */

.plate { overflow: hidden; }
.plate__img {
  position: absolute;
  inset: -2px;
  background-image: var(--plate);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-color: var(--ink);
}
/* Three steps, chosen on width alone.

   The rule this replaces served the 2200px file to anything at 1.5dppx or more,
   which is every phone made in the last decade: a 375px screen was downloading
   423 KB to show it 750 device pixels wide. Resolution is the wrong test on its
   own, because a dense screen is not necessarily a wide one. Width decides, and
   the density is already inside it: a 375px phone at 2x needs 750 pixels, and
   the 1100 covers that with room to spare.

   A plate that states no --plate-sm falls back to --plate, which is how the
   standing assessment plate opts out: its own smallest file is 900 across. */
.plate__img { background-image: var(--plate-sm, var(--plate)); }

@media (min-width: 700px) {
  .plate__img { background-image: var(--plate); }
}
@media (min-width: 1000px) {
  .plate__img { background-image: var(--plate-lg); }
}
/* Only the text column needs a stacking context of its own. The credit and the
   cue are already absolutely positioned and must stay that way, or they join
   the hero's flex row and push the column off the page. */
.plate > .wrap { position: relative; z-index: 1; }
.plate__credit, .cue { z-index: 2; }

.kc-js .plate__img { transform: scale(1.045); transition: transform 1700ms var(--ease); }
.kc-js .plate.is-in .plate__img { transform: scale(1); }

/* A slow continuous drift, only where the browser drives it off the main
   thread. No scroll handler is worth the jank. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 56rem) {
    .kc-js .plate.is-in .plate__img {
      animation: plate-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
      transition: none;
    }
    @keyframes plate-drift {
      from { transform: scale(1.05) translateY(-1.6%); }
      to   { transform: scale(1.05) translateY(1.6%); }
    }
  }
}

/* On a narrow screen the scrim no longer covers the column, so the type sits
   on solid ink and the photographic half becomes a band below it. */
@media (max-width: 56rem) {
  .plate__img {
    top: auto;
    /* Framed, not magnified, and the height is doing the framing. The source
       is 1100 by 619 with the scrim baked into its left 52 per cent, measured
       rather than guessed: every column up to there has a spread in brightness
       under one, and the drawing starts at 52. Cover on a 38vh band showed the
       window from 29 to 98 per cent of that source, so a third of the picture
       on screen was flat navy with a seam down it. A taller band narrows the
       window - it is 202/height of the source - and at 440 that is 46 per
       cent, which 94 per cent anchors at 51: past the scrim, with the figure
       a fifth in from the left rather than sliced by the frame. */
    height: var(--band, 440px);
    background-size: cover;
    background-position: 94% center;
  }
}

/* ------------------------------------------------------- 6. the curtain -- */

/* Plays once per session, and never for a visitor who asked for less motion.
   Injected by a class on <html> from the inline script, so a browser with no
   script never sees a curtain and has nothing to lift. */

.curtain { display: none; }
.kc-intro .curtain {
  display: grid;
  position: fixed;
  inset: 0;
  z-index: 200;
  place-items: center;
  background: var(--ink);
  transition: transform 1000ms var(--ease-io);
  /* If script dies between here and the lift, the page opens anyway. Sooner
     than it used to: while this is up it is a black screen that swallows
     clicks, and four and a half seconds of that is indistinguishable from a
     page that has locked up. */
  animation: curtain-safety 0ms 3200ms forwards;
}
/* The moment it starts moving it stops taking clicks. It is on its way out and
   the page behind it is already the thing being pointed at; a thousand
   milliseconds of transform used to sit on top of the nav eating them. */
.kc-intro.kc-lift .curtain { transform: translateY(-100%); pointer-events: none; }
@keyframes curtain-safety {
  to { transform: translateY(-100%); visibility: hidden; pointer-events: none; }
}
.kc-intro body { overflow: hidden; }

.curtain__inner { display: grid; justify-items: center; gap: 1.3rem; }
.curtain__mark {
  width: auto;
  height: 3.25rem;
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity 640ms var(--ease), transform 640ms var(--ease);
}
.curtain__rule {
  width: 8rem;
  height: 1px;
  background: var(--copper-light);
  transform: scaleX(0);
  transition: transform 780ms var(--ease) 240ms;
}
.curtain__word {
  font-family: var(--sans);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--dim-text);
  opacity: 0;
  transition: opacity 640ms var(--ease) 420ms;
}
.kc-intro.kc-ready .curtain__mark { opacity: 1; transform: translateY(0); }
.kc-intro.kc-ready .curtain__rule { transform: scaleX(1); }
.kc-intro.kc-ready .curtain__word { opacity: 1; }

/* ------------------------------------------------ 7. progress and rail -- */

.progress {
  position: fixed;
  top: 0; left: 0;
  z-index: 60;
  width: 100%;
  height: 2px;
  background: var(--copper-deep);
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  .progress { animation: progress-grow linear both; animation-timeline: scroll(root block); }
  @keyframes progress-grow { to { transform: scaleX(1); } }
}

/* The contents rail: an outline you can see and click. A well-set document
   has one; a landing page does not. */
.rail {
  position: fixed;
  right: max(1.4rem, calc(var(--gutter) - 1.9rem));
  top: 50%;
  z-index: 40;
  display: none;
  flex-direction: column;
  gap: 0.55rem;
  transform: translateY(-50%);
  opacity: 0;
  transition: opacity var(--t-fade) var(--ease);
}
.rail.is-on { opacity: 1; }
@media (min-width: 80rem) { .kc-js .rail { display: flex; } }

/* The rail is fixed at the middle of the viewport, so it regularly straddles
   the seam between a navy band and a white one. Rather than guess which side
   it is on, it inverts against whatever is actually behind it: white type
   turns black over paper and near-cream over ink, and stays legible over a
   photographic plate too. Because colour is no longer available to mark the
   current section, the tick length and the weight do that job instead. */
.rail { mix-blend-mode: difference; }

.rail__item {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
  text-decoration: none;
  font-family: var(--serif);
  font-size: 0.6875rem;
  font-weight: 700;
  color: #FFFFFF;
  opacity: 0.62;
  transition: opacity 320ms var(--ease);
}
.rail__label {
  font-family: var(--sans);
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  transform: translateX(0.4rem);
  transition: opacity 320ms var(--ease), transform 320ms var(--ease);
}
.rail__tick {
  display: block;
  width: 0.75rem;
  height: 1px;
  background: currentColor;
  transition: width 320ms var(--ease), height 320ms var(--ease);
}
.rail__item:hover,
.rail__item:focus-visible { opacity: 1; }
.rail__item:hover .rail__label,
.rail__item:focus-visible .rail__label { opacity: 1; transform: translateX(0); }
.rail__item[aria-current="true"] { opacity: 1; }
.rail__item[aria-current="true"] .rail__tick { width: 1.7rem; height: 2px; }

/* -------------------------------------------------------- 8. the matrix -- */

.kc-js .cell {
  transition:
    background-color var(--t-cell) var(--ease) var(--d, 0ms),
    box-shadow var(--t-cell) var(--ease) var(--d, 0ms),
    transform var(--t-cell) var(--ease) var(--d, 0ms);
}
/* squares hand over one at a time, along the chain */
.state__cells .cell:nth-child(1) { --d: 0ms; }
.state__cells .cell:nth-child(2) { --d: 70ms; }
.state__cells .cell:nth-child(3) { --d: 140ms; }
.state__cells .cell:nth-child(4) { --d: 210ms; }
.state__cells .cell:nth-child(5) { --d: 280ms; }
.kc-js .matrix.is-morphing .state__cells .cell { transform: scale(0.68); }

/* the chain draws itself once, then the squares land along it */
.kc-js .state__cells::before { transform: scaleX(0); transform-origin: left center; transition: transform var(--t-rule) var(--ease); }
.kc-js .state.is-in .state__cells::before { transform: scaleX(1); }
.kc-js .state__cells .cell { transform: scale(0); }
.kc-js .state.is-in .state__cells .cell { transform: scale(1); }

.kc-js .matrix__step {
  opacity: 0;
  transform: translateY(0.4rem);
  transition:
    opacity var(--t-fade) var(--ease) calc(var(--i, 0) * 60ms),
    transform var(--t-fade) var(--ease) calc(var(--i, 0) * 60ms);
}
.kc-js .matrix__steps.is-in .matrix__step { opacity: 1; transform: translateY(0); }

.matrix.is-enhanced .matrix__tab { border-bottom-color: transparent; position: relative; }
.matrix__tab::after {
  content: "";
  position: absolute;
  left: 0; bottom: -1px;
  width: 100%;
  height: 2px;
  background: var(--copper-deep);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 420ms var(--ease);
}
.matrix__tab[aria-selected="true"]::after { transform: scaleX(1); }

/* ---------------------------------------------------------- 9. the bar -- */

.kc-js .bar__fill { transform: scaleX(0); transform-origin: left center; transition: transform 1100ms var(--ease) var(--d, 0ms); }
.kc-js .bar__figure { opacity: 0; transform: translateY(0.5rem); transition: opacity var(--t-fade) var(--ease) var(--d, 0ms), transform var(--t-fade) var(--ease) var(--d, 0ms); }
.bars .bar:nth-child(1) { --d: 0ms; }
.bars .bar:nth-child(2) { --d: 140ms; }
.bars .bar:nth-child(3) { --d: 280ms; }
.kc-js .bars.is-in .bar__fill { transform: scaleX(1); }
.kc-js .bars.is-in .bar__figure { opacity: 1; transform: translateY(0); }

/* -------------------------------------------------------- 10. the hover -- */

/* The button fills rather than fades: the same wipe as a rule drawing. */
.btn { position: relative; overflow: hidden; z-index: 0; background: transparent; border-color: var(--cream); color: var(--ink); }
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--cream);
  transform: scaleX(1);
  transform-origin: left center;
  transition: transform 480ms var(--ease);
}
.btn:hover { color: var(--cream); background: transparent; }
.btn:hover::before { transform: scaleX(0); transform-origin: right center; }

.nav__link { position: relative; border-bottom-color: transparent; }
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--copper-light);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 380ms var(--ease);
}
.nav__link:hover::after,
.nav__link[aria-current="page"]::after { transform: scaleX(1); transform-origin: left center; }
.nav__link[aria-current="page"] { color: var(--cream); }

.link { position: relative; border-bottom-color: transparent; }
.link::before, .link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
}
.link::after { transform: scaleX(0); transform-origin: right center; transition: transform 420ms var(--ease); }
.link:hover::before { opacity: 0; }
.link:hover::after { transform: scaleX(1); transform-origin: left center; }

.contact__line a, .footer__contact a, .footer__nav a { position: relative; border-bottom-color: transparent; }
.contact__line a::after, .footer__contact a::after, .footer__nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 1px;
  background: var(--copper-light);
  transform-origin: left center;
  transition: transform 380ms var(--ease);
}
.contact__line a::after { transform: scaleX(1); }
.contact__line a:hover::after { transform: scaleX(0); transform-origin: right center; }
.footer__contact a::after, .footer__nav a::after { transform: scaleX(0); transform-origin: right center; }
.footer__contact a:hover::after, .footer__nav a:hover::after { transform: scaleX(1); transform-origin: left center; }

/* -------------------------------------------------- 11. page transition -- */

@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation: vt-out 300ms var(--ease-io) both; }
  ::view-transition-new(root) { animation: vt-in 520ms var(--ease) both; }
  @keyframes vt-out { to { opacity: 0; transform: translateY(-1.1rem); } }
  @keyframes vt-in { from { opacity: 0; transform: translateY(1.6rem); } }
}

/* -------------------------------------------------------- 12. scroll cue -- */

.cue {
  position: absolute;
  left: var(--gutter);
  bottom: 2.1rem;
  display: flex;
  align-items: center;
  gap: 0.85rem;
  font-family: var(--sans);
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--dim-text);
}
.kc-js .cue { opacity: 0; transition: opacity var(--t-fade) var(--ease) 700ms; }
.kc-js .cue.is-in { opacity: 1; }
.cue__line { display: block; width: 3.25rem; height: 1px; background: var(--copper-light); transform-origin: left center; }
@media (prefers-reduced-motion: no-preference) {
  .cue.is-in .cue__line { animation: cue-sweep 2800ms var(--ease-io) infinite; }
  @keyframes cue-sweep {
    0%, 100% { transform: scaleX(0.3); opacity: 0.45; }
    50%      { transform: scaleX(1); opacity: 1; }
  }
}
@media (max-width: 56rem) { .cue { display: none; } }

/* --------------------------------------------------- 13. reduced motion -- */

@media (prefers-reduced-motion: reduce) {
  .kc-js .lines .wi { transform: none; transition: none; }
  .w { overflow: visible; padding-bottom: 0; margin-bottom: 0; }
  .kc-js .col::after, .kc-js .closer::before, .kc-js .stat::after,
  .kc-js .pull::before, .kc-js .refused::before, .kc-js .split::before,
  .kc-js .state::after, .kc-js .clients__group::after, .kc-js .price::before,
  .kc-js .footer__top::after, .kc-js .contact__grid::before,
  .kc-js .marker__rule, .kc-js .bar__fill, .kc-js .ticks li::before,
  .btn::before, .contact__line a::after { transform: scaleX(1); transition: none; }
  .kc-js .col::before { transform: scaleY(1); transition: none; }
  .kc-js .plate__img { transform: none; animation: none; transition: none; }
  .curtain { display: none; }
  .cue.is-in .cue__line { animation: none; transform: scaleX(1); }
  .kc-js .col, .kc-js .stat__figure, .kc-js .stat__line, .kc-js .standfirst,
  .kc-js .body, .kc-js .source, .kc-js .hero__sub, .kc-js .hero__cta,
  .kc-js .statement__body, .kc-js .contact__body, .kc-js .contact__note,
  .kc-js .contact__line, .kc-js .contact__meta, .kc-js .clients__names,
  .kc-js .refused__body, .kc-js .footer__col, .kc-js .footer__base,
  .kc-js .ticks li, .kc-js .fourth__body, .kc-js .fatigue__note,
  .kc-js .marker__n, .kc-js .marker__label, .kc-js .matrix__step,
  .kc-js .bar__figure, .kc-js .cue,
  .kc-js .wash, .kc-js .wash-inflow { opacity: 1; transform: none; transition: none; }
}

/* ------------------------------------------------------- 14. the pivot -- */

/* One word per headline is set in italic: the word the sentence turns on.
   Caladea has a true bold italic, so this is a real cut and not a slant. */

.hero__headline em,
.headline em,
.statement__text em,
.contact__statement em,
.closer em {
  font-style: italic;
  font-weight: 700;
}
/* punctuation handed to an italic word keeps its own upright cut */
em .roman { font-style: normal; }

/* ------------------------------------------------- 15. the filament field -- */

/* The page ground is ink and the field is painted on it. Paper sections paint
   over the field; ink sections leave it showing. Nothing here is interactive
   and nothing here is content, so it is inert to pointers and to assistive
   technology alike. */

body { background: var(--ink); }

.field {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  /* Not 100%. A fixed element sized as a percentage follows the address bar on
     a phone, so the box grows and shrinks while the reader scrolls, and the
     canvas inside it is rebuilt each time. lvh is the viewport as if the bar
     were already hidden, which is a constant: the box stops moving, and the
     resize handler has nothing left to react to. 100vh is the fallback, and on
     most mobile browsers it already means the same thing. */
  height: 100vh;
  height: 100lvh;
  pointer-events: none;
}

main, .footer, .contact { position: relative; z-index: 1; }
.footer, .contact { background: transparent; }

/* The plates sit just off full opacity so the field carries through the
   photograph rather than stopping dead at its edge. */
.plate { background-color: transparent; }
.plate__img { opacity: 0.86; }
.hero .plate__img { opacity: 0.8; }

/* the relit point lights sit on the photograph, under the type */
.plate__glow {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* ------------------------------------------- 16. letting the light through -- */

/* The plates carry a navy scrim baked into their left half, which is what lets
   type sit on solid colour. That same scrim was also sealing the field out.
   A horizontal mask drops the plate away over the type side, so the light runs
   behind the words and the photograph still owns the other half. The seam
   falls inside the baked ramp, so there is nothing to see where they meet. */

@media (min-width: 56rem) {
  .hero .plate__img,
  .statement .plate__img,
  .hero .plate__glow,
  .statement .plate__glow {
    -webkit-mask-image: linear-gradient(to right, transparent 0%, transparent 16%, #000 46%, #000 100%);
    mask-image: linear-gradient(to right, transparent 0%, transparent 16%, #000 46%, #000 100%);
  }
  .hero .plate__img { opacity: 0.92; }
}

/* A standing photograph gets a column, not a crop.

   The rule above hands the plate the whole width and fades it out over the
   type. That suits a landscape frame, and it destroys a portrait one: at hero
   proportions `cover` throws away two thirds of the height, which on this
   photograph is the whole subject. Given a band of its own it keeps its
   proportions, and the soft left edge keeps it from reading as a rectangle
   pasted onto the page. Slightly more than half the width, so it carries the
   frame the way the landing page does. Placed after the rule it overrides,
   because the two have the same specificity. */
@media (min-width: 56rem) {
  .hero--portrait .plate__img {
    top: 0;
    bottom: 0;
    left: auto;
    right: 0;
    width: min(54%, 46rem);
    background-size: cover;
    background-position: center;
    opacity: 0.95;
    -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 30%, #000 100%);
    mask-image: linear-gradient(to right, transparent 0%, #000 30%, #000 100%);
  }
}

/* On a narrow screen it is a band below the type like the others, but framed
   to fit rather than magnified: the rule for the landscape plates zooms to
   240% of the height, which on a standing frame lands inside one window. */
@media (max-width: 56rem) {
  .hero--portrait .plate__img {
    height: var(--band, 44vh);
    background-size: cover;
    background-position: center 45%;
  }
}

/* The nav rides on the hero until the reader leaves it, then takes a ground. */
.nav {
  background: transparent;
  border-bottom-color: transparent;
  transition: background-color 420ms var(--ease), border-color 420ms var(--ease);
}
.nav.is-stuck { background: var(--ink); border-bottom-color: var(--rule-dark); }

/* ------------------------------------------------------------ 17. the wash -- */

/* Paint sits under the text and inside the sheet, so it is cropped by the
   edge of the paper the way a real mark would be. */
.section { position: relative; overflow: hidden; }
.section > .wrap { position: relative; z-index: 1; }

/* The wash now covers its whole section and finds the gaps in the text for
   itself, so there is no corner to anchor it to and no mask to fade it with. */
/* Placed and sized by script, one canvas per mark rather than one per
   section, so `inset` must not stretch it back over the whole thing. */
.wash { position: absolute; inset: auto; z-index: 0; pointer-events: none; }

.kc-js .wash { opacity: 0; transition: opacity 1400ms var(--ease); }

/* The narrow-screen paint. Block level, off to one side, with real air round
   it: on a phone this is the only thing standing between two thousand pixels
   of type and the next two thousand, so it is given the room a picture gets
   rather than the room a flourish gets. */
.wash-inflow {
  margin: 2.75rem 0;
  display: flex;
  justify-content: flex-start;
}
.wash-inflow--right { justify-content: flex-end; }
.wash-inflow canvas { display: block; }
.kc-js .wash-inflow { opacity: 0; transition: opacity 1400ms var(--ease); }
.kc-js .wash-inflow.is-in { opacity: 1; }
.kc-js .wash-inflow.is-instant { transition: none; }
.kc-js .wash.is-in { opacity: 1; }

/* ------------------------------------------------------- 18. the apertures -- */

/* The navy blocks on the light sections are openings cut through the paper to
   the ground underneath, not boxes painted navy. The branches carry on growing
   behind them. The ink background stays as the floor, so a browser without
   script still gets a solid block rather than a hole. */

.aperture { position: relative; overflow: hidden; }
.aperture > * { position: relative; z-index: 1; }

.aperture__view {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* A passe-partout, set in from the edge the way a mount is. */
.aperture::after {
  content: "";
  position: absolute;
  inset: 0.85rem;
  z-index: 2;
  border: 1px solid var(--copper-light);
  opacity: 0.45;
  pointer-events: none;
}
@media (max-width: 46rem) { .aperture::after { inset: 0.55rem; } }

/* --------------------------------------------------- 19. the painting -- */

/* The masked canvas replaces the plain image once the strokes have loaded.
   Without script the photograph is simply shown square, which is a picture on
   a page and perfectly fine. */
.painting__canvas { display: block; width: 100%; height: auto; }
.kc-js .painting__canvas { opacity: 0; transition: opacity 1200ms var(--ease); }
.kc-js .painting.is-in .painting__canvas { opacity: 1; }
