/* ==========================================================================
   Self-hosted fonts. GENERATED by scripts/fetch-fonts.sh — do not edit.
   Served when local_fonts: true in _config.yml.
   ========================================================================== */
/* latin-ext */
@font-face {
  font-family: 'Instrument Sans';
  font-style: italic;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxigypc9vsFDm051Uf6KVwgkfoSbSnNPooZAN0lInHGpCWNE27lgU-XJojENuu-2oyAH297Y.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;
}
/* latin */
@font-face {
  font-family: 'Instrument Sans';
  font-style: italic;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxigypc9vsFDm051Uf6KVwgkfoSbSnNPooZAN0lInHGpCWNE27lgU-XJojENuu-2oy4H2w.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;
}
/* latin-ext */
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxiTypc9vsFDm051Uf6KVwgkfoSxQ0GsQv8ToedPibnr0She1YmV.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;
}
/* latin */
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxiTypc9vsFDm051Uf6KVwgkfoSxQ0GsQv8ToedPibnr0SZe1Q.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;
}
/* latin-ext */
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxiTypc9vsFDm051Uf6KVwgkfoSxQ0GsQv8ToedPibnr0She1YmV.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;
}
/* latin */
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxiTypc9vsFDm051Uf6KVwgkfoSxQ0GsQv8ToedPibnr0SZe1Q.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;
}
/* latin-ext */
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxiTypc9vsFDm051Uf6KVwgkfoSxQ0GsQv8ToedPibnr0She1YmV.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;
}
/* latin */
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url(/assets/fonts/pxiTypc9vsFDm051Uf6KVwgkfoSxQ0GsQv8ToedPibnr0SZe1Q.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;
}
/* latin-ext */
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/jizHRFtNs2ka5fXjeivQ4LroWlx-6zAjgn7MsNo.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;
}
/* latin */
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/jizHRFtNs2ka5fXjeivQ4LroWlx-6zAjjH7M.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;
}
/* latin-ext */
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/jizBRFtNs2ka5fXjeivQ4LroWlx-6zsTjmbI.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;
}
/* latin */
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/jizBRFtNs2ka5fXjeivQ4LroWlx-6zUTjg.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   Tokens
   Every colour, typeface, space and easing used on the site. Nothing else in
   the codebase should contain a raw hex value or a hard-coded typeface.
   ========================================================================== */

:root{
  /* --- Surfaces: the strata, lightest at the top of the core sample ------ */
  --c-surface-1:#F8F6F2;   /* nav band, first section                       */
  --c-surface-2:#F1EEE7;   /* hero band, alternate section                  */
  --c-surface-3:#E8E3D9;   /* hero base band                                */
  --c-line:#DCD6C9;        /* hairline between strata, list rules           */

  /* --- Ink -------------------------------------------------------------- */
  --c-ink:#14151A;         /* headings, primary text, bedrock background    */
  --c-ink-muted:#6B675D;   /* body copy, nav links                          */
  --c-ink-faint:#948F83;   /* micro labels, credential                      */

  /* --- Accent and hardware ---------------------------------------------- */
  --c-accent:#2E82FF;      /* brand blue. Rules and dots only, never text.  */
  --c-slate:#5A5E66;       /* datum marker disc                             */

  /* --- Reversed: bedrock sections and the footer ------------------------- */
  --c-inv-ink:rgba(241,238,231,1);
  --c-inv-muted:rgba(241,238,231,.68);
  --c-inv-faint:rgba(241,238,231,.58);
  --c-inv-line:rgba(241,238,231,.17);

  /* --- Type ------------------------------------------------------------- */
  --font-display:"Instrument Serif", Georgia, "Times New Roman", serif;
  --font-sans:"Instrument Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* --- Space ------------------------------------------------------------ */
  --gutter:clamp(20px, 4.4vw, 58px);   /* page side padding                 */
  --measure:1200px;                    /* max content width                 */
  --band:clamp(66px, 10.5vh, 124px);   /* vertical padding of a section     */
  --datum-size:clamp(28px, 2.5vw, 34px);

  /* Distance from the viewport edge to the content edge. Used to hang the
     datum marker on the same vertical line as the content. */
  --rail:max(var(--gutter), calc((100vw - var(--measure)) / 2 + var(--gutter)));

  /* --- Motion ----------------------------------------------------------- */
  --ease:cubic-bezier(.2,.7,.2,1);        /* hover and micro-interaction    */
  --ease-out:cubic-bezier(.16,.84,.3,1);  /* entrances                      */
}

@media (max-width:880px){
  :root{ --datum-size:28px; }
}

/* ==========================================================================
   Base
   Document defaults and accessibility. No component styling lives here.
   ========================================================================== */

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

html{
  -webkit-text-size-adjust:100%;   /* stop iOS inflating type in landscape */
}

html,body{ margin:0; padding:0; }

/* Flex column so a page shorter than the viewport still puts the footer on
   the bottom edge, instead of ending early and leaving a band of body surface
   below it. .site-footer takes margin-top:auto to claim the slack. Safe for
   the fold, which is sized by its own content and never by viewport height,
   so there is nothing here for flex to shrink. dvh second: browsers that have
   it use it, and it survives the mobile toolbar collapsing. */
body{
  display:flex;
  flex-direction:column;
  min-height:100vh;
  min-height:100dvh;
  background:var(--c-surface-1);
  color:var(--c-ink);
  font-family:var(--font-sans);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  -webkit-tap-highlight-color:rgba(46,130,255,.14);
  overflow-wrap:break-word;
}

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

h1,h2,h3,h4{ margin:0; font-weight:400; }

