/* ==========================================================================
   HackPro — site stylesheet.

   This file is the ONLY source of presentation for the site. There are no
   inline style attributes in the HTML and no JavaScript anywhere, which is
   what lets the Content-Security-Policy stay at its strictest useful setting:

     default-src 'none'; script-src 'none'; style-src 'self'; font-src 'self'

   No 'unsafe-inline' is needed or wanted. If you add an inline style to a page
   it will be silently dropped by the browser — add a class here instead.

   The palette is fixed: Old Glory Red and Old Glory Blue on warm off-white,
   set in Archivo, with square corners. Everything below is craft applied to
   that, not a change of it.

   Contents
     01  Fonts
     02  Design tokens (light + dark)
     03  Reset and base elements
     04  Layout primitives
     05  Type
     06  Buttons, links, tags, rules
     07  Masthead and navigation
     08  Hero
     09  Marquee
     10  Section headers
     11  Spec panels
     12  Index rows
     13  Pillars, steps, FAQ
     14  Team
     15  Forms
     16  Bands and calls to action
     17  Footer
     18  Motion
     19  Print
   ========================================================================== */


/* 01  Fonts ================================================================
   Archivo is served from our own origin, not from Google. That removes a
   third-party request from every page load: no visitor IP is handed to a
   third party, no external host can change what our pages render, and the
   CSP does not have to allowlist anyone. Archivo is a variable font, so one
   file covers every weight from 100 to 900.
   Archivo is licensed under the SIL Open Font License 1.1 — see fonts/OFL.txt.
   ------------------------------------------------------------------------ */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/archivo-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: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/archivo-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;
}


/* 02  Design tokens ======================================================== */
:root {
  color-scheme: light;

  /* Brand constants — identical in both themes. */
  --red: #b31942;
  --red-deep: #921434;
  --navy: #0a3161;
  --navy-deep: #072346;

  /* Surfaces and ink. */
  --bg: #f3f2f2;
  --bg-sunk: #eae9e9;
  --ink: #201e1d;
  --ink-soft: #4a4746;
  --ink-mute: #6b6867;
  --line: #cbc8c7;
  --line-strong: #201e1d;
  --hair: rgba(32, 30, 29, 0.16);

  /* Roles. */
  --accent: var(--red);
  --accent-text: var(--red-deep);   /* the red used for small text — darker, for contrast */
  --accent-on: #ffffff;             /* text on a red fill */
  --band: var(--navy);              /* full-bleed navy sections, and row hovers */
  --band-deep: var(--navy-deep);    /* the footer */
  --band-ink: #f3f2f2;
  --band-ink-soft: rgba(255, 255, 255, 0.78);
  --band-ink-mute: rgba(255, 255, 255, 0.58);
  --band-line: rgba(255, 255, 255, 0.26);
  --band-link: #ffb3c4;
  --rule-alt: var(--navy);

  /* Type. */
  --font: "Archivo", "Archivo Narrow", "Helvetica Neue", Helvetica, Arial,
    system-ui, sans-serif;
  --weight-heavy: 800;

  /* Fluid scale. The jump from --t-display to --t-body is deliberately
     enormous: the size contrast is what carries the editorial feel, and it is
     free — one headline set large costs nothing and reads as confidence. */
  --t-display: clamp(2.65rem, 0.4rem + 9vw, 8rem);
  --t-h1: clamp(2.4rem, 0.9rem + 5.6vw, 5.25rem);
  --t-h2: clamp(1.85rem, 1.15rem + 2.7vw, 3.1rem);
  --t-h3: clamp(1.1rem, 1.02rem + 0.35vw, 1.25rem);
  --t-lead: clamp(1.05rem, 0.98rem + 0.34vw, 1.2rem);
  --t-body: clamp(0.94rem, 0.91rem + 0.14vw, 0.97rem);
  --t-small: 0.83rem;
  --t-kicker: 0.76rem;
  --t-index: clamp(1.6rem, 0.9rem + 2.6vw, 3rem);   /* the big row numerals */

  /* Rhythm. */
  --gutter: clamp(1.375rem, 0.2rem + 5vw, 5.5rem);
  --section-y: clamp(3.5rem, 1.6rem + 6.5vw, 7rem);
  --gap: clamp(1.75rem, 0.9rem + 3.2vw, 3rem);
  --gap-wide: clamp(2rem, 0.4rem + 6vw, 6rem);

  /* Motion. */
  --ease: cubic-bezier(0.22, 0.68, 0.32, 1);
  --fast: 150ms;
  --mid: 320ms;
  --slow: 460ms;
}

/* The site is light in every context, on purpose. `color-scheme: light` above
   tells the browser so explicitly, which also keeps form controls, scrollbars
   and the address bar light for a visitor whose OS is set to dark — without
   it, those chrome elements go dark against a white page.

   There is no dark theme and no toggle: a toggle needs JavaScript, and this
   site ships none so that the Content-Security-Policy can stay at
   script-src 'none'. If a dark theme is ever wanted, it is one
   @media (prefers-color-scheme: dark) block restating the tokens above. */