/* --- Focus ------------------------------------------------------------- */
a:focus-visible,
button:focus-visible{
  outline:2px solid var(--c-accent);
  outline-offset:4px;
  border-radius:2px;
}
/* On reversed surfaces the accent is too close to the background */
.stratum--bedrock a:focus-visible,
.site-footer a:focus-visible{ outline-color:#7DB0FF; }

/* --- Skip link --------------------------------------------------------- */
.skip-link{
  position:absolute; left:-9999px; top:0; z-index:20;
  background:var(--c-ink); color:var(--c-surface-1);
  padding:12px 18px; text-decoration:none; font-size:14px;
}
.skip-link:focus{ left:var(--gutter); top:12px; }

/* --- Motion preferences -------------------------------------------------
   The prefers-reduced-motion overrides live at the foot of utilities.css,
   after the animations they switch off. Source order matters there.
   ------------------------------------------------------------------------ */

/* ==========================================================================
   Typography objects
   Three roles, and only three. Display serif, body sans, micro label.
   Anything that needs a fourth role probably needs rethinking instead.
   ========================================================================== */

/* --- Display: the serif. Section-opening statements. -------------------- */
.lede{
  font-family:var(--font-display);
  font-weight:400;
  font-size:clamp(1.42rem, 2.62vw, 2.28rem);
  line-height:1.16;
  letter-spacing:-.015em;
  margin:0;
  max-width:20ch;
  text-wrap:pretty;
}
.lede--tight{ max-width:19ch; }              /* longer lines, same size     */

/* The closing question, and nothing else. It is larger than a section lede
   because the closing stratum is a single column with no body copy in it:
   the question and the button are the whole block, so the type carries the
   weight that a right-hand column used to. Sized to break the default
   question over two lines on a desktop. If it ever wraps to four, the
   question is too long for the block rather than the block being too small
   for the question. */
.lede--lg{
  font-size:clamp(1.9rem, 4.6vw, 3.6rem);
  line-height:1.04;
  max-width:15ch;
}

/* --- Body: running prose ------------------------------------------------ */
.prose{ max-width:56ch; }
.prose--narrow{ max-width:50ch; }
.prose p{
  margin:0 0 18px;
  font-size:clamp(15.5px, 1.1vw, 17px);
  line-height:1.65;
  color:var(--c-ink-muted);
}
.prose p:last-child{ margin-bottom:0; }
.prose strong{ color:var(--c-ink); font-weight:600; }

/* --- Micro label: eyebrows, credentials, jump links --------------------- */
.label{
  font-size:clamp(11px, .85vw, 12px);
  letter-spacing:.19em;
  text-transform:uppercase;
  font-weight:500;
  line-height:1.5;
  color:var(--c-ink-faint);
}

@media (max-width:880px){
  .lede{ max-width:26ch; }
  .lede--tight{ max-width:24ch; }
  .lede--lg{ max-width:18ch; }
}
@media (max-width:480px){
  .label{ letter-spacing:.14em; }   /* stop long labels overflowing */
}

/* ==========================================================================
   Layout
   The page scaffolding. Sections are strata: horizontal bands of the core
   sample, descending from palest at the top to bedrock at the bottom.
   ========================================================================== */

/* --- Content rail -------------------------------------------------------- */
.wrap{
  width:100%;
  max-width:var(--measure);
  margin-inline:auto;
  padding-inline:
    max(var(--gutter), env(safe-area-inset-left))
    max(var(--gutter), env(safe-area-inset-right));
}

/* --- Stratum: one full-width section ------------------------------------ */
.stratum{ position:relative; }
.stratum__inner{ padding-block:var(--band); }

.stratum--pale{    background:var(--c-surface-1); border-top:1px solid var(--c-line); }
.stratum--warm{    background:var(--c-surface-2); border-top:1px solid var(--c-line); }
.stratum--bedrock{ background:var(--c-ink); color:var(--c-inv-ink); }

/* Reversed type inside the bedrock stratum */
.stratum--bedrock .lede{ color:var(--c-inv-ink); }
.stratum--bedrock .prose p{ color:var(--c-inv-muted); }
.stratum--bedrock .prose strong{ color:var(--c-inv-ink); }

/* --- Duo: the asymmetric two-column reading grid ------------------------ */
.duo{
  display:grid;
  grid-template-columns:minmax(0,1.02fr) minmax(0,1fr);
  gap:clamp(28px, 5vw, 80px);
  align-items:start;
}

@media (max-width:880px){
  .duo{ grid-template-columns:1fr; gap:30px; }
}

/* ==========================================================================
   Site header
   Used on every page. On narrow screens the brand and the call to action
   hold the first row and the section links wrap onto a second row, so no
   navigation is hidden and no JavaScript is needed to reach it.
   ========================================================================== */

.site-header{
  background:var(--c-surface-1);
  border-bottom:1px solid var(--c-line);
}
.site-header__inner{
  display:flex;
  align-items:center;
  gap:clamp(18px, 2.6vw, 38px);
  padding-block:clamp(20px, 2.6vw, 30px);
}

.brand{ display:block; margin-right:auto; }
.brand img{ height:clamp(19px, 1.95vw, 24px); width:auto; display:block; }

.site-nav{ display:flex; align-items:center; gap:clamp(18px, 2.6vw, 38px); }

.site-nav__link{
  position:relative;
  font-size:15px;
  color:var(--c-ink-muted);
  text-decoration:none;
  padding:6px 0;
}
.site-nav__link::after{
  content:""; position:absolute; left:0; right:0; bottom:2px; height:1px;
  background:var(--c-ink);
  transform:scaleX(0); transform-origin:left;
  transition:transform .3s var(--ease);
}
.site-nav__link:hover{ color:var(--c-ink); }
.site-nav__link:hover::after{ transform:scaleX(1); }

/* Current page marker. Add aria-current="page" in the markup. */
.site-nav__link[aria-current="page"]{ color:var(--c-ink); }
.site-nav__link[aria-current="page"]::after{ transform:scaleX(1); background:var(--c-line); }

.site-nav__cta{
  display:inline-flex; align-items:center; gap:9px;
  color:var(--c-ink); font-weight:500; text-decoration:none;
}

@media (max-width:880px){
  .site-header__inner{ flex-wrap:wrap; row-gap:4px; }
  .site-nav{ order:3; width:100%; gap:22px; }
  .site-nav__link{ padding:11px 0; }   /* 44px touch target */
}

/* On a phone the section links go, and the header is one row: brand left,
   call to action right. A visitor who has just arrived has no use for them,
   and the second row cost 45px of a 764px screen. Nothing becomes
   unreachable — the footer carries every one of these links, plus the CRA
   factsheet — so the no-hidden-navigation rule above still holds; the links
   sit at the end of the document rather than behind a control. */
@media (max-width:480px){
  .site-nav{ display:none; }
}

/* The one-row header only holds while the brand and the call to action fit
   a line together. Below about 360px they stop fitting and the call to
   action drops to a row of its own. Buying back roughly 20px here keeps it
   to one row on every phone still in use. */
@media (max-width:400px){
  .site-header__inner{ gap:12px; }
  .site-nav__cta{ font-size:14px; }
}

/* ==========================================================================
   Fold — homepage only
   Three stacked strata: header band, hero band, base band. The hero band is
   sized by its own content plus deliberate air, never by viewport height, so
   the composition is identical on a phone and on a 27in display.
   ========================================================================== */

.fold{ display:flex; flex-direction:column; }

/* --- Hero band ---------------------------------------------------------- */
.fold__hero{
  position:relative;
  background:var(--c-surface-2);
  border-bottom:1px solid var(--c-line);
}
.fold__hero-inner{
  padding-top:clamp(58px, 10.5vh, 124px);
  padding-bottom:clamp(38px, 5.6vh, 62px);
}

/* Headline left, outcome right, both sitting on the same bottom line. The
   outcome's hairline hugs its own text rather than spanning to the top of the
   headline, so it never reads as a rule floating on its own. */
.fold__lockup{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,.42fr);
  gap:clamp(30px, 4.4vw, 72px);
  align-items:end;
}

/* The floor governs everything below about 925px, so raising it is a
   narrow-screen change only — desktop still runs off the 6.05vw term. A phone
   viewport is small enough that the title needs to be proportionally larger
   there, not smaller, if it is to hold the screen on its own. 3.5rem is the
   ceiling before "team can prove." stops fitting one line at 390px. */
.fold__title{
  font-family:var(--font-display);
  font-weight:400;
  font-size:clamp(3.5rem, 6.05vw, 5.6rem);
  line-height:.955;
  letter-spacing:-.019em;
  margin:0;
}

.fold__outcome{
  align-self:end;
  margin:0;
  padding-top:clamp(14px, 1.8vh, 18px);
  border-top:1px solid var(--c-line);
  max-width:34ch;
  font-size:clamp(15.5px, 1.2vw, 18px);
  line-height:1.5;
  letter-spacing:-.004em;
  color:var(--c-ink);
}

/* --- Base band ---------------------------------------------------------- */
/* The band's job is to end the hero panel, not to hold anything. Once that is
   accepted it does not need contents, it needs the right height: 11px between
   the hero's hairline and the next stratum's keeps the layered look and
   removes the empty-content problem entirely. Do not put text in here — text
   needs height, and height is what turned this band into a void in the first
   place. If it ever has to carry something, it stops being a step and the
   whole composition has to be rethought rather than the height nudged. */
.fold__base{
  position:relative;
  background:var(--c-surface-3);
  height:11px;
}

/* The disc centres on the band rather than sitting on its top edge. At this
   height an edge-anchored disc would clear the hero hairline by 14px and
   overhang the next stratum's by 3, which reads as a misalignment; centred,
   it straddles both symmetrically and pins the seam. */
.fold__base .datum{ top:50%; }

@media (max-width:880px){
  .fold__break{ display:none; }          /* let the headline wrap naturally */
  .fold__lockup{ grid-template-columns:1fr; gap:clamp(24px, 3.4vh, 32px); }
  .fold__outcome{ max-width:38ch; padding-top:clamp(18px, 2.4vh, 24px); }

  /* Once the outcome drops beneath the title, nothing sits to the side of the
     title any more, so the hero reads as a symmetrical block and its padding
     equalises to match. The base band needs no narrow-screen treatment now
     that it is a fixed step: 11px costs the fold nothing on a phone and the
     layered look survives at every width. */
  .fold__hero-inner{ padding-block:clamp(58px, 10.5vh, 124px); }
}

@media (max-width:480px){
  /* Dropping the nav row returns about 100px. Left alone it would simply pull
     the section below into view, which is what made the fold feel busy in the
     first place — so the hero absorbs it rather than the page scrolling up.
     The boundary then lands near the foot of the screen and the lede beneath
     it is left half-covered by the browser chrome: enough to say there is
     more, not enough to read as a second headline. */
  .fold__hero-inner{ padding-block:clamp(72px, 13vh, 124px); }
}

/* ==========================================================================
   Cycle — the swapping word in the fold headline
   --------------------------------------------------------------------------
   "Security your team can prove." where the last word alternates: prove,
   trust. The intent is a display refreshing rather than a carousel, so the
   outgoing word flickers twice before it goes, and both words travel the same
   direction — out through the top, in from below — which reads as one line of
   type being replaced rather than two words taking turns.

   The first word carries three jobs at once, which is why "prove" appears in
   the markup exactly once:
   - it is the accessible text. Every word after it is aria-hidden, so a
     screen reader reads the headline as "Security your team can prove." and
     is not told about a decorative loop it cannot see.
   - it stays in flow while the others are taken out of it, so the span has a
     width and a baseline without an invisible copy holding the box open.
   - it is the visible word at rest.

   Progressive enhancement:
   - No JavaScript: the first word is in flow and marked .is-active, so the
     headline is simply static and correctly sized.
   - Reduced motion: js/cycle.js bails before the first swap, same result.

   Sizing. With JS the width becomes an explicit measurement per word and
   transitions between them, so the full stop tracks the word rather than
   leaving a gap after the shorter one. The first word then overflows the box
   whenever a shorter word is active, which is invisible because it is also at
   opacity 0 by then.
   ========================================================================== */