/* 03  Reset and base ====================================================== */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
:target { scroll-margin-top: 7rem; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--t-body);
  line-height: 1.6;
  text-wrap: pretty;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Kerning and ligatures on, and quotes allowed to hang into the margin so a
     quoted line starts on the same optical axis as the line above it. Safari
     honours hanging-punctuation; everywhere else it is simply ignored. */
  font-kerning: normal;
  font-variant-ligatures: common-ligatures contextual;
  hanging-punctuation: first last;
}

img, svg { display: block; max-width: 100%; }
figure { margin: 0; }

a { color: var(--accent-text); text-decoration: none; }

:focus { outline: none; }
/* A 3px ring with a matching offset reads clearly on both themes and against
   the navy bands, where a thin accent-coloured ring nearly disappears. */
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.band :focus-visible, .masthead :focus-visible, .footer :focus-visible {
  outline-color: var(--band-link);
}
::selection { background: color-mix(in srgb, var(--accent) 26%, transparent); }
.band ::selection, .footer ::selection, .masthead ::selection {
  background: color-mix(in srgb, var(--band-link) 40%, transparent);
}

.skiplink {
  position: absolute; left: -9999px; top: 0; z-index: 60;
  background: var(--accent); color: var(--accent-on);
  padding: 0.7rem 1.15rem;
  font-size: var(--t-small); font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.skiplink:focus { left: 0; }

/* Honeypot: a field only an automated submitter fills in. Positioned
   off-screen rather than display:none, which some bots detect and skip. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }


/* 04  Layout primitives ==================================================== */
.page { display: flex; flex-direction: column; min-height: 100vh; }
main { flex: 1; }

.shell { padding-inline: var(--gutter); }

.section { padding-block: var(--section-y); }
.section--flush-top { padding-top: 0; }
.section--ruled { border-top: 2px solid var(--line-strong); padding-top: var(--gap); }

.split {
  display: grid;
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: var(--gap-wide);
  align-items: start;
}

.cols-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap); }
.cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); }
.cols-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap); }
.cols-5 { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--gap); }

@media (max-width: 68rem) {
  .cols-4, .cols-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split { grid-template-columns: minmax(0, 1fr); gap: var(--gap); }
}
@media (max-width: 40rem) {
  .cols-2, .cols-3, .cols-4, .cols-5 { grid-template-columns: minmax(0, 1fr); }
}


/* 05  Type ================================================================= */
h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-weight: var(--weight-heavy);
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* Optical tightening: the bigger the type, the tighter it wants to be set. */
.display {
  font-size: var(--t-display);
  line-height: 0.94;
  letter-spacing: -0.045em;
}
.display .line { display: block; }

.h1 { font-size: var(--t-h1); line-height: 0.98; letter-spacing: -0.038em; }
.h1 .line { display: block; }
.h2 { font-size: var(--t-h2); line-height: 1.02; letter-spacing: -0.03em; }
.h3 { font-size: var(--t-h3); line-height: 1.25; letter-spacing: -0.008em; }

/* A small uppercase label, led by a short red rule. */
.kicker {
  display: flex; align-items: center; gap: 0.8rem;
  margin: 0 0 1.6rem;
  font-size: var(--t-kicker); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent-text);
}
.kicker::before {
  content: ""; flex: none;
  width: 2.25rem; height: 2px; background: var(--accent);
}
.band .kicker { color: var(--band-link); }
.band .kicker::before { background: var(--band-link); }

.lead { font-size: var(--t-lead); line-height: 1.6; color: var(--ink-soft); margin: 0 0 1.2rem; }
.lead:last-child { margin-bottom: 0; }
.cols-2 > .lead, .cols-3 > .lead, .cols-4 > .lead { margin-bottom: 0; }
.measure { max-width: 56ch; }
.measure-tight { max-width: 44ch; }

.body { margin: 0 0 0.9rem; color: var(--ink-soft); line-height: 1.65; }
.body:last-child { margin-bottom: 0; }
.section-intro + .body, .body + .body, .lead + .body { margin-top: 0.9rem; }

.muted { color: var(--ink-mute); }
.num { font-variant-numeric: tabular-nums; }


/* 06  Buttons, links, tags, rules =========================================
   Buttons fill from the bottom on hover rather than swapping colour. It costs
   one pseudo-element and reads as considerably more deliberate.
   ------------------------------------------------------------------------ */
.actions { display: flex; gap: 0.7rem; flex-wrap: wrap; align-items: center; }
/* On a phone two buttons of different widths stack raggedly. Give them the
   full column instead — the usual mobile pattern, and a bigger tap target. */