.cycle{
  position:relative;
  display:inline-block;
  vertical-align:baseline;
  white-space:nowrap;
}

/* Measured in js/cycle.js. Unset until then, so the sizer governs. */
.js .cycle{
  width:var(--cycle-w, auto);
  transition:width .52s var(--ease);
}

/* Resting state is the incoming state: sitting just low, invisible. A word
   becomes .is-active to rise into place, then .is-leaving to carry on up and
   out, then drops back to this state with the transition suppressed.

   inline-block matters: transforms do not apply to non-replaced inline
   elements, so the in-flow first word would not move without it. Its baseline
   is its own text baseline, so it still sits on the headline's line. */
.cycle__word{
  position:absolute;
  left:0; top:0;
  display:inline-block;
  opacity:0;
  transform:translateY(.17em);
  transition:opacity .44s var(--ease-out), transform .44s var(--ease-out);
}

/* The first word only. Left in flow to give the span its width and baseline;
   transform and opacity do not affect layout, so it can animate like any
   other while still holding the box. Order-dependent by design — a new word
   goes after it, never before. */
.cycle__word:first-child{ position:static; }
.cycle__word.is-active{ opacity:1; transform:none; }
.cycle__word.is-leaving{ opacity:0; transform:translateY(-.15em); }

/* Rearming after an exit. Instant, and behind opacity:0 either way. */
.cycle__word.is-reset{ transition:none; }

/* The flicker. Two dips, the second running straight into the exit rather
   than returning to full — two transitions of luminance over 300ms on a
   handful of characters, which keeps it well inside flash guidance while
   still reading as a panel refreshing. */
.cycle__word.is-flicker{ animation:cycle-flicker .3s steps(1, end) 1; }
@keyframes cycle-flicker{
  0%,  100%{ opacity:1; }
  16%, 54%{  opacity:.34; }
  32%, 70%{  opacity:1; }
}

/* The one techno tell: a hairline that wipes across the word and off again as
   it changes. Accent blue, which the system reserves for rules and dots and
   never for type, so the rule stands. Present for well under a second and
   only during a swap. */
.cycle__scan{
  position:absolute;
  left:0; right:0; bottom:-.055em;
  height:1px;
  background:var(--c-accent);
  opacity:0;
  transform:scaleX(0);
  transform-origin:0 50%;
}
.cycle.is-swapping .cycle__scan{ animation:cycle-scan .8s var(--ease) 1; }
@keyframes cycle-scan{
  0%{   opacity:0;   transform:scaleX(0); transform-origin:0 50%; }
  20%{  opacity:.5; }
  46%{  opacity:.5;  transform:scaleX(1); transform-origin:0 50%; }
  47%{  opacity:.5;  transform:scaleX(1); transform-origin:100% 50%; }
  100%{ opacity:0;   transform:scaleX(0); transform-origin:100% 50%; }
}

@media (prefers-reduced-motion:reduce){
  .js .cycle{ transition:none; }
  .cycle__word{ transition:none; }
  .cycle__word.is-flicker{ animation:none; }
  .cycle.is-swapping .cycle__scan{ animation:none; }
}

/* ==========================================================================
   Page head — inner pages
   The fold's quieter sibling for services, about, writing and article pages.
   Same strata logic, one column, no outcome line.
   ========================================================================== */

.page-head{
  background:var(--c-surface-2);
  border-bottom:1px solid var(--c-line);
}
.page-head__inner{
  padding-top:clamp(48px, 8vh, 96px);
  padding-bottom:clamp(38px, 5.6vh, 62px);
}
.page-head__title{
  font-family:var(--font-display);
  font-weight:400;
  font-size:clamp(2.1rem, 4.6vw, 4rem);
  line-height:1.02;
  letter-spacing:-.017em;
  margin:0;
  max-width:18ch;
}
.page-head__standfirst,
.page-actions__note{
  margin:clamp(20px, 3vh, 30px) 0 0;
  max-width:52ch;
  font-size:clamp(15.5px, 1.2vw, 18px);
  line-height:1.55;
  color:var(--c-ink-muted);
}

/* --- Merged action block -------------------------------------------------
   A page with one action and nothing else to say reads as thin when the head
   and a stratum below it repeat the same eyebrow-and-lede shape with a grid
   built for two columns of substance. /contact/ instead draws the two as one
   block: the head drops its hairline and bottom padding, and .page-actions
   continues the same surface underneath. Opt in with head_flush: true in the
   page's front matter.

   The action block stays inside <main> rather than being injected into the
   head, so the main landmark is not left empty.
   ------------------------------------------------------------------------ */
.page-head--flush{ border-bottom:0; }
.page-head--flush .page-head__inner{ padding-bottom:0; }

.page-actions{ background:var(--c-surface-2); }
.page-actions__inner{
  /* Padding, not the note's own margin. With padding-top:0 there is nothing
     to stop that margin collapsing out through the top of this box, which
     drags .page-actions down and shows a pale stripe of body surface across
     the middle of what is supposed to read as one block. */
  padding-top:clamp(26px, 3.6vh, 36px);
  padding-bottom:clamp(56px, 9vh, 104px);
}
.page-actions__note{ margin-top:0; }

/* ==========================================================================
   Eyebrow
   Blue rule above a micro label. Marks the start of a section or a page.
   Pair with .label for the type: <p class="eyebrow label">What I do</p>
   ========================================================================== */

.eyebrow{ display:block; margin:0 0 clamp(16px, 2.2vh, 22px); }
.eyebrow::before{
  content:"";
  display:block;
  width:28px; height:2px;
  background:var(--c-accent);
  margin-bottom:13px;
}

/* Slightly more air when it opens a page rather than a section */
.eyebrow--lead{ margin-bottom:clamp(20px, 3vh, 32px); }
.eyebrow--lead::before{ margin-bottom:14px; }

/* On a phone the lead eyebrow is long enough to take two lines, which turns a
   label into a paragraph and sets it competing with the title beneath it.
   Tighter tracking holds it to one line on a 390px screen. */
@media (max-width:480px){
  .eyebrow--lead{ letter-spacing:.1em; }
}

/* ==========================================================================
   Byline
   The author credit that closes the article page head.

   Design notes, because this component is easy to get wrong:

   1. It is a credit, not a card. The page head opens with a micro label
      (WRITING · DATE) and now closes with one, so the title block is framed
      top and bottom by the same voice. The name therefore takes .label, not
      a fourth type role invented for it.
   2. The portrait is the only photographic object on a flat tonal page, so
      its chroma is pulled back slightly at the asset level to sit inside the
      warm neutral palette. Slightly. Take it much below 0.85 and the face
      reads as greyed out rather than composed.
   3. The disc is 48px. Below about 44 the features collapse into mush at
      this crop; much above 56 it stops reading as metadata and starts
      reading as a widget.
   4. Hover follows .jump-link exactly: faint to ink, transparent hairline to
      --c-line. One interaction idiom for every micro-label link on the site.
   ========================================================================== */

.byline{
  display:flex;
  align-items:center;
  gap:14px;
  /* Tight to the standfirst it credits. This is a caption relationship, not
     a new section. */
  margin:clamp(20px, 2.4vh, 26px) 0 0;
}

/* The page head closes up under the byline. The disc carries the weight that
   a run of padding would otherwise have to. */
.page-head__inner--byline{
  padding-bottom:clamp(26px, 3.4vh, 38px);
}

.byline__portrait{
  width:48px; height:48px; flex:none;
  border-radius:50%;
  object-fit:cover;
  background:var(--c-surface-3);
  /* Inset, so the hairline sits inside the 40px rather than growing it, and
     so the photograph's edge meets the band through the same line weight
     used between strata. */
  box-shadow:inset 0 0 0 1px rgba(20,21,26,.09);
}

.byline__name{
  color:var(--c-ink-muted);
  text-decoration:none;
  padding-bottom:4px;
  border-bottom:1px solid transparent;
  transition:color .3s var(--ease), border-color .3s var(--ease);
}
a.byline__name:hover,
a.byline__name:focus-visible{
  color:var(--c-ink);
  border-bottom-color:var(--c-line);
}

/* Reversed surfaces, should the byline ever sit on bedrock. */
.stratum--bedrock .byline__name,
.site-footer .byline__name{ color:var(--c-inv-muted); }
.stratum--bedrock a.byline__name:hover,
.site-footer a.byline__name:hover{ color:var(--c-inv-ink); border-bottom-color:var(--c-inv-line); }
.stratum--bedrock .byline__portrait,
.site-footer .byline__portrait{ box-shadow:inset 0 0 0 1px rgba(241,238,231,.2); }

@media (max-width:560px){
  .byline{ gap:12px; }
  .byline__portrait{ width:44px; height:44px; }
}

/* ==========================================================================
   Portrait
   The photograph on the About page. The byline disc is metadata; this is the
   thing itself, and the only large photographic object on the site.

   Design notes:

   1. Square-cornered, not a disc. At 48px a circle reads as an avatar; at
      500px it reads as a profile widget from a different website. The
      rectangle sits in the strata grid the way every other block does.
   2. 4:5. Taller than the crop feels natural for a face, which is the point
      — the extra height gives the figure room and stops the block sitting
      like a passport photo pasted into the column.
   3. Chroma is pulled back at the asset level, matching the byline. The
      hairline is the same inset trick for the same reason: the photograph
      meets the band through the line weight used between strata.
   4. It caps out well short of the column. A portrait that fills the grid
      column is a hero image, and this page is not making that claim.
   ========================================================================== */

.portrait{
  display:block;
  width:100%;
  max-width:340px;
  aspect-ratio:4/5;
  object-fit:cover;
  border-radius:2px;
  background:var(--c-surface-3);
  box-shadow:inset 0 0 0 1px rgba(20,21,26,.09);
}

/* The caption under the portrait: name and where. Micro-label voice, so it
   shares the type role with the eyebrow above it rather than inventing a
   fourth. */
.portrait__caption{
  margin:14px 0 0;
  max-width:340px;
}

@media (max-width:880px){
  /* On one column the portrait leads the block, so it loses the width it
     was holding against a neighbouring column and takes a size that reads
     as a person rather than a banner. */
  .portrait{ max-width:210px; }
  .portrait__caption{ max-width:210px; }
}

/* ==========================================================================
   Testimonial
   One quotation, attributed to a named person at a named company. There is
   no plural version of this component on purpose: a carousel of three is a
   marketing device, and one verifiable name does more work than three
   unverifiable ones.

   Design notes:

   1. No box, no card, no quotation marks set as decoration. The quote is
      lifted out of the flow by a single accent rule on the leading edge —
      the one place on the site the brand blue is allowed to be a rule.
   2. The quote takes the display serif at .lede scale but a longer measure,
      because it is someone speaking rather than a section opening.
   3. Attribution is the micro label, so the block is framed in the same
      voice as every other piece of metadata on the site.
   4. Reversed variant included because this may one day sit on bedrock.

   Markup:
   <figure class="testimonial">
     <blockquote class="testimonial__quote"><p>…</p></blockquote>
     <figcaption class="testimonial__source label">
       Name<span class="testimonial__role">Role, Company</span>
     </figcaption>
   </figure>
   ========================================================================== */