@media (max-width: 30rem) {
  .actions { flex-direction: column; align-items: stretch; }
  .actions .btn { width: 100%; }
}

.btn {
  position: relative; isolation: isolate; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  padding: 0.95rem 1.4rem;
  font: inherit; font-weight: var(--weight-heavy); font-size: 0.85rem;
  line-height: 1.2; letter-spacing: 0.04em; text-transform: uppercase;
  border: 2px solid transparent; border-radius: 0;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: color var(--mid) var(--ease), border-color var(--mid) var(--ease);
}
.btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  transform: scaleY(0); transform-origin: bottom;
  transition: transform var(--mid) var(--ease);
}
.btn:hover::before, .btn:focus-visible::before { transform: scaleY(1); }
.btn:active { transform: translateY(1px); }

.btn-arrow { transition: transform var(--mid) var(--ease); }
.btn:hover .btn-arrow { transform: translateX(4px); }

.btn-primary { background: var(--accent); color: var(--accent-on); border-color: var(--accent); }
.btn-primary::before { background: var(--ink); }
.btn-primary:hover, .btn-primary:focus-visible { border-color: var(--ink); color: var(--bg); }

.btn-secondary { color: var(--ink); border-color: var(--line-strong); }
.btn-secondary::before { background: var(--ink); }
.btn-secondary:hover, .btn-secondary:focus-visible { color: var(--bg); border-color: var(--ink); }

.btn-onband { color: var(--band-ink); border-color: var(--band-ink); }
.btn-onband::before { background: var(--band-ink); }
.btn-onband:hover, .btn-onband:focus-visible { color: var(--band); }

/* Text links: an underline that draws in from the left. */
.link {
  color: var(--accent-text);
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size var(--mid) var(--ease);
}
.link:hover, .link:focus-visible { background-size: 100% 1px; }
.band .link { color: var(--band-link); }

.tag {
  display: inline-flex; align-items: center;
  padding: 0.3rem 0.75rem;
  font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  border: 1px solid transparent; white-space: nowrap;
}
.tag-accent { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent-text); border-color: color-mix(in srgb, var(--accent) 34%, transparent); }
.tag-outline { border-color: var(--line-strong); color: var(--ink-soft); }
.tag-neutral { background: var(--bg-sunk); color: var(--ink-soft); border-color: var(--line); }

/* The 4px red bar that closes the masthead and opens every navy band. */
.stripe { height: 4px; background: var(--accent); }

/* The mark: three stars in a row over a red bar. The stars take the current
   text colour so the same markup works on navy and on the page background;
   only the bar is pinned to the accent. */
.mark { flex: none; }
.mark .mark-star { fill: currentColor; }
.mark .mark-bar { fill: var(--accent); }
.mark-lg { color: var(--band); margin-bottom: 1.5rem; }
.band .mark-lg, .panel--navy .mark-lg { color: var(--band-ink); }


/* 07  Masthead and navigation ============================================= */
.masthead {
  position: sticky; top: 0; z-index: 50;
  background: var(--band); color: var(--band-ink);
}
.masthead-inner {
  display: flex; align-items: center; gap: clamp(1.25rem, 2.5vw, 3rem);
  padding-block: 1.1rem;
}

.brand {
  display: flex; align-items: center; gap: 0.7rem;
  margin-right: auto; color: var(--band-ink);
}
.brand-mark { transition: transform var(--slow) var(--ease); }
.brand:hover .brand-mark { transform: translateY(-2px); }
.brand-name { font-weight: var(--weight-heavy); font-size: 1.3rem; letter-spacing: -0.012em; }

.nav {
  display: flex; align-items: center; gap: clamp(1rem, 2vw, 2.25rem);
  font-size: 0.76rem; font-weight: 700;
  letter-spacing: 0.13em; text-transform: uppercase;
}
.navlink { position: relative; padding-block: 0.4rem; color: var(--band-ink); }
.navlink:hover { color: #ffffff; }
.navlink::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--slow) var(--ease);
}
.navlink:hover::after, .navlink:focus-visible::after,
.navlink[aria-current="page"]::after { transform: scaleX(1); }

.masthead .btn-primary::before { background: var(--band-ink); }
.masthead .btn-primary:hover, .masthead .btn-primary:focus-visible {
  color: var(--band); border-color: var(--band-ink);
}

@media (max-width: 62rem) {
  .masthead { position: static; }
  .masthead-inner { flex-wrap: wrap; gap: 0.9rem 1.5rem; padding-block: 1rem; }
  .brand { margin-right: 0; flex: 1 0 auto; }
  /* Stack order: brand, then the links, then the call to action last. */
  .nav { order: 2; width: 100%; flex-wrap: wrap; gap: 0.5rem 1.25rem; }
  .masthead-inner > .btn { order: 3; }
}


/* 08  Hero ================================================================
   The home hero is one tall column: label, an oversized headline, then a
   baseline row carrying the sentence, the buttons and the index. Anchoring
   the mass to the bottom of the viewport is what makes it feel composed
   rather than merely large.
   ------------------------------------------------------------------------ */
.hero-full {
  min-height: min(86svh, 54rem);
  display: flex; flex-direction: column; justify-content: center;
  padding-block: clamp(3rem, 1rem + 7vw, 6rem) var(--section-y);
}
.hero-display { margin: 0 0 auto; }
.hero-foot {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: var(--gap-wide);
  align-items: end;
  margin-top: clamp(2.5rem, 1rem + 5vw, 5rem);
}
.hero-foot .lead { max-width: 42ch; }
.hero-foot .actions { margin-top: 1.8rem; }

/* The inner-page hero: headline column plus a fact panel. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 23rem);
  gap: var(--gap-wide);
  align-items: start;
  padding-block: clamp(3rem, 1.2rem + 6vw, 5.5rem) var(--section-y);
}
.hero--wide-aside { grid-template-columns: minmax(0, 1fr) minmax(0, 27rem); }
.hero-title { margin: 0 0 1.6rem; }
.hero .lead { max-width: 52ch; }
.hero .actions { margin-top: 2.2rem; }

@media (max-width: 68rem) {
  .hero, .hero--wide-aside, .hero-foot {
    grid-template-columns: minmax(0, 1fr); gap: var(--gap);
  }
  .hero-full { min-height: 0; }
}

/* The numbered capability index in the hero. */
.index-list { margin: 0; border-top: 2px solid var(--line-strong); }
.index-list div {
  display: flex; align-items: baseline; gap: 1.1rem;
  padding-block: 0.65rem;
  border-bottom: 1px solid var(--hair);
  font-size: 0.92rem;
}
.index-list dt { color: var(--ink-mute); font-variant-numeric: tabular-nums; font-size: 0.78rem; }
.index-list dd { margin: 0; transition: transform var(--mid) var(--ease); }
/* The row indents very slightly under the pointer — enough to feel responsive,
   not enough to reflow anything around it. */
.index-list div:hover dd { transform: translateX(6px); }
.index-list div:hover dt { color: var(--accent-text); }


/* 09  Marquee =============================================================
   Decorative repetition of what we test. The list is duplicated so the loop
   is seamless, so the whole strip is aria-hidden — the same capabilities are
   in the hero index above it, where a screen reader reads them once.
   The animation only ever moves the strip; nothing is hidden at rest, so a
   browser that refuses to animate simply shows the first copy.
   ------------------------------------------------------------------------ */
.marquee {
  overflow: hidden;
  border-block: 2px solid var(--line-strong);
  padding-block: 1.1rem;
  -webkit-user-select: none; user-select: none;
}
.marquee-track {
  display: flex; width: max-content;
  animation: marquee 42s linear infinite;
}
/* Stop it while the pointer is over it. Movement under a reader's eye is the
   one thing a marquee is genuinely bad at; letting them halt it costs a line. */
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-item {
  display: flex; align-items: center; gap: 2.25rem;
  padding-right: 2.25rem;
  font-size: clamp(1rem, 0.75rem + 0.9vw, 1.5rem);
  font-weight: var(--weight-heavy);
  letter-spacing: -0.01em; text-transform: uppercase;
  white-space: nowrap;
}
.marquee-item::after {
  content: ""; flex: none;
  width: 0.5rem; height: 0.5rem; background: var(--accent);
  transform: rotate(45deg);
}
@keyframes marquee { to { transform: translateX(-50%); } }


/* 10  Section headers =====================================================
   A number, a title, and a hairline that runs to the right edge. Repeating
   this exactly is most of what makes a page feel designed rather than
   assembled.
   ------------------------------------------------------------------------ */
.sec-head {
  display: flex; align-items: baseline; gap: 1.25rem;
  margin-bottom: var(--gap);
  padding-top: 1.1rem;
  border-top: 2px solid var(--line-strong);
}
.sec-num {
  flex: none;
  font-size: var(--t-kicker); font-weight: 700;
  letter-spacing: 0.16em; font-variant-numeric: tabular-nums;
  color: var(--accent-text);
}
.sec-head .h2 { margin-right: auto; }
/* Shrinkable, not `flex: none` — beside a very wide heading it has to be able
   to give ground and wrap rather than push past the right edge. */
.sec-note {
  flex: 0 1 auto; max-width: 30ch; text-align: right;
  font-size: var(--t-small); line-height: 1.5; color: var(--ink-mute);
}
.band .sec-head { border-top-color: var(--band-line); }
.band .sec-num { color: var(--band-link); }
.band .sec-note { color: var(--band-ink-mute); }
@media (max-width: 55rem) {
  .sec-head { flex-wrap: wrap; gap: 0.5rem 1.25rem; }
  .sec-note { text-align: left; max-width: none; width: 100%; }
}