.testimonial{
  margin:clamp(30px, 4vh, 44px) 0 0;
  padding:2px 0 2px clamp(20px, 2.2vw, 30px);
  border-left:1px solid var(--c-accent);
  max-width:46ch;
}

.testimonial__quote{
  margin:0;
  font-family:var(--font-display);
  font-weight:400;
  font-size:clamp(1.16rem, 1.62vw, 1.44rem);
  line-height:1.28;
  letter-spacing:-.012em;
  color:var(--c-ink);
  text-wrap:pretty;
}
.testimonial__quote p{ margin:0 0 14px; }
.testimonial__quote p:last-child{ margin-bottom:0; }

.testimonial__source{
  margin:clamp(15px, 1.8vh, 19px) 0 0;
  color:var(--c-ink);
  display:flex;
  flex-direction:column;
  gap:3px;
}
/* The role drops to faint so the name carries, without a second type size. */
.testimonial__role{
  color:var(--c-ink-faint);
  text-transform:none;
  letter-spacing:.055em;
}

/* Reversed surfaces */
.stratum--bedrock .testimonial__quote{ color:var(--c-inv-ink); }
.stratum--bedrock .testimonial__source{ color:var(--c-inv-ink); }
.stratum--bedrock .testimonial__role{ color:var(--c-inv-faint); }

@media (max-width:880px){
  .testimonial{ max-width:none; }
}

/* ==========================================================================
   Datum marker
   The disc that straddles a stratum boundary, and the accent dot it shares a
   colour language with. The marker is decorative: keep aria-hidden on it.

   Its parent must be position:relative. Use sparingly. Two markers close
   together read as a rendering fault rather than a motif.
   ========================================================================== */

.datum{
  position:absolute; top:0; right:var(--rail); z-index:4;
  width:var(--datum-size); height:var(--datum-size);
  border-radius:50%;
  background:var(--c-slate);
  display:grid; place-items:center;
  transform:translateY(-50%);
  opacity:.88;
  pointer-events:none;
}
.datum svg{ width:56%; height:56%; display:block; }
.datum svg *{
  stroke:var(--c-surface-2);
  stroke-width:1.9;
  stroke-linecap:round;
  stroke-linejoin:round;
  fill:none;
}

/* On a bedrock boundary the disc sinks into the section below it */
.datum--sunken{ background:var(--c-ink); opacity:1; }

/* --- Accent dot --------------------------------------------------------- */
.dot{
  width:7px; height:7px;
  border-radius:50%;
  background:var(--c-accent);
  flex:none;
  display:inline-block;
}

/* ==========================================================================
   Rule list
   Hairline-ruled list with an accent dot. Deliberately unnumbered: the items
   are a set, not a sequence. If you ever need a real sequence, that is a
   different component.
   ========================================================================== */

.rule-list{
  list-style:none;
  margin:clamp(28px, 3.8vh, 42px) 0 0;
  padding:0;
  border-top:1px solid var(--c-line);
}
.rule-list__item{
  display:flex; align-items:flex-start; gap:14px;
  padding:clamp(13px, 1.7vh, 17px) 0;
  border-bottom:1px solid var(--c-line);
  font-size:clamp(15.5px, 1.14vw, 17.5px);
  line-height:1.38;
  color:var(--c-ink);
}
.rule-list__item .dot{ margin-top:.52em; }   /* optical alignment to the cap */

/* ==========================================================================
   Article card and grid
   Links to writing. The whole card is the link. On hover an accent rule
   draws left to right along the top edge.
   ========================================================================== */

.article-grid{
  display:grid;
  grid-template-columns:repeat(3, minmax(0,1fr));
  gap:clamp(26px, 3.4vw, 52px);
  margin-top:clamp(40px, 6vh, 68px);
}

.article-card{
  position:relative;
  display:block;
  text-decoration:none;
  color:inherit;
  border-top:1px solid var(--c-ink);
  padding-top:clamp(18px, 2.2vh, 24px);
}
.article-card::before{
  content:"";
  position:absolute; top:-1px; left:0; right:0; height:2px;
  background:var(--c-accent);
  transform:scaleX(0); transform-origin:left;
  transition:transform .5s var(--ease);
}
.article-card:hover::before,
.article-card:focus-visible::before{ transform:scaleX(1); }

.article-card__title{
  font-family:var(--font-display);
  font-weight:400;
  font-size:clamp(1.12rem, 1.46vw, 1.36rem);
  line-height:1.22;
  letter-spacing:-.008em;
  margin:0 0 12px;
  color:var(--c-ink);
}
.article-card__standfirst{
  margin:0;
  font-size:clamp(14.5px, 1.02vw, 15.5px);
  line-height:1.58;
  color:var(--c-ink-muted);
}

@media (max-width:880px){
  .article-grid{ grid-template-columns:1fr; gap:0; }
  .article-card{ padding-bottom:clamp(22px, 3vh, 28px); }
  .article-card:last-child{ padding-bottom:0; }
}

/* ==========================================================================
   Article prose
   Extensions to .prose for long-form Markdown bodies rendered by Jekyll.
   Headings are the sans, not the serif: the display face appears once per
   section, and on an article page that is the title in the page head.
   The accent blue stays out of text — links underline in the hairline
   colour and darken to ink on hover.
   ========================================================================== */

.prose h2,
.prose h3{
  font-family:var(--font-sans);
  font-weight:600;
  color:var(--c-ink);
  line-height:1.3;
  margin:34px 0 12px;
}
.prose h2{ font-size:clamp(17px, 1.3vw, 20px); }
.prose h3{ font-size:clamp(15.5px, 1.1vw, 17px); }
.prose h2:first-child{ margin-top:0; }