/* 11  Spec panels ========================================================= */
.specs { margin: 0; font-size: 0.9rem; line-height: 1.5; }
.specs div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1.5rem;
  padding-block: 0.7rem;
  border-bottom: 1px solid var(--hair);
}
.specs div:last-child { border-bottom: 0; }
.specs dt { color: var(--ink-mute); }
.specs dd { margin: 0; text-align: right; font-weight: 600; }

.panel { border: 2px solid var(--line-strong); padding: clamp(1.4rem, 3vw, 2rem); }
.panel--navy {
  background: var(--band); color: var(--band-ink); border-color: var(--band);
}
.panel--navy .specs dt { color: var(--band-ink-mute); }
.panel--navy .specs div { border-bottom-color: var(--band-line); }
.panel-note {
  margin: 1.5rem 0 0; padding-top: 1.2rem;
  border-top: 2px solid var(--band-line);
  font-size: 0.85rem; line-height: 1.6; color: var(--band-ink-mute);
}


/* 12  Index rows ==========================================================
   The horizontal rows used for services, tracks and test types. On hover the
   row fills with navy from the bottom, bleeding past the page gutters to the
   viewport edge, and the type inverts. `isolation: isolate` keeps the z-index
   of the fill inside the row, so it paints over the page but under the text.
   ------------------------------------------------------------------------ */
.ledger { border-bottom: 2px solid var(--line-strong); }

.ledger-row {
  position: relative; isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 4.5rem) minmax(0, 18rem) minmax(0, 1fr) minmax(0, 11rem);
  gap: var(--gap);
  align-items: baseline;
  padding-block: clamp(1.5rem, 0.6rem + 1.8vw, 2.4rem);
  border-top: 2px solid var(--line-strong);
}
.ledger-row + .ledger-row { border-top-width: 1px; border-top-color: var(--hair); }
.ledger-row::before {
  content: ""; position: absolute; z-index: -1;
  top: 0; bottom: 0;
  left: calc(var(--gutter) * -1); right: calc(var(--gutter) * -1);
  background: var(--band);
  transform: scaleY(0); transform-origin: bottom;
  transition: transform var(--slow) var(--ease);
}
/* One state, two triggers. Every rule below uses the same :is() so that a
   keyboard user tabbing into the row gets the identical inversion a mouse
   user gets — an earlier version filled the row navy on :focus-within but
   only inverted the title, leaving the number, body and tag unreadable. */
.ledger-row:is(:hover, :focus-within)::before { transform: scaleY(1); }

.ledger-num {
  margin: 0;
  font-size: var(--t-index); font-weight: var(--weight-heavy);
  line-height: 0.9; letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
  transition: color var(--mid) var(--ease);
}
.ledger-title {
  margin: 0;
  font-size: clamp(1.35rem, 1rem + 1.4vw, 2rem);
  line-height: 1.05; letter-spacing: -0.03em;
}
.ledger-title a { color: var(--ink); }
.ledger-title .btn-arrow { display: inline-block; opacity: 0; margin-left: 0.4rem; }
.ledger-body { margin: 0; max-width: 46ch; color: var(--ink-soft); }
.ledger-meta {
  justify-self: end; text-align: right;
  font-size: var(--t-small); font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-mute);
}
.ledger-row .tag { justify-self: end; }

/* The inversion. */
.ledger-row:is(:hover, :focus-within) :is(.ledger-title, .ledger-title a) { color: var(--band-ink); }
.ledger-row:is(:hover, :focus-within) :is(.ledger-body, .ledger-meta) { color: var(--band-ink-soft); }
.ledger-row:is(:hover, :focus-within) .ledger-num { color: var(--band-link); }
.ledger-row:is(:hover, :focus-within) .ledger-title .btn-arrow {
  opacity: 1; transform: translateX(4px);
}
.ledger-row:is(:hover, :focus-within) .tag {
  background: transparent; border-color: var(--band-line); color: var(--band-ink-soft);
}
/* The focus ring has to switch to a colour that reads on the navy fill. */
.ledger-row:focus-within :focus-visible { outline-color: var(--band-link); }

@media (max-width: 68rem) {
  .ledger-row {
    grid-template-columns: minmax(0, 3.5rem) minmax(0, 1fr);
    gap: 0.4rem 1.1rem;
  }
  .ledger-num { grid-row: 1; }
  .ledger-title { grid-column: 2; }
  .ledger-body { grid-column: 2; margin-top: 0.5rem; }
  .ledger-meta, .ledger-row .tag {
    grid-column: 2; justify-self: start; text-align: left; margin-top: 0.7rem;
  }
}


/* 13  Pillars, steps, FAQ ================================================= */
/* The rule above a pillar is drawn as a pseudo-element so it can grow from
   the left when the block is hovered — the whole card stays static, which is
   the point: it reads as a detail noticed rather than an effect performed. */