.prose ul,
.prose ol{
  margin:0 0 18px;
  padding-left:1.2em;
}
.prose li{
  margin:0 0 8px;
  font-size:clamp(15.5px, 1.1vw, 17px);
  line-height:1.65;
  color:var(--c-ink-muted);
}
.prose li::marker{ color:var(--c-ink-faint); }

.prose a a:not(.btn){
  color:var(--c-ink);
  text-decoration:underline;
  text-decoration-color:var(--c-line);
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  transition:text-decoration-color .3s var(--ease);
}
.prose a:not(.btn):hover,
.prose a:not(.btn):focus-visible{ text-decoration-color:var(--c-ink); }

.prose blockquote{
  margin:0 0 18px;
  padding-left:18px;
  border-left:2px solid var(--c-line);
}
.prose blockquote p{ color:var(--c-ink-faint); }

.prose code{
  font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size:.92em;
  background:var(--c-surface-2);
  padding:.1em .35em;
  border-radius:3px;
}
.prose pre{
  background:var(--c-surface-2);
  padding:16px 18px;
  overflow-x:auto;
  margin:0 0 18px;
}
.prose pre code{ background:none; padding:0; font-size:13px; line-height:1.6; }

.prose hr{
  border:0;
  border-top:1px solid var(--c-line);
  margin:34px 0;
}

/* ==========================================================================
   Links
   .link-arrow  section-closing link, body size, hairline underline
   .jump-link   micro-label link, used for in-page jumps
   ========================================================================== */

.link-arrow{
  display:inline-flex; align-items:center; gap:11px;
  font-size:15px; font-weight:500;
  color:var(--c-ink);
  text-decoration:none;
  padding-bottom:8px;
  border-bottom:1px solid var(--c-line);
  transition:border-color .35s var(--ease);
}
.link-arrow__arrow{ display:inline-block; transition:transform .35s var(--ease); }
.link-arrow:hover{ border-color:var(--c-ink); }
.link-arrow:hover .link-arrow__arrow{ transform:translateX(5px); }

.jump-link{
  display:inline-flex; align-items:center; gap:10px;
  color:var(--c-ink-faint);
  text-decoration:none;
  padding-bottom:5px;
  border-bottom:1px solid transparent;
  transition:color .3s var(--ease), border-color .3s var(--ease);
}
.jump-link .link-arrow__arrow{ transition:transform .35s var(--ease); }
.jump-link:hover{ color:var(--c-ink); border-bottom-color:var(--c-line); }
.jump-link:hover .link-arrow__arrow{ transform:translateY(3px); }

@media (max-width:480px){
  .jump-link{ margin-left:auto; }   /* stays right when the row wraps */
}

/* ==========================================================================
   Button
   One button style. It appears once per page, in the closing stratum.
   If a second, quieter action is ever needed, add a .btn--ghost modifier
   here rather than restyling this one in place.
   ========================================================================== */