.pillar { position: relative; border-top: 2px solid var(--hair); padding-top: 1.3rem; }
.pillar::before {
  content: ""; position: absolute; top: -2px; left: 0; right: 0; height: 2px;
  background: var(--accent);
  transform: scaleX(0.22); transform-origin: left;
  transition: transform var(--slow) var(--ease);
}
.pillar:hover::before, .pillar:focus-within::before { transform: scaleX(1); }
.pillar--alt::before { background: var(--rule-alt); }
.band .pillar { border-top-color: var(--band-line); }
.band .pillar::before { background: var(--band-link); }
.band .pillar--accent::before { background: var(--accent); }
.pillar-title { margin: 0 0 0.55rem; }
.pillar-body { margin: 0; color: var(--ink-soft); }

/* A numbered step. The figure is set large and low-contrast so it reads as
   structure rather than as content competing with the label. */
.step { position: relative; border-top: 2px solid var(--line-strong); padding-top: 1.1rem; }
/* The rule doubles in weight on hover, drawn as a pseudo-element so the change
   costs no layout shift. Matches the .pillar treatment above, deliberately —
   two different hover idioms for two near-identical blocks reads as an accident. */
.step::before {
  content: ""; position: absolute; top: -2px; left: 0; right: 0; height: 2px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--slow) var(--ease);
}
.step:hover::before, .step:focus-within::before { transform: scaleX(1); }
.band .step::before { background: var(--band-link); }
.step-num {
  display: block; margin: 0 0 0.5rem;
  font-size: var(--t-index); font-weight: var(--weight-heavy);
  line-height: 0.9; letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  transition: transform var(--slow) var(--ease);
}
.step:hover .step-num { transform: translateX(3px); }
.step-label {
  display: block; margin: 0 0 0.6rem;
  font-size: var(--t-kicker); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
}
.step-body { margin: 0; color: var(--ink-soft); font-size: 0.93rem; }
.band .step { border-top-color: var(--band-line); }
.band .step-num { color: var(--band-link); }
.band .step-body { color: var(--band-ink-soft); }

.faq { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--gap-wide); }
.faq-item { border-top: 1px solid var(--hair); padding-block: 1.6rem; }
.faq-item:nth-child(-n + 2) { border-top: 2px solid var(--line-strong); }
.faq-q { margin: 0 0 0.5rem; font-size: 1.05rem; line-height: 1.25; }
.faq-a { margin: 0; color: var(--ink-soft); }
@media (max-width: 40rem) {
  .faq { grid-template-columns: minmax(0, 1fr); }
  .faq-item:nth-child(2) { border-top-width: 1px; border-top-color: var(--hair); }
}

/* Photograph placeholders. Replace each with a real <img class="shot-img">;
   the markup to use sits commented directly above every one in the HTML. */
.shot { border: 2px solid var(--line-strong); overflow: hidden; }
.shot-img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(1) contrast(1.06); }
.photoslot {
  width: 100%; height: 100%; min-height: 9rem;
  display: grid; place-items: center; padding: 1.25rem;
  background: var(--bg-sunk);
}
.photoslot span {
  font-size: 0.72rem; line-height: 1.5; letter-spacing: 0.1em;
  text-transform: uppercase; text-align: center;
  color: var(--ink-mute); max-width: 28ch;
}
.shot--hero { height: clamp(16rem, 28vw, 24rem); }
.shot--tile { height: 10rem; margin-bottom: 1.2rem; }
.shot--portrait { aspect-ratio: 4 / 5; margin-bottom: 1.2rem; }


/* 14  Team ================================================================= */
.team { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); }
@media (max-width: 62rem) { .team { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 40rem) { .team { grid-template-columns: minmax(0, 1fr); } }

.member { border-top: 2px solid var(--line-strong); padding-top: 1.2rem; }
.member-name { margin: 0 0 0.25rem; font-size: 1.3rem; letter-spacing: -0.025em; }
.member-role {
  margin: 0 0 0.8rem;
  font-size: var(--t-kicker); font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent-text);
}
.member-body { margin: 0; color: var(--ink-soft); font-size: 0.93rem; }
.member-links {
  margin: 0.85rem 0 0;
  font-size: var(--t-small); font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
}

.team-note {
  margin: var(--gap) 0 0; padding-top: 1.2rem;
  border-top: 1px solid var(--hair);
  max-width: 74ch;
  font-size: var(--t-small); line-height: 1.65; color: var(--ink-mute);
}


/* 15  Forms =============================================================== */
.form { display: flex; flex-direction: column; gap: 1.1rem; }
.form--framed { border: 2px solid var(--line-strong); padding: clamp(1.5rem, 3vw, 2.25rem); }

.field > label {
  display: block; margin-bottom: 0.4rem;
  font-size: var(--t-kicker); font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-mute);
}
.input {
  width: 100%; min-height: 2.9rem; padding: 0.6rem 0;
  font: inherit; font-size: 1rem;
  color: var(--ink); caret-color: var(--accent);
  background: transparent;
  border: 0; border-bottom: 2px solid var(--line);
  border-radius: 0;
  transition: border-color var(--mid) var(--ease);
}
.input::placeholder { color: var(--ink-mute); }
.input:hover { border-bottom-color: var(--line-strong); }
.input:focus-visible { border-bottom-color: var(--accent); outline: none; }
textarea.input { min-height: 5.5rem; resize: vertical; }

/* :user-invalid, not :invalid — it only matches once the visitor has actually
   engaged with the field, so an untouched required input is never marked
   wrong before they have had a chance to fill it in. */
.input:user-invalid { border-bottom-color: var(--accent); }
.input:user-invalid + .field-hint { display: block; }
.field-hint {
  display: none; margin: 0.4rem 0 0;
  font-size: var(--t-small); color: var(--accent-text);
}

.form-note { margin: 0; font-size: var(--t-small); line-height: 1.6; color: var(--ink-mute); }

.form--onband .field > label { color: var(--band-ink-mute); }
.form--onband .input { color: var(--band-ink); border-bottom-color: var(--band-line); }
.form--onband .input::placeholder { color: var(--band-ink-mute); }
.form--onband .input:hover { border-bottom-color: rgba(255, 255, 255, 0.55); }
.form--onband .input:focus-visible { border-bottom-color: var(--band-link); }
.form--onband .form-note, .band .form-note { color: var(--band-ink-mute); }


/* 16  Bands and calls to action =========================================== */
/* A very slight top-to-bottom lift across the navy. Flat navy over a tall
   section reads as a dead rectangle; three percent of luminance is enough to
   give it a light source without anyone consciously noticing a gradient. */
.band {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--band) 94%, white) 0%,
    var(--band) 55%,
    color-mix(in srgb, var(--band) 96%, black) 100%
  );
  color: var(--band-ink);
}
.band-inner { padding-block: var(--section-y); }
.band a { color: var(--band-link); }
.band .h1, .band .h2, .band .h3, .band .pillar-title { color: var(--band-ink); }
.band .body, .band .lead, .band .pillar-body, .band .section-intro { color: var(--band-ink-soft); }
/* .pillar rules on a band are set in section 13, alongside the base rule. */

.section-intro { margin: 0.9rem 0 0; color: var(--ink-soft); max-width: 44ch; }

.cta {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--gap-wide); flex-wrap: wrap;
}
.cta-title {
  margin: 0 0 1rem;
  font-size: clamp(2.1rem, 1rem + 4.4vw, 4.25rem);
  line-height: 0.98; letter-spacing: -0.038em;
}
.cta-title:last-child { margin-bottom: 0; }
.cta-title .line { display: block; }
.cta-copy { margin: 0; max-width: 44ch; color: var(--ink-soft); }
.band .cta-copy { color: var(--band-ink-soft); }
.cta--ruled { border-top: 2px solid var(--accent); padding-top: var(--gap); }


/* 17  Footer ==============================================================
   Closed by an oversized wordmark, cropped by the viewport. It costs nothing,
   uses type already loaded, and gives the page a deliberate last beat.
   ------------------------------------------------------------------------ */
.footer { background: var(--band-deep); color: var(--band-ink); }
.footer a { color: var(--band-ink); }
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  gap: var(--gap);
  padding-block: clamp(3rem, 1.5rem + 4vw, 4.5rem) 3rem;
}
.footer-brand { display: flex; align-items: center; gap: 0.7rem; margin-bottom: 1.2rem; }
.footer-blurb { margin: 0 0 1.2rem; max-width: 32ch; color: var(--band-ink-soft); font-size: 0.93rem; }
.footer-mail { margin: 0; font-size: 0.95rem; font-weight: 600; }
.footer-mail a { color: var(--band-link); }

.footer-head {
  margin: 0 0 1.15rem;
  font-size: var(--t-kicker); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--band-ink-mute);
}
.footer-nav { display: flex; flex-direction: column; gap: 0.7rem; font-size: 0.93rem; }
.footlink { position: relative; color: var(--band-ink); width: fit-content; }
.footlink::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: var(--band-link);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--mid) var(--ease);
}
.footlink:hover { color: var(--band-link); }
.footlink:hover::after, .footlink:focus-visible::after { transform: scaleX(1); }

.footer-wordmark {
  display: block; overflow: hidden;
  padding-top: 0.5rem;
  border-top: 1px solid var(--band-line);
}
.footer-wordmark span {
  display: block;
  font-size: clamp(4rem, 19vw, 17rem);
  font-weight: var(--weight-heavy);
  line-height: 0.78; letter-spacing: -0.055em;
  color: rgba(255, 255, 255, 0.09);
  white-space: nowrap; text-align: center;
}