.btn{
  display:inline-flex; align-items:center; gap:12px;
  padding:15px 25px 15px 22px;
  border-radius:2px;
  background:var(--c-surface-1);
  color:var(--c-ink);
  font-size:16px; font-weight:500; letter-spacing:-.004em;
  text-decoration:none;
  transition:transform .35s var(--ease), background .35s var(--ease);
}
.btn__arrow{ display:inline-block; transition:transform .35s var(--ease); }
.btn:hover{ transform:translateY(-2px); background:#fff; }
.btn:hover .btn__arrow{ transform:translateX(4px); }

/* The base button is pale on ink: written for the bedrock stratum, invisible
   anywhere else. .btn--ink is the same button for a pale or warm stratum,
   which /contact/ needs because its primary action does not sit in a closing
   block. Must stay below the base rule — same specificity, so source order
   is what makes the override work. Hover keeps the lift and the arrow but
   holds its background: there is nowhere darker for ink to go. */
.btn--ink{ background:var(--c-ink); color:var(--c-inv-ink); }
.btn--ink:hover{ background:var(--c-ink); }

/* ==========================================================================
   Download
   A file offered inside an article. Hairline-ruled like .rule-list, because
   it is the same idea: an item set apart from the prose without a box or a
   shadow. The whole block is the link; the arrow is the only hover motion.

   Markup:
   <a class="download" href="/assets/downloads/thing.pdf" download>
     <span class="download__icon" aria-hidden="true">…svg…</span>
     <span class="download__text">
       <span class="download__title">Thing</span>
       <span class="download__meta">PDF &middot; 4 pages &middot; 288 KB</span>
     </span>
     <span class="download__arrow" aria-hidden="true">&darr;</span>
   </a>
   ========================================================================== */

.download{
  display:flex; align-items:center; gap:16px;
  margin:clamp(28px, 3.6vh, 40px) 0;
  padding:clamp(16px, 2vh, 20px) 0;
  border-top:1px solid var(--c-line);
  border-bottom:1px solid var(--c-line);
  text-decoration:none;
  color:var(--c-ink);
}

.download__icon{
  flex:none;
  width:34px; height:34px;
  display:grid; place-items:center;
  border-radius:2px;
  background:var(--c-surface-3);
  transition:background .35s var(--ease);
}
.download__icon svg{ width:16px; height:16px; display:block; }
.download__icon svg *{
  stroke:var(--c-ink-muted);
  stroke-width:1.7;
  stroke-linecap:round;
  stroke-linejoin:round;
  fill:none;
  transition:stroke .35s var(--ease);
}

.download__text{ display:flex; flex-direction:column; gap:3px; min-width:0; }

.download__title{
  font-size:clamp(15.5px, 1.1vw, 17px);
  font-weight:600;
  line-height:1.3;
  letter-spacing:-.004em;
}

/* Same micro type as .label, without the uppercase shout. */
.download__meta{
  font-size:clamp(11.5px, .88vw, 12.5px);
  letter-spacing:.06em;
  color:var(--c-ink-faint);
  line-height:1.4;
}

.download__arrow{
  margin-left:auto;
  flex:none;
  font-size:17px;
  color:var(--c-ink-faint);
  transition:transform .35s var(--ease), color .35s var(--ease);
}

.download:hover .download__icon,
.download:focus-visible .download__icon{ background:var(--c-line); }
.download:hover .download__icon svg *,
.download:focus-visible .download__icon svg *{ stroke:var(--c-ink); }
.download:hover .download__arrow,
.download:focus-visible .download__arrow{
  transform:translateY(3px);
  color:var(--c-ink);
}

/* .prose underlines every link it contains; this one is not running text. */
.prose a.download{ text-decoration:none; }

@media (max-width:480px){
  .download{ gap:13px; }
  .download__icon{ width:30px; height:30px; }
}

/* ==========================================================================
   Credential
   A certification mark and its name. Inherits its type from the context it
   sits in, so it works as a micro label in the fold and as footer meta.
   ========================================================================== */

.credential{ display:flex; align-items:center; gap:11px; }

.credential__mark{
  width:27px; height:27px; flex:none;
  border:1px solid var(--c-line);
  border-radius:2px;
  background:rgba(255,255,255,.5);
  display:grid; place-items:center;
  font-size:9px; font-weight:600; letter-spacing:.04em;
  color:var(--c-ink-faint);
}

/* Reversed surfaces */
.site-footer .credential__mark,
.stratum--bedrock .credential__mark{
  border-color:var(--c-inv-line);
  background:rgba(241,238,231,.05);
  color:var(--c-inv-faint);
}

/* ==========================================================================
   Site footer
   Used on every page. Continues the bedrock stratum, so it reads as the base
   of the core sample rather than as a separate slab.
   ========================================================================== */

.site-footer{
  margin-top:auto;   /* takes up the slack on pages shorter than the viewport */
  background:var(--c-ink);
  color:var(--c-inv-muted);
  padding-bottom:env(safe-area-inset-bottom);  /* clear the home indicator */
}
.site-footer__inner{
  border-top:1px solid var(--c-inv-line);
  padding-top:clamp(38px, 5.5vh, 58px);
  padding-bottom:clamp(34px, 5vh, 52px);
}

.site-footer__top{
  display:flex; justify-content:space-between; align-items:flex-start;
  gap:clamp(24px, 4vw, 60px);
  flex-wrap:wrap;
}
.site-footer__brand img{ height:clamp(18px, 1.85vw, 22px); width:auto; display:block; }

.site-footer__nav{ display:flex; flex-wrap:wrap; gap:clamp(16px, 2.4vw, 34px); }
.site-footer__link{
  position:relative;
  font-size:14.5px;
  color:var(--c-inv-muted);
  text-decoration:none;
  padding-bottom:3px;
}
.site-footer__link::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:var(--c-inv-ink);
  transform:scaleX(0); transform-origin:left;
  transition:transform .3s var(--ease);
}
.site-footer__link:hover{ color:var(--c-inv-ink); }
.site-footer__link:hover::after{ transform:scaleX(1); }

.site-footer__meta{
  display:flex; justify-content:space-between; align-items:center;
  gap:20px; flex-wrap:wrap;
  margin-top:clamp(40px, 6vh, 72px);
  font-size:12.5px;
  letter-spacing:.01em;
  color:var(--c-inv-faint);
}

.site-footer__legal{
  margin-top:20px;
  padding-top:18px;
  border-top:1px solid var(--c-inv-line);
  font-size:12px;
  letter-spacing:.012em;
  color:var(--c-inv-faint);
}
/* Each particular stays whole; the line breaks between them instead of
   through the company number. */
.site-footer__legal > span{ white-space:nowrap; }
.site-footer__sep{ opacity:.55; padding-inline:5px; }

@media (max-width:880px){
  .site-footer__meta{ margin-top:38px; }
  .site-footer__link{ padding-block:8px 11px; }   /* touch target */
}

/* ==========================================================================
   Utilities
   Single-purpose helpers. Keep this file short. If a utility starts carrying
   design meaning, promote it to a component.
   ========================================================================== */

/* --- Vertical rhythm ---------------------------------------------------- */
.u-space-s{ margin-top:clamp(28px, 3.6vh, 40px); }
.u-space-m{ margin-top:clamp(30px, 4vh, 44px); }
.u-space-l{ margin-top:clamp(38px, 5vh, 58px); }

/* --- Screen reader only ------------------------------------------------- */
.u-visually-hidden{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden; white-space:nowrap;
}

/* --- Page load entrance -------------------------------------------------
   Set the stagger in the markup: style="--delay:.2s"
   ------------------------------------------------------------------------ */
.u-enter{
  opacity:0;
  transform:translateY(13px);
  animation:u-enter .85s var(--ease-out) forwards;
  animation-delay:var(--delay, 0s);
}
@keyframes u-enter{ to{ opacity:1; transform:none; } }

.u-enter--datum{
  transform:translateY(-50%) scale(.9);
  animation-name:u-enter-datum;
  animation-duration:.7s;
  animation-timing-function:cubic-bezier(.16,.9,.3,1);
}
@keyframes u-enter-datum{ to{ opacity:.88; transform:translateY(-50%) scale(1); } }

/* --- Reduced motion ------------------------------------------------------
   Last in the last file, so it wins over everything above it.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion:reduce){
  .u-enter{ opacity:1; transform:none; animation:none; }
  .u-enter--datum{ opacity:.88; transform:translateY(-50%); animation:none; }
  *{ transition:none !important; }
}