.footer-legal {
  display: flex; gap: 1rem 2.25rem; flex-wrap: wrap;
  padding-block: 1.4rem 2.25rem;
  font-size: var(--t-small); color: var(--band-ink-mute);
}
.footer-legal span:first-child { margin-right: auto; }

@media (max-width: 62rem) {
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-grid > :first-child { grid-column: 1 / -1; }
}
@media (max-width: 30rem) { .footer-grid { grid-template-columns: minmax(0, 1fr); } }


/* 18  Motion ==============================================================
   THE RULE FOR THIS SECTION: no animation may ever leave real content
   invisible at rest.

   The obvious scroll-reveal — start a section at opacity:0, fade it in on a
   view() timeline — was tried and removed. Any renderer that rasterises the
   page without a real scroll (headless capture, print-to-PDF, link-preview
   crawlers, reader modes, a browser that ships view() but stalls the
   timeline) evaluates it at zero and photographs a blank page. For a
   marketing site that is a far worse outcome than no animation at all.

   So everything below is one of two safe kinds:
     · transform-only, so the worst case is content sitting a few pixels off
       its final position — still fully legible;
     · purely decorative, on an element that carries no information.
   Nothing here animates opacity, clip-path or visibility on real content.
   ------------------------------------------------------------------------ */

/* — Reading progress. A white rule runs left to right along the masthead's red
     one as the page is consumed. The red rule itself is never touched: it is
     the brand's signature and it must be at full strength on first paint,
     which ruled out the more obvious version of this (dim the rule, fill it
     with red on scroll) — that one costs you the red entirely above the fold. */
@supports (animation-timeline: scroll()) {
  .masthead .stripe { position: relative; }
  .masthead .stripe::after {
    content: ""; position: absolute; inset: 0;
    background: var(--band-ink);
    transform: scaleX(0); transform-origin: left;
    /* Longhand on purpose. The `animation` shorthand resets duration to 0s,
       and a scroll-driven animation with a zero active duration sits at
       progress 0 for ever — it looks exactly like an unsupported browser.
       Scroll timelines need `auto`. */
    animation-name: read-progress;
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: scroll(root block);
  }
  @keyframes read-progress { to { transform: scaleX(1); } }
}

@media (prefers-reduced-motion: no-preference) {
  /* — Hero entrance. Transform only: at frame zero the headline is already
       drawn and readable, just under half a line low. Each line follows the
       one above it. */
  @keyframes line-rise { from { transform: translateY(0.42em); } to { transform: none; } }
  .hero-display .line {
    animation: line-rise 760ms var(--ease) backwards;
  }
  .hero-display .line:nth-child(2) { animation-delay: 85ms; }
  .hero-display .line:nth-child(3) { animation-delay: 170ms; }
  .hero-full .hero-foot { animation: line-rise 760ms var(--ease) 255ms backwards; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* — Parallax on the oversized mark. Decorative SVG; drifts against the
         scroll through its own travel. */
    @keyframes mark-drift {
      from { transform: translateY(20px); }
      to { transform: translateY(-20px); }
    }
    .mark-lg {
      animation-name: mark-drift;
      animation-duration: auto;      /* see the note on read-progress above */
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }

    /* — Photographs settle out of a slight overscale as they cross the
         viewport. Applies once real images replace the placeholders. */
    @keyframes shot-settle { from { transform: scale(1.07); } to { transform: none; } }
    .shot-img {
      animation-name: shot-settle;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: view();
      animation-range: entry 0% cover 55%;
    }
  }
}

/* — The footer wordmark catches a slow highlight. Guarded twice: the whole
     effect needs background-clip:text, and the element is aria-hidden
     decoration, so losing it costs nothing. */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  @media (prefers-reduced-motion: no-preference) {
    .footer-wordmark span {
      background-image: linear-gradient(100deg,
        var(--band-ink-mute) 0 42%, var(--band-ink) 50%, var(--band-ink-mute) 58% 100%);
      background-size: 280% 100%;
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
      animation: wordmark-sheen 9s linear infinite;
    }
    @keyframes wordmark-sheen {
      from { background-position: 140% 0; }
      to { background-position: -140% 0; }
    }
  }
}

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


/* 19  Print =============================================================== */
@media print {
  .skiplink, .masthead .btn, .actions, .footer-nav, .marquee,
  .footer-wordmark { display: none; }
  .page, body { background: #ffffff; color: #000000; }
  .masthead, .band, .footer, .panel--navy {
    background: #ffffff !important; color: #000000 !important;
  }
  .band .h1, .band .h2, .band .h3, .band .body, .band .lead, .band .step-body,
  .footer a, .footlink, .brand, .brand-name, .panel--navy { color: #000000 !important; }
  .hero-full { min-height: 0; }
  .ledger-row, .pillar, .step, .faq-item, .member { break-inside: avoid; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.7rem; }
}
