/* ==========================================================================
   FortuneFinance Consulting Limited — global stylesheet
   Single stylesheet, no build step, no third-party requests.

   DESIGN CONCEPT — "the ledger"
   The page is built like an accounting document rather than a SaaS
   brochure. Structure is carried by hairline rules and a visible grid, and
   by solid blocks with a hard extruded edge rather than soft floating
   shadows. Every figure, label and code is set in monospace and aligned
   like a statement extract, and totals close on a double rule, the
   accountant's convention.

   Corners are round. The ledger reading is carried by the rules, the mono
   figures and the block edges, not by square corners — so the radius is
   free to soften the whole surface without costing the concept anything.
   All four radius values live in the token block below.

   Two type roles, one rule: MONO = data, labels, codes, references.
   POPPINS = everything else, wordmark included.

   Colour discipline: forest green and hairline rules do the structural
   work. Orange is spent in one place — things the visitor can act on
   (buttons, links, active nav, focus) plus the short rule that opens every
   section. It is not sprinkled across headings and icons.

   Brand palette (supplied): forest #193C27 · orange #E13B06 · wine #A32020
   sky #F9FAFD · dark grey #232323 · Poppins

   Sections: 0 Fonts · 1 Tokens · 2 Reset · 3 Layout · 4 Typography
   5 Buttons · 6 Header · 7 Footer · 8 Components · 9 Page blocks
   10 Forms · 11 Utilities · 12 Motion & responsive
   ========================================================================== */

/* 0. Fonts ---------------------------------------------------------------
   Poppins alone, self-hosted, Open Font License. Self-hosted rather than
   CDN-linked: no third-party request, no layout shift, works offline and
   behind restrictive firewalls.

   One family for everything: the wordmark, headlines, running text, and
   the labels and figures that used to be set in Roboto Mono. Those keep
   their uppercase and their letter-spacing, which is what separated them
   from running text rather than the face itself.

   Poppins ships as static weights rather than a variable font, so each
   weight is its own file — 400 text, 500 labels and buttons, 600
   headlines, 700 figures. Four files at ~8KB each. */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/poppins-400-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/poppins-500-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/poppins-600-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/poppins-700-latin.woff2") format("woff2");
}

/* 1. Design tokens -------------------------------------------------------
   Contrast notes (WCAG 2.1, measured against the grounds actually used):

   · Brand orange #E13B06 reaches only 4.35:1 on white and 2.81:1 on forest
     green, so it cannot carry text at body or button size in either place.
     It is kept at full strength for non-text marks — the section rule, the
     nav underline — where the 3:1 threshold applies.
   · --accent-ink #B62E04 is that orange darkened for text and buttons on
     light grounds. It clears 4.5:1 on all four — raised 6.21, sky 5.95,
     alt 5.31, tint 4.85 — which is what set the value: the deepest tint
     is the binding ground, not white.
   · --accent-glow #FF7A4D is it lightened for use on forest: 4.74:1.
   · Wine #A32020 needed no adjustment — 7.54:1 either way.
   · Neutrals carry a slight green bias so they sit with the forest rather
     than reading as an unrelated stock grey. */
:root {
  /* Brand — forest green */
  --forest-900: #10281a;
  --forest-800: #193c27;   /* supplied */
  --forest-700: #245436;
  --forest-600: #2f6b46;

  /* Brand — orange */
  --orange-500: #e13b06;   /* supplied — non-text marks only */
  --accent-ink: #a52905;   /* text and buttons on light grounds */
  --accent-glow: #ff7a4d;  /* text and marks on forest grounds */

  /* Brand — wine. Carries the closing call to action, so the page ends on
     a different colour from the one it opens on. */
  --wine-600: #a32020;     /* supplied */
  --wine-700: #8a1b1b;
  --wine-800: #6d1515;

  /* Neutrals (green-biased). Nothing on the site is pure white: the base
     ground is the supplied sky, and the alternating band is a green tint
     deep enough to actually read as a band. */
  --ink-900: #232323;      /* supplied */
  --ink-700: #3f4742;
  --ink-500: #47504a;
  --ink-400: #4d564f;      /* lightest tone passing 4.5:1 on every ground */
  /* Softened from #c8d3cb. The rule was built to be the main structural
     device and ended up asserting itself in a dozen components at once; a
     page carrying this many of them wants them to sit back and separate
     rather than draw. */
  --line: #d4ddd6;
  --line-strong: #a6b4aa;
  /* Form controls need their boundary to carry 3:1 under WCAG 1.4.11, and
     --line-strong only reaches 2.07:1 on the form card. This is the same
     hue, taken down until it clears the threshold at 3.21:1. */
  --field-line: #7f8f84;
  /* The ground was the supplied "sky" at 98% white, with pure-white cells on
     top of it — a step so small that nothing read as raised and the whole
     page read as blank paper. Sky moves up to become the raised surface,
     which is the role a near-white actually belongs in, and the grounds step
     down into green-neutral so a band is a tone rather than an absence. */
  --surface: #e9eee9;      /* page ground */
  --surface-alt: #dae3db;  /* the alternating band */
  --surface-tint: #c9d6cb;  /* deepest light tone */
  --surface-raised: #f9fafd;  /* supplied "sky" — cells, so they lift */

  /* Text on forest grounds */
  --on-dark: #c5d3ca;
  --on-dark-muted: #b8c6bc;
  --rule-dark: rgba(255, 255, 255, 0.14);

  /* Status — deliberately outside the brand hues so state never reads
     as branding. */
  --success: #1c7a52;
  --danger: #b3261e;

  /* Type — Poppins carries the wordmark, headlines and running text; mono
     keeps the data, codes and labels. */
  --font-body: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Arial, sans-serif;
  --font-display: var(--font-body);
  /* The label role: eyebrows, codes, figures and table headers. It was
     Roboto Mono; the site is one family now, so this is Poppins with the
     uppercase and letter-spacing doing the work the mono face used to. */
  --font-label: var(--font-body);
  --font-wordmark: var(--font-body);

  /* Type scale. Five steps, each with a job, because one heading size doing
     every job is what makes a page read as generated. The ratio tightens as
     it descends, which is how a scale is supposed to behave: 1.53 from
     section to display, 1.19 from body to card.

     At 1280px these land on 67 / 44 / 33 / 24 / 19 against a 16px body.

     display  once a page at most, and only where the headline is the thing
              the visitor came for
     lead     a section whose heading IS the argument, not a label for what
              sits under it
     section  the workhorse: a heading that names the block below it
     sub      a section whose content is a figure, so the heading steps back
              and lets the graphic carry it
     card     titles inside cards and list items */
  /* 5.9vw rather than 6.2: at 1024 the headline needed 977px of a 976px
     column and broke by one pixel. Desktop is unaffected, because from
     1280 up this is pinned at the 4.2rem ceiling either way. */
  --step-display: clamp(2.4rem, 5.9vw, 4.2rem);
  --step-lead: clamp(1.95rem, 4.2vw, 2.75rem);
  --step-section: clamp(1.5rem, 2.9vw, 2.05rem);
  --step-sub: clamp(1.2rem, 1.9vw, 1.5rem);
  --step-card: clamp(1.02rem, 1.55vw, 1.18rem);

  /* Space & shape. Every corner on the site resolves to one of these four
     values — nothing hardcodes a radius — so the whole shape language can
     be tuned from here. */
  --container: 1160px;
  --container-narrow: 780px;
  --gutter: 1.5rem;
  --radius-sm: 10px;    /* inputs, small controls, status strips */
  --radius: 18px;       /* cards, blocks, media, panels */
  --radius-lg: 28px;    /* the largest surfaces: form card, accordion */
  --radius-pill: 999px; /* tags, practice codes, icon wells, rule caps */

  /* Motion. One curve and one duration scale, so everything on the page
     accelerates and settles the same way — that consistency is what reads
     as "considered" rather than "animated". --ease-out leaves immediately
     and decelerates into place; nothing on this site eases in, because a
     slow start feels like lag on a control you just clicked. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --dur-1: 140ms;  /* colour and small state flips */
  --dur-2: 240ms;  /* hovers, presses, nudges */
  --dur-3: 380ms;  /* panels opening, heights resolving */
  --dur-4: 560ms;  /* entrances */

  /* Shadows are reserved for things that genuinely float above the page:
     the sticky header and the mobile nav drawer. Nothing else lifts. */
  --shadow-header: 0 1px 0 rgba(25, 60, 39, 0.08),
    0 4px 16px rgba(25, 60, 39, 0.06);
  --shadow-drawer: 0 12px 32px rgba(25, 60, 39, 0.14);

  /* Block extrusion. A hard offset edge, never a blur — the card reads as a
     solid printed block sitting on the page rather than something floating
     above it, which is the one way this system will do depth. */
  --block-edge: #c2d0c6;
  --block-edge-dark: #0a1c11;

  /* Taller, so the wordmark can be the size it is on the reference rather
     than a line of text squeezed into a bar. Everything that hangs off the
     header (the menu panel, the practice rail, anchor scroll offsets) reads
     this token, so they all follow. */
  --header-h: 96px;
}

/* 2. Reset --------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* The site at nine tenths. Everything measured in rem — type, spacing,
     the block paddings — comes down by a tenth, which reproduces what a
     browser at 90% zoom does: at 1280 the headline goes 67.2px to 60.5px,
     the lede 18.4 to 16.6, a section's padding 47.4 to 43.2, each matching
     the zoomed figures to the decimal.

     A percentage, not a pixel value: it is nine tenths of whatever the
     reader has set as their own default, so someone browsing at 20px still
     gets their larger type, scaled. A px here would overrule them. */
  font-size: 90%;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

/* A short page used to end wherever its content ended, leaving the body
   showing below the footer — 232px of it on contact at 1280x1600, and
   714px on the 404. The page is a column the height of the viewport, and
   main takes up whatever slack there is, so the footer sits at the bottom
   of the screen when the content does not reach it and is pushed down
   normally when it does. The skip link is absolute and the script does not
   render, so header, main and footer are the only flex items. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.98rem;
  font-weight: 400;
  line-height: 1.72;
  color: var(--ink-700);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
}

main {
  flex: 1 0 auto;
}

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

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

a:hover {
  color: var(--wine-600);
}

ul,
ol {
  margin: 0;
  padding: 0;
}

button {
  font: inherit;
  cursor: pointer;
}

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

.skip-link {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 200;
  background: var(--forest-800);
  color: #fff;
  padding: 0.75rem 1.25rem;
  /* Parked above the viewport rather than at left:-9999px, so it can slide
     in — an offscreen position is not a transitionable value. */
  transform: translateY(-120%);
  transition: transform var(--dur-2) var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
  color: #fff;
}

/* 3. Layout -------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* A reading measure that starts where the page's other columns start. This
   used to be a narrower box with the auto margins it inherited from
   .container, which put the column in the middle of the page under a
   left-aligned headline. Invisible while a third of a screen separated the
   two; obvious once they sit together.

   So the box is now an ordinary container and the measure is capped on the
   content instead. Same line length as before, and the left edge matches
   the headline at every width without doing arithmetic on the viewport. */
.container-narrow > * {
  max-width: calc(var(--container-narrow) - var(--gutter) * 2);
}

.section {
  /* Every band pays this twice, and two bands meeting pay it four times:
     at 4rem a plain section boundary was 128px of nothing at 1280. The
     bands already separate themselves by changing surface, and every block
     inside carries its own margins, so the padding only has to keep the
     content off the seam. */
  padding-block: clamp(2rem, 3.7vw, 3rem);
}

.section-tight {
  padding-block: clamp(1.4rem, 2.6vw, 1.9rem);
}

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

.section-tint {
  background: var(--surface-tint);
}

.section-dark {
  background: var(--forest-800);
  color: var(--on-dark);
}

.section-dark h2,
.section-dark h3 {
  color: #fff;
}

/* The hairline grid. Cells sit on a rule-coloured ground with a 1px gap,
   so dividers are exactly one pixel and never double up — the same way a
   ruled schedule is set. */
.grid {
  display: grid;
  gap: clamp(0.9rem, 1.6vw, 1.35rem);
}

/* No bed and no outer frame: the cells used to be drawn by this rule-coloured
   ground showing through a 1px gap, but blocks bring their own outline and
   edge, so it would only read as a slab behind them. */

.grid-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.grid-3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.grid-4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* The process list borrows .grid-2 for its columns but is not a ruled
   schedule, so it opts back out of the hairline ground. */
.steps.grid-2 {
  background: transparent;
  border: 0;
  gap: 2.25rem 3rem;
}

.split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

/* 4. Typography ----------------------------------------------------------
   One family for language, one for data. Hierarchy comes from weight, size
   and tracking rather than contrasting faces. */
/* Serif headlines need far less negative tracking than the sans did — the
   letterforms already have the width. */
h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  color: var(--forest-800);
  line-height: 1.18;
  margin: 0 0 0.6em;
  font-weight: 600;
  letter-spacing: -0.026em;
  text-wrap: balance;
}

h1 {
  font-size: clamp(2.05rem, 4.5vw, 3.05rem);
  letter-spacing: -0.038em;
  line-height: 1.08;
}

h2 {
  font-size: var(--step-section);
  letter-spacing: -0.032em;
  line-height: 1.15;
}

/* The heading is the argument. Tracking tightens as the size grows, which
   is why these are not one rule with a variable in it.

   Only valid on a page with a display h1 above it, which means the home
   page. On an inner page the h1 is clamp(1.95rem, 3.4vw, 3rem), so at
   1280px it renders 43.5px and this renders 44 — the section heading would
   outgrow the page title. On an inner page the thesis is the h1 already. */
.h2-lead {
  font-size: var(--step-lead);
  letter-spacing: -0.035em;
  line-height: 1.08;
  max-width: 20ch;
}

/* The figure below is the content; the heading announces it and gets out
   of the way. */
.h2-quiet {
  font-size: var(--step-sub);
  letter-spacing: -0.022em;
}

h3 {
  font-size: var(--step-card);
  letter-spacing: -0.02em;
}

h4 {
  font-size: 1.02rem;
}

p {
  margin: 0 0 1.1rem;
}

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

/* The section marker. A short orange rule opens every section — the one
   structural place the full-strength brand orange appears. */
.eyebrow {
  display: block;
  font-family: var(--font-label);
  font-size: 0.71rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-400);
  margin-bottom: 1rem;
}

/* No tick above the label. The eyebrow is already set apart by being the
   only mono, uppercase, letter-spaced line on the page; a short orange bar
   over every one of them was a second announcement of the same thing, and
   at one per section head, per card and per panel it was the most repeated
   mark on the site. */

/* The home hero's list of services is the one eyebrow left on the site;
   every other one has been removed, and with them the rules that coloured
   an eyebrow for a dark band, a light page hero or a wine call to action. */
.hero .eyebrow {
  color: var(--on-dark-muted);
}

/* Standfirst — the sans paragraph that sits under a serif headline and
   carries the summary. Kept sans so it reads as a different voice from the
   headline, the way a newspaper sets it. */
.lede {
  font-family: var(--font-body);
  font-size: clamp(1.02rem, 1.5vw, 1.15rem);
  font-weight: 400;
  color: var(--ink-500);
  line-height: 1.65;
  max-width: 62ch;
}

.section-dark .lede {
  color: var(--on-dark);
}

/* Section head — the label and the headline, with no rule above them.

   This used to be the broadsheet device: a hairline running the full
   measure with a short orange segment starting it. One per section meant
   a long line drawn across the page every time the subject changed, which
   is the opposite of the blend this site is after. The rule is gone and
   the eyebrow's own short mark, the one the hero and the page heroes
   already use, does the announcing instead. */
.section-head {
  position: relative;
  max-width: 46rem;
  margin-bottom: clamp(1.25rem, 2.3vw, 1.65rem);
}

/* Heading and lede side by side instead of stacked. The headline gets to run
   large on the left while the explanatory sentence sits quietly to the right,
   baseline-aligned with it, rather than pushing the section content down. */
.section-head-split {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 0 clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

.section-head-split h2 {
  grid-column: 1;
}

.section-head-split h2 {
  margin-bottom: 0;
  max-width: 18ch;
}

.section-head-split .lede {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: end;
  margin: 0;
  max-width: 44ch;
}

@media (max-width: 800px) {
  .section-head-split {
    grid-template-columns: 1fr;
  }

  .section-head-split h2,
  .section-head-split .lede {
    grid-column: 1;
  }

  .section-head-split .lede {
    grid-row: auto;
    margin-top: 1.1rem;
  }

  .section-head-split h2 {
    max-width: none;
  }
}

/* 5. Buttons -------------------------------------------------------------
   Buttons are language, so they stay in Roboto. The accent button fills
   with --accent-ink because white on the full-strength orange is 4.35:1
   and would fail. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.82rem 1.55rem;
  border: 1px solid transparent;
  /* Rounded rectangle rather than a pill. Buttons are the one place the
     radius reads as a shape rather than a corner treatment, and the pill
     was pulling the whole page toward a softer register than the block
     edges elsewhere. */
  border-radius: var(--radius-sm);
  font-size: 0.93rem;
  font-weight: 500;
  text-align: center;
  transition:
    background-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    transform var(--dur-2) var(--ease-out);
}

/* Buttons lift toward the pointer and give the travel back on click, so a
   press registers physically before the page has done anything. */
.btn:hover {
  transform: translateY(-2px);
}

.btn:active {
  transform: translateY(0);
}

.btn-primary {
  background: var(--forest-800);
  color: #fff;
}

.btn-primary:hover {
  background: var(--forest-600);
  color: #fff;
}

.btn-accent {
  background: var(--accent-ink);
  color: #fff;
}

.btn-accent:hover {
  background: var(--wine-600);
  color: #fff;
}

/* The home headline's orange, carried onto a button. White on it measures
   2.58:1, so the label is forest-900 instead: the same pair as the
   headline, the other way round, at 6.07:1. --accent-ink, which the
   closing call to action uses, is a different orange chosen because white
   does hold on it. */
.btn-glow {
  background: var(--accent-glow);
  color: var(--forest-900);
}

.btn-glow:hover {
  background: #ff8c63;
  color: var(--forest-900);
}

.btn-outline {
  border-color: var(--line-strong);
  background: transparent;
  color: var(--forest-800);
}

.btn-outline:hover {
  border-color: var(--forest-800);
  background: var(--forest-800);
  color: #fff;
}

.btn-ghost-light {
  border-color: rgba(255, 255, 255, 0.45);
  color: #fff;
}

.btn-ghost-light:hover {
  background: #fff;
  color: var(--forest-800);
}

.btn-sm {
  padding: 0.58rem 1.05rem;
  font-size: 0.86rem;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-label);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

.link-arrow::after {
  content: "→";
  transition: transform var(--dur-1) var(--ease-out);
}

.link-arrow:hover::after {
  transform: translateX(3px);
}

/* 6. Header -------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  /* Forest, not the near-white it was. Matched to the top of the hero
     gradient so at rest the bar and the hero read as one panel; once the
     page scrolls under it, it becomes a hard dark edge against the light
     bands instead of a pale strip that disappeared into them. */
  background: var(--forest-900);
  /* Transparent, not removed: the hero below is now the same flat green, so
     a hairline here would be the one seam left across it. The rule keeps
     its place in the box model so nothing shifts by a pixel. */
  /* No backdrop-filter. It would make the header the containing block for
     the fixed nav panel below, which could then never reach the bottom of
     the screen. At 96% opaque the blur was doing almost nothing anyway. */
  border-bottom: 1px solid transparent;
}

/* Open, the header is the top of the panel rather than a bar above it: same
   green, no rule between them, no shadow cast onto something that is now the
   same surface. The wordmark still reads because it is white on forest, not
   because the bar behind it is a different tone. */
.site-header:has(.site-nav.is-open) {
  border-bottom-color: transparent;
  box-shadow: none;
}

/* No shadow on the scrolled bar, and none at rest either.

   It was there from when this header was near-white and needed lifting off
   the page. A forest-900 bar needs nothing: against the light bands the
   colour is the separation, and against the hero and the ribbon — the same
   forest as the bar — any cast is a tonal step through one continuous
   green. Sampled across eight columns, the shadow took the first pixel
   below the bar from rgb(16,40,26) to rgb(14,37,24) with no gradient
   leading into it, which is the line that kept showing up. The two now
   read as one surface, which is what the flat hero was for. */

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: var(--header-h);
}

/* Wordmark — "FortuneFinance" set as one word in forest green, in Poppins
   like the rest of the site. One text run, no overlap, no visual split
   between Fortune and Finance. Set a step heavier and tighter than a
   heading so it reads as a mark rather than as a line of text. */
 /* The wordmark is the only way home from every page now that the
    breadcrumb is gone, so it has to behave like a control rather than a
    logo: a tap target over the 44px minimum, a colour shift, a press, and
    a focus ring. The negative margin keeps the header height unchanged. */
.brand {
  display: inline-flex;
  flex-direction: column;
  gap: 0.22rem;
  padding-block: 0.5rem;
  margin-block: -0.5rem;
  border-radius: var(--radius-sm);
  color: #fff;
  transition:
    color var(--dur-1) var(--ease-out),
    transform var(--dur-2) var(--ease-out);
}

/* No colour change. The wordmark went orange on hover, and on a
   touchscreen a tap fires hover and leaves it there, so the logo stayed
   orange after you pressed it. The press itself is the feedback.

   Stated rather than simply deleted: the brand is an <a>, so dropping its
   own hover colour handed it to the global `a:hover`, which turned the
   logo wine instead of orange. */
.brand:hover {
  color: #fff;
}

.brand:active {
  transform: scale(0.985);
}

.brand:focus-visible {
  outline: 2px solid var(--accent-glow);
  outline-offset: 4px;
}

.wordmark {
  display: block;
  font-family: var(--font-wordmark);
  /* Lowercased here rather than in the markup, so every page still carries
     "FortuneFinance" in the DOM: that is the company's name, and it is what
     a screen reader announces and what a search engine indexes. The logo is
     a drawing of the name, not the name itself. */
  text-transform: lowercase;
  /* The same three values the inner-page headline is set in: it is the same
     family, so matching size, weight and tracking makes the wordmark and
     that headline one voice rather than two near-misses. */
  font-size: clamp(1.95rem, 3.4vw, 3rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
  color: inherit;
}

 /* Just the bars. The width and height stay — they are the tap target, and
    that has to clear 24px whether or not anything is drawn around it. */
/* The bar is a wordmark and a menu button now, but the wordmark at its
   normal size still crowds the button under 420px. It steps down; measured
   so 320px fits. */
@media (max-width: 420px) {
  .site-header .wordmark {
    font-size: 1.25rem;
  }
}

.nav-toggle {
  display: block;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 0;
  background: transparent;
}

.nav-toggle:hover .nav-toggle-bars,
.nav-toggle:hover .nav-toggle-bars::before,
.nav-toggle:hover .nav-toggle-bars::after {
  background: var(--accent-glow);
}

/* The bar itself goes transparent when open, so keep the hover off it. */
.nav-toggle[aria-expanded="true"]:hover .nav-toggle-bars {
  background: transparent;
}

.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 26px;
  height: 2px;
  margin-inline: auto;
  background: var(--on-dark);
  transition: transform var(--dur-2) var(--ease-out), opacity var(--dur-2) var(--ease-out);
}

.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: "";
  position: relative;
}

.nav-toggle-bars::before {
  top: -6px;
}

.nav-toggle-bars::after {
  top: 6px;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bars {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before {
  transform: translateY(6px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after {
  transform: translateY(-6px) rotate(-45deg);
}

/* Open is a state, not a hover. The X held the resting grey until the
   pointer came back to it, so the one control that was doing something
   looked like the one control that was not. It now carries the same orange
   as the headline and as its own hover, for as long as the panel is open.
   Same specificity as the hover rule above and the same value, so which of
   the two applies never matters. */
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before,
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after {
  background: var(--accent-glow);
}

/* The panel runs from under the header to the bottom of the screen, in the
   same green as the header, so the two read as one surface and none of the
   page shows through behind it. */
.site-nav {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  z-index: 95;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  padding: 0 0 1.75rem;
  background: var(--forest-900);
  /* Slides down from behind the header rather than fading in place, so the
     movement reads as the panel arriving from above. */
  transform: translateY(-1.5rem);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-2) var(--ease-out),
    visibility var(--dur-2);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.site-nav.is-open {
  transform: none;
  opacity: 1;
  visibility: visible;
}

/* Rows line up under the wordmark rather than against the raw screen edge,
   so the panel reads as part of the same page grid as everything else. */
.nav-list {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  list-style: none;
}

/* No dividers between the rows. Spacing separates them, which is quieter
   than a rule per item and stops the panel reading as a table. */

/* Set as words rather than as labels: sentence case, normal tracking, and
   enough room around each one that nothing has to be drawn between them. */
.nav-list a {
  position: relative;
  display: block;
  padding-block: clamp(0.85rem, 1.9vh, 1.15rem);
  font-size: clamp(1.02rem, 1.3vw, 1.2rem);
  font-weight: 400;
  color: var(--on-dark);
}

.nav-list a:hover {
  color: #fff;
}

/* Sized to its label rather than stretched across the panel: a full-width
   light slab pulls more weight than the menu it sits under. The margin puts
   its left edge on the same line as the labels at any width, without needing
   a wrapper element around it. */
/* The current page is marked by the accent on the label itself. The sliding
   underline this used to have belonged to links in a row; against a divider
   it just drew a second line. */
.nav-list a[aria-current="page"] {
  color: var(--accent-glow);
}

/* Practice index — a sticky bar of the ten practice codes that tracks
   which service is in view. Ten sections is too many to hold in your head,
   so this is a wayfinding device first and an ornament never. 

 /* No underline marks the practice in view any more. Weight carries it,
    which is a non-colour cue, with the darker ink reinforcing it. 

/* Anchors must clear both the header and the rail when jumped to. 

/* 7. Footer --------------------------------------------------------------
   Brand block plus three link columns. Legal sits in a column of its own
   rather than crammed into the bottom bar, and the bottom bar carries the
   regulatory note a finance firm is expected to state. */
/* The footer is a directory. Its chrome was 192px of the 555px it stood at
   1280 — 72 above the columns, 56 under them, and 64 around the small print
   — so a third of it was padding. Each of those is cut to what keeps the
   blocks apart rather than what holds them in a frame. */
.site-footer {
  background: var(--forest-900);
  color: var(--on-dark-muted);
  padding-top: clamp(2.25rem, 4vw, 3rem);
  font-size: 0.92rem;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 0.85fr;
  /* Split: the columns need the width between them, but when they wrap the
     same figure becomes a 51px hole between stacked blocks. */
  gap: clamp(1.5rem, 2.6vw, 2.25rem) clamp(2rem, 4vw, 3.5rem);
  padding-bottom: clamp(1.75rem, 3vw, 2.25rem);
}

.site-footer h4 {
  color: #fff;
  font-family: var(--font-label);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin-bottom: 0.9rem;
}

.footer-brand .brand,
/* The footer is a directory, not a title page. The header wordmark renders
   43.5px at 1280; here it takes the scale's sub step, which is the size a
   heading uses when it is announcing something rather than being the thing.
   A step from the scale rather than a number picked by eye. */
.footer-brand .wordmark {
  color: #fff;
  font-size: var(--step-sub);
  letter-spacing: -0.025em;
}

.footer-blurb {
  margin-top: 0.85rem;
  max-width: 34ch;
  color: var(--on-dark-muted);
  line-height: 1.65;
}

.footer-email {
  display: inline-block;
  margin-top: 0.85rem;
  color: var(--on-dark);
  font-size: 0.9rem;
}

.footer-email:hover {
  color: var(--accent-glow);
}

/* Social row. The 40px well is the tap target, so no coarse-pointer rule is
   needed; the negative left margin pulls the first glyph back into line with
   the text above it, which the well would otherwise indent by 10px. */
.social-links {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
  margin: 0.8rem 0 0 -10px;
}

.social-links a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  color: var(--on-dark-muted);
  transition: color var(--dur-2) var(--ease-out),
              background-color var(--dur-2) var(--ease-out),
              transform var(--dur-2) var(--ease-out);
}

.social-links a:hover {
  color: var(--accent-glow);
  background: rgba(255, 255, 255, 0.07);
  transform: translateY(-2px);
}

.social-links a:focus-visible {
  outline: 2px solid var(--accent-glow);
  outline-offset: 2px;
}

.social-links svg {
  width: 20px;
  height: 20px;
}

.footer-links {
  list-style: none;
  display: grid;
  gap: 0.55rem;
}

.footer-links a {
  color: var(--on-dark-muted);
  transition: color var(--dur-1) var(--ease-out);
}

.footer-links a:hover {
  color: var(--accent-glow);
}

.footer-bottom {
  display: grid;
  gap: 0.6rem;
  padding-block: 1.25rem 1.6rem;
  border-top: 1px solid var(--rule-dark);
  font-size: 0.85rem;
  color: var(--on-dark-muted);
}

.footer-bottom p {
  margin: 0;
}

/* Without this the phone number takes the global link colour, which is the
   accent tuned for light grounds and measures 2.2:1 against the footer. */
.footer-bottom a {
  color: var(--on-dark-muted);
  transition: color var(--dur-1) var(--ease-out);
}

.footer-bottom a:hover {
  color: var(--accent-glow);
}

.footer-note {
  max-width: 90ch;
  font-size: 0.82rem;
  line-height: 1.6;
  color: rgba(197, 211, 202, 0.72);
}

@media (max-width: 900px) {
  .footer-grid {
    grid-template-columns: 1fr 1fr;
    /* Same split as the base rule: the columns keep their width apart, the
       stacked blocks do not need 40px between them. */
    gap: 1.6rem 2.5rem;
  }

  .footer-brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 560px) {
  .footer-grid {
    grid-template-columns: 1fr;
  }
}

/* 8. Components ----------------------------------------------------------
   Cells, not cards: flat, square, separated by the grid's hairlines. */
/* Blocks. Square corners, a hairline outline and a hard offset edge, so the
   grid reads as a set of solid tiles rather than a run of ruled cells.
   Interactive blocks press into the page on hover — the edge collapses as
   the block travels the same distance, which is what sells the depth. */
.card {
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 2.4vw, 2rem);
  box-shadow: 5px 5px 0 var(--block-edge);
  transition:
    transform var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out),
    background-color var(--dur-2) var(--ease-out);
}

.card-hover:hover {
  transform: translate(4px, 4px);
  box-shadow: 1px 1px 0 var(--block-edge);
}

.card-hover:active {
  transform: translate(5px, 5px);
  box-shadow: 0 0 0 var(--block-edge);
}

.card-hover:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

/* Short accent rule at the head of every card that is itself a link. Orange
   stays on the site's one rule — it marks things you can act on — and it
   gives the grid a repeating tick that reads like an index. */
.card-hover {
  position: relative;
}

/* The tick that used to head every linked card is gone with the rest of
   them. The card still signals that it is a link: it carries the hard
   offset edge, and it presses in on hover and on focus. */

/* Hover shifts the ground rather than lifting the cell — a ruled schedule
   does not float. */
.card-hover:hover {
  background: var(--surface-alt);
}

.card-hover:hover h3 {
  color: var(--accent-ink);
}

.card h3 {
  margin-bottom: 0.5rem;
}

.card p {
  color: var(--ink-500);
  font-size: 0.95rem;
}

.card-icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-bottom: 1.35rem;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--forest-600);
}

.card-icon svg {
  width: 26px;
  height: 26px;
}

.card-link {
  margin-top: 1.2rem;
}

/* Audit tick — the mark an accountant puts beside a verified line. */
.checklist {
  list-style: none;
  display: grid;
  gap: 0.8rem;
  margin-top: 1.5rem;
}

.checklist li {
  position: relative;
  padding-left: 1.85rem;
  color: var(--ink-700);
}

.checklist li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--font-label);
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--forest-600);
}

/* Every dark ground, not just .section-dark — the hero and page hero carry
   checklists too, and inheriting the light-ground ink puts dark text on a
   dark panel. */
.section-dark .checklist li,
.hero .checklist li,
.cta-band .checklist li {
  color: var(--on-dark);
}

.section-dark .checklist li::before,
.hero .checklist li::before,
.cta-band .checklist li::before {
  color: var(--accent-glow);
}

/* The engagement process is a genuine sequence, so it keeps its numbering.
   The figure sits in the margin over a rule, like a schedule reference. */
.steps {
  counter-reset: step;
  list-style: none;
  display: grid;
  gap: 1.75rem;
}

.step {
  counter-increment: step;
  position: relative;
  padding-left: 3.6rem;
}

.step::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0.15rem;
  width: 2.4rem;
  padding-bottom: 0.3rem;
  border-bottom: 2px solid var(--orange-500);
  font-family: var(--font-label);
  font-size: 0.82rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  color: var(--forest-800);
}

.step h3 {
  margin-bottom: 0.3rem;
}

.step p {
  color: var(--ink-500);
  font-size: 0.95rem;
}

/* Editorial pull-quote: ruled top and bottom, nothing floating. */
.quote {
  margin: 0;
  padding: clamp(2rem, 4vw, 2.75rem) 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--forest-800);
  border-bottom: 1px solid var(--forest-800);
  border-radius: 0;
  box-shadow: none;
}

.quote p {
  font-size: clamp(1.2rem, 2.2vw, 1.6rem);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.45;
  color: var(--forest-800);
  text-wrap: balance;
}

.quote footer {
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-family: var(--font-label);
  font-size: 0.74rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-400);
}

.quote cite {
  display: block;
  font-style: normal;
  font-weight: 700;
  color: var(--forest-800);
  margin-bottom: 0.2rem;
}

/* Set as a plain line under the name rather than as a tracked uppercase
   label. "Chief Executive Officer & Chief Financial Officer" in caps at
   0.14em ran to three lines and read as a stamp on the portrait; in
   sentence case it is what it is, the person's title. */
.person-role {
  font-size: 0.88rem;
  line-height: 1.4;
  color: var(--ink-500);
  margin-bottom: 0;
}

.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  list-style: none;
  margin-top: 1.5rem;
}

.tag {
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  font-family: var(--font-label);
  font-size: 0.68rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-500);
}

.section-dark .tag {
  border-color: var(--rule-dark);
  color: var(--on-dark);
}

.article-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.article-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.9rem;
  padding-bottom: 0.85rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-label);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-400);
}

.article-meta .topic {
  color: var(--accent-ink);
  font-weight: 700;
}

.article-card p {
  flex: 1;
}

/* Accordion. A stack of rounded cards rather than the hairline rules used
   elsewhere: the FAQ is a set of controls, not a document surface, so it
   is the one block on the site allowed a large radius and a lift. One
   answer is open at a time, and the panel animates its height rather than
   snapping — see initAccordion in main.js.

   Built on <details>/<summary> so it degrades honestly: with scripting
   off you get native disclosure, every answer reachable and printable.
   The collapse and the height transition are only armed once JS has
   marked the group .is-enhanced. */
/* Two columns of flat rows, from the reference FAQ. Each column is its own
   block rather than the questions flowing across a shared grid: in a grid
   the two columns share row heights, so opening an answer on the right tore
   a hole in the left. Here an opening panel only ever moves what is under
   it in its own column. The hairline is the separator a list of questions
   wants, and it is the one place on this site a rule still earns its keep. */
/* One column, not two. Seven questions split into two columns forces the
   reader's eye back and forth across the page and leaves an odd short
   column on one side; stacked, it reads straight down. */
.accordion {
  display: grid;
  grid-template-columns: 1fr;
  align-items: start;
}

.accordion-col {
  min-width: 0;
}

.accordion details {
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  transition: border-color 200ms ease;
}

.accordion details[open] {
  border-bottom-color: var(--line-strong);
}

.accordion summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.15rem 0 1.15rem 0;
  font-size: clamp(1.05rem, 1.6vw, 1.2rem);
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.35;
  color: var(--forest-800);
  cursor: pointer;
  list-style: none;
  -webkit-user-select: none;
  user-select: none;
}

.accordion summary::-webkit-details-marker {
  display: none;
}

.accordion summary:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: -3px;
  border-radius: var(--radius-lg);
}

/* Plus that spins into a minus: two bars, the upright one rotating flat
   and fading as the whole well turns 180°. */
.accordion-icon {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  width: 2.25rem;
  height: 2.25rem;
  align-items: center;
  justify-content: center;
  color: var(--accent-ink);
  transition: transform var(--dur-3) var(--ease-out);
}

.accordion-icon::before,
.accordion-icon::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 1.75px;
  border-radius: 1px;
  background: currentColor;
  transition:
    transform var(--dur-3) var(--ease-out),
    opacity 200ms ease;
}

.accordion-icon::after {
  transform: rotate(90deg);
}

.accordion details[open] .accordion-icon {
  transform: rotate(180deg) scale(1.05);
}

.accordion details[open] .accordion-icon::after {
  transform: rotate(0deg);
  opacity: 0;
}

/* Height is written inline by JS; the transition lives here. */
.accordion.is-enhanced .accordion-panel {
  height: 0;
  overflow: hidden;
  transition: height var(--dur-3) var(--ease-out);
}

.accordion .accordion-body {
  padding: 0 0 1.6rem;
  color: var(--ink-500);
  font-size: 1.02rem;
  line-height: 1.75;
  max-width: 62ch;
}

.accordion.is-enhanced .accordion-body {
  opacity: 0;
  transform: translateY(-8px);
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-3) var(--ease-out);
}

.accordion.is-enhanced details[open] .accordion-body {
  opacity: 1;
  transform: none;
}

@media (max-width: 560px) {
  .accordion summary {
    padding: 1rem 0.5rem 1rem 1.35rem;
  }

  .accordion .accordion-body {
    padding: 0 1.35rem 1.5rem;
  }
}

/* 9. Page blocks --------------------------------------------------------- */

/* Ledger paper: faint horizontal rules over the forest ground. */
.hero {
  position: relative;
  overflow: hidden;
  /* The same flat green the header and the open menu are painted in, so
     the top of the page is one surface rather than three. This carried a
     32px rule grid and a 168deg gradient, and closed on a 3px double
     border; all of it is gone. */
  background: var(--forest-900);
  color: var(--on-dark);
  /* Still asymmetric — the text starts close under the logo and the band
     opens out below it rather than boxing it in the middle — but the open
     space was running to 16rem, which left the ribbon marooned at the far
     end of an empty field. Roughly one part above to four below. */
  padding-top: clamp(1.25rem, 2.2vw, 1.9rem);
  padding-bottom: clamp(5rem, 8.5vw, 7.5rem);
}

/* The column rules that used to fade in across the right of the hero are
   gone with the horizontal ones. The band is one flat green. */

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

/* Single column, given room to breathe. The headline is the whole point of
   the panel, so nothing sits beside it competing for width. */
.hero-inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* No min-height. The band used to be a fixed height with the text
     centred in it, so whatever the text did not use became empty green
     above and below it. The hero is the size of what it says. */
}

.hero h1 {
  /* The brand orange, in the form of it that is legible on forest. The
     supplied #e13b06 manages 3.6:1 on this green, which is why the token
     beside it exists and why --orange-500 is marked for marks only; this
     one is the same orange lifted to 6.07:1. */
  color: var(--accent-glow);
  /* No measure cap: the line is meant to run the width of the container as
     one line, and 15ch was what forced the break after "finance". */
  font-size: var(--step-display);
  line-height: 1.04;
  letter-spacing: -0.035em;
}

/* The distinctive half of the headline, carried in the one colour the site
   spends on things that matter. */
/* White, like the rest of the line. The span stays so the second half can
   be picked out again later without touching the markup. */
.h1-accent {
  color: inherit;
}

.hero p {
  max-width: 50ch;
  color: var(--on-dark);
  font-size: clamp(1.02rem, 1.6vw, 1.15rem);
  font-weight: 400;
}

/* Eyebrow as a service list — says what the firm sells before the headline
   gets a chance to be poetic about it. Drops the rule the plain eyebrow
   carries, since the middots are already doing the separating. */
.eyebrow-list {
  max-width: none;
  /* Never let a lone service drop to its own line behind a dangling middot. */
  text-wrap: balance;
}

/* The rule that hid this eyebrow's tick is gone with the tick itself. */


/* The checklist as a standalone band: ruled rows rather than a loose list,
   so it reads as a schedule like the rest of the site. */
.checklist-band {
  margin-top: 2rem;
  gap: 0;
  border-top: 1px solid var(--line);
}

 /* A row of things you can tick off, so the mark is a filled checkbox
    rather than a bare glyph. Laid out as a grid rather than an absolutely
    positioned ::before, which is what left the tick pinned to the top of
    the row while its label sat a rem below it. */
.checklist-band li {
  display: grid;
  grid-template-columns: 1.25rem 1fr;
  align-items: center;
  gap: 0.95rem;
  padding: 0.7rem 0 0.7rem 1rem;
}

.checklist-band li::before {
  content: "";
  position: static;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 6px;
  background-color: var(--forest-700);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.4l3 3 6-6.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 0.8rem;
}

/* Light, not the forest band the home page opens on. The dark ground and
   the heavy headline are the home page's voice; an inner page arrives with
   the reader already inside the site and does not need announcing twice. */
.page-hero {
  background: var(--surface);
  color: var(--ink-900);
  /* Asymmetric, the way the home hero is: the title starts close under the
     header rather than floating in 68px of empty band, and what space
     there is sits below it where it separates the title from the page.
     Nine pages opened on that gap. */
  padding-top: clamp(1.25rem, 2.2vw, 1.9rem);
  padding-bottom: clamp(1.9rem, 3.4vw, 2.75rem);
  border-bottom: 1px solid var(--line);
}

/* A step lighter than the home headline, and a step smaller. The bold
   display weight is reserved for the home page. */
.page-hero h1 {
  color: var(--forest-800);
  font-weight: 500;
  font-size: clamp(1.95rem, 3.4vw, 3rem);
  letter-spacing: -0.02em;
  /* No measure cap. 22ch computed to 613.658px at 1280, and "Financial
     Planning & Analysis" needs 616px — it was breaking by two and a half
     pixels, in a container offering 1203. A page title is a name, not a
     paragraph: it takes the width it has and wraps only when the screen
     runs out. */
  margin-bottom: 0.6rem;
}

.page-hero p {
  max-width: 58ch;
  color: var(--ink-500);
  font-weight: 400;
}

/* Where the band under the hero is the same colour as the hero, the two are
   one column of text and should be spaced like one. They were not: the
   hero's own bottom padding and the section's top padding stacked to about
   a third of a screen, with a hairline in the middle doing nothing but
   marking the seam. Both are cut and the rule goes.

   Scoped by what follows, because a tinted or dark band underneath is a
   genuine change of surface and keeps its full separation. */
.page-hero:has(+ .section:not(.section-alt):not(.section-dark):not(.section-tint)) {
  padding-bottom: clamp(1.2rem, 2vw, 1.7rem);
  border-bottom-color: transparent;
}

.page-hero + .section:not(.section-alt):not(.section-dark):not(.section-tint) {
  padding-top: clamp(1rem, 1.8vw, 1.5rem);
}

/* About opens on one block rather than three: the statement, the two lines
   of story, and the registry facts beside them. A narrower headline so the
   two columns start on the same line. */
.page-hero-split h1 {
  max-width: 17ch;
}

/* The facts card is taller than the three lines beside it. Centred, the
   leftover height splits above and below the text instead of pooling under
   it as a gap the eye reads as a missing section. */
.page-hero-split .split {
  align-items: center;
}

/* The facts panel's heading is an h2 so the page outline has no missing
   level, but it is still a card heading and takes the card step, not the
   section step an h2 would otherwise get. */
.page-hero-split .card h2 {
  font-size: var(--step-card);
  letter-spacing: -0.02em;
  margin-bottom: 0.4rem;
}

/* Wine, not forest. The page opens on green and closes on the third brand
   colour, so the final ask does not read as one more green band. */
 /* Sits inside a .container, so this is a contained block and takes the
    block language like every other one: a radius and a hard offset edge.
    It used to close on a top double rule, but that convention belongs to
    the full-bleed band closers (.hero, .page-hero) where the rule can run
    edge to edge — dragged around a 28px curve it reads as a cap. */
.cta-band {
  background: var(--wine-600);
  color: #f3dede;
  border-radius: var(--radius-lg);
  box-shadow: 5px 5px 0 var(--wine-800);
  padding: clamp(2rem, 4.5vw, 3rem);
  display: grid;
  grid-template-columns: 1.4fr auto;
  gap: 2rem;
  align-items: center;
}

.cta-band h2 {
  color: #fff;
  margin-bottom: 0.5rem;
}

.cta-band p {
  color: #f0d6d6;
  max-width: 52ch;
  font-weight: 400;
}

/* The accent button is an orange on a red ground — it would disappear.
   White carries the ask instead. */
.cta-band .btn-accent {
  background: var(--surface-raised);
  color: var(--wine-700);
}

.cta-band .btn-accent:hover {
  background: #f3dede;
  color: var(--wine-800);
}

.cta-band .btn-row {
  margin-top: 0;
}

/* Service cards. Each one stacks: code, title, the line that sums it up,
   what it delivers, then how it is billed or who it suits — the same shape
   as the engagement-model cards further down the page, so the two sets read
   as one family rather than two components that happen to share a page. */
.service-row {
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 2.6vw, 2rem);
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: 5px 5px 0 var(--block-edge);
}

.service-row > div:first-child {
  margin-bottom: 1rem;
}

/* The last block sits on a rule at the foot of the card, so every card
   closes the same way however much sits above it. */
.service-row > div:last-child {
  display: flex;
  flex-direction: column;
  flex: 1;
}

.service-row h2 {
  font-size: clamp(1.15rem, 1.9vw, 1.35rem);
  margin-bottom: 0.5rem;
}

.service-row .service-note {
  margin-top: auto;
}


/* No sticky head here. Pinning the name made sense when the card was two
   columns and the name sat beside a long list; the card stacks now, so the
   same rule pinned the name over its own body text and overlapped it. */

.service-row:first-of-type {
  border-top: 1px solid var(--forest-800);
}

.service-row:last-of-type {
  border-bottom: 1px solid var(--forest-800);
}

/* Service marks. Ten glyphs on one 24-grid with one stroke weight and
   square caps, each abstracting what the service produces — so the index
   can be scanned rather than read. Forest by default, orange on hover,
   which is the only place the accent moves. */
.service-mark {
  width: 30px;
  height: 30px;
  color: var(--forest-700);
  margin-bottom: 1rem;
  transition: color var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
}

a.card:hover .service-mark {
  color: var(--accent-ink);
  transform: translateY(-2px);
}

/* On the services page the mark sits beside the code rather than above. */
.service-row-mark {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin: 0 0 0.9rem;
}

.service-row-mark .service-mark {
  width: 34px;
  height: 34px;
  margin-bottom: 0;
  flex: 0 0 34px;
}

/* The cells used to be drawn by a rule-coloured bed showing through a 1px
   gap. Blocks carry their own outline and edge now, so the bed would just
   read as a slab behind them. */

.section-dark .card {
  /* A step up from the band it sits on, or the block has no face to catch
     the light and only the edge would be doing the work. */
  background: var(--forest-700);
  color: var(--on-dark);
  border-color: var(--forest-600);
  box-shadow: 5px 5px 0 var(--block-edge-dark);
}

.section-dark .card-hover:hover,
.section-dark .card-hover:active {
  box-shadow: 1px 1px 0 var(--block-edge-dark);
}

.section-dark .card-hover:focus-visible {
  outline-color: var(--accent-glow);
}

.section-dark .card h3 {
  color: #fff;
}

.section-dark .card p {
  color: var(--on-dark-muted);
}

.section-dark a.card:hover {
  background: var(--forest-700);
}

.section-dark a.card:hover h3 {
  color: var(--accent-glow);
}

.section-dark .service-mark {
  color: var(--accent-glow);
}

.section-dark .list-label,
.section-dark .note-label {
  color: var(--on-dark-muted);
}

.section-dark .service-note {
  border-top-color: var(--rule-dark);
  color: var(--on-dark-muted);
}

.section-dark .note-label {
  color: var(--accent-glow);
}

/* Cells that are themselves links — the services index on the home page. */
a.card {
  display: block;
  color: inherit;
}

a.card:hover {
  color: inherit;
}

/* Small mono heading above a list, without the section rule an .eyebrow
   carries — those would repeat too often down a long schedule. */
.list-label {
  display: block;
  font-family: var(--font-label);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-400);
  margin: 0 0 0.85rem;
}

.list-label + .checklist {
  margin-top: 0;
}

/* The operating rhythm — the site's one diagram. A month drawn as four
   stages in the order they happen.

   It was an SVG of a ruled 1-to-31 scale. Two things were wrong with that.
   The scale carried day numbers, which read as a promise about dates the
   firm has not made; and once the numbers came off, a ruler with nothing
   measured on it is a hairline with four dots on it — the drawing had
   nothing left to look at.

   Rebuilt as markup rather than a drawing. Text in an SVG cannot wrap, so
   that version needed every label to fit a computed width and, below 860px,
   a sideways scroll inside its own container at a fixed 820px. Four blocks
   reflow, stack, and need neither. */
.month {
  margin: 0;
}

/* One object divided, not four objects in a row: the dividing lines are
   the month's own, and only the outer corners are rounded. */
.month-bar {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 6px 6px 0 var(--block-edge);
}

/* The month deepens as it runs. Four steps of the one green, lightest at
   the open and darkest at the close, so the bar reads as a month filling
   up rather than as four unrelated cells. */
.month-stage {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: clamp(1.25rem, 2.2vw, 1.85rem);
  min-height: clamp(12.5rem, 18vw, 15.5rem);
  border-right: 1px solid rgba(255, 255, 255, 0.16);
}

.month-stage:last-child {
  border-right: 0;
}

.month-stage:nth-child(1) { background: var(--forest-600); }
.month-stage:nth-child(2) { background: var(--forest-700); }
.month-stage:nth-child(3) { background: var(--forest-800); }
.month-stage:nth-child(4) { background: var(--forest-900); }

/* One mark per stage, in the accent the service marks take on dark
   grounds, so a mark on green means the same thing wherever it appears.
   Large enough to be what the eye lands on: the stage label and the
   deliverable sit under it rather than beside it, and the block is sized
   by the mark rather than the mark fitted into a block. */
.month-mark {
  display: inline-flex;
  color: var(--accent-glow);
}

.month-mark svg {
  width: clamp(3.5rem, 5vw, 4.5rem);
  height: clamp(3.5rem, 5vw, 4.5rem);
}

/* Full white, and no opacity on it. The muted tone the rest of the dark
   sections use measures 3.5:1 against the lightest of these four greens,
   and white held back to 0.82 measures 4.15:1 — both under AA for type
   this size. Size, weight and tracking separate it from the deliverable
   instead, which costs nothing in contrast. */
.month-when {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #fff;
}

.month-what {
  margin: 0;
  margin-top: auto;
  padding-top: 0.4rem;
  font-size: var(--step-sub);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: #fff;
  text-wrap: balance;
}

.month figcaption {
  margin-top: 1.4rem;
  font-family: var(--font-label);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-500);
}

/* Two across, then one. Four is a kind number: every tier divides it. */
@media (max-width: 860px) {
  .month-bar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* With two columns the right-hand cell of each row ends the row, and the
     two rows need a line between them that the single-row layout does not. */
  .month-stage:nth-child(2n) {
    border-right: 0;
  }

  .month-stage:nth-child(-n + 2) {
    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  }
}

@media (max-width: 520px) {
  .month-bar {
    grid-template-columns: minmax(0, 1fr);
  }

  .month-stage {
    min-height: 0;
    border-right: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  }

  .month-stage:last-child {
    border-bottom: 0;
  }
}


/* The finance stack — the diagram that explains the whole offer. Five
   layers from raw source data up to the decisions it feeds, with the
   layers the firm builds and runs marked on the left edge. */
/* The finance stack. Was a hand-built SVG with hardcoded text coordinates,
   which meant no label could reflow and any copy change risked collisions.
   Rebuilt as real markup: an ordered list read the way the page is read,
   top down, 01 sources feeding through to 05 decisions, with a spine
   connecting each layer to the one it feeds.

   The platform names carry a neutral glyph rather than vendor logos — those
   are other companies' trademarks and are not ours to reproduce. 

/* The spine: each layer reaches down to the one feeding it. 

/* The three layers the firm builds and runs, which is the claim the heading
   above makes — the diagram has to carry it or the heading is unsupported. 

 /* Items size to their content and wrap. A fixed column count spread three
    entries across the whole card and left most of it empty. 

/* Lines draw themselves when their figure first scrolls into view. Set
   once, on entry, then left alone — not tied to scroll position. */
.draw path,
.draw polyline {
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
}

.draw.is-drawn path,
.draw.is-drawn polyline {
  transition: stroke-dashoffset 1.5s cubic-bezier(0.22, 0.61, 0.36, 1);
  stroke-dashoffset: 0;
}

@media (prefers-reduced-motion: reduce) {
  .draw path,
  .draw polyline {
    stroke-dasharray: none;
    stroke-dashoffset: 0;
  }
}

/* Runway chart. Sits on the forest ground so it breaks the run of light
   sections, and so the accent can carry the line that matters. */
.runway {
  margin: 0;
}

.runway-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.runway svg {
  width: 100%;
  height: auto;
  display: block;
}

.runway .grid-line {
  stroke: rgba(255, 255, 255, 0.1);
  stroke-width: 1;
}

.runway .axis-line {
  stroke: rgba(255, 255, 255, 0.3);
  stroke-width: 1;
}

.runway .gained {
  fill: var(--orange-500);
  fill-opacity: 0.16;
}

.runway .line-before {
  fill: none;
  stroke: var(--on-dark-muted);
  stroke-width: 2;
  stroke-dasharray: 5 4;
}

.runway .line-after {
  fill: none;
  stroke: var(--accent-glow);
  stroke-width: 2.5;
}

.runway .dot {
  fill: var(--accent-glow);
}

.runway .dot-hollow {
  fill: var(--forest-800);
  stroke: var(--on-dark-muted);
  stroke-width: 2;
}

.runway .marker {
  stroke: rgba(255, 255, 255, 0.28);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}

.runway .tick-label {
  fill: var(--on-dark-muted);
  font-family: var(--font-label);
  font-size: 13px;
  letter-spacing: 0.08em;
}

.runway .note {
  fill: var(--on-dark);
  font-family: var(--font-label);
  font-size: 13px;
  letter-spacing: 0.1em;
}

.runway .note-accent {
  fill: var(--accent-glow);
  font-family: var(--font-label);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
}

.runway-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.75rem;
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule-dark);
  font-family: var(--font-label);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-dark-muted);
}

.runway-legend span {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}

.runway-legend .key {
  width: 20px;
  height: 0;
  border-top: 2.5px solid var(--accent-glow);
}

.runway-legend .key-before {
  border-top: 2px dashed var(--on-dark-muted);
}

/* The disclaimer is the one line on this chart that must be readable — it
   is what keeps an illustrative graphic from reading as a claimed result.
   Held at --on-dark-muted (5.56:1) rather than a faint white. */
.runway-legend .caveat {
  color: var(--on-dark-muted);
  text-transform: none;
  letter-spacing: 0.04em;
}

@media (max-width: 860px) {
  .runway svg {
    min-width: 760px;
  }

  .runway .tick-label,
  .runway .note,
  .runway .note-accent {
    font-size: 15px;
  }
}


/* Photography slot. Sized and framed so a real image drops straight in;
   until then it states what belongs here rather than showing a stock
   photograph, which would look worse than an honest gap. */
.media {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface-tint);
}

.media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.media-empty {
  display: grid;
  place-content: center;
  gap: 0.4rem;
  text-align: center;
  aspect-ratio: 3 / 2;
  padding: 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: calc(var(--radius) - 1px);
  margin: -1px;
}

.media-empty .what {
  font-family: var(--font-label);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--forest-800);
}

.media-empty .spec {
  font-family: var(--font-label);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  color: var(--ink-400);
}

.media figcaption {
  padding: 0.75rem 0 0;
  font-family: var(--font-label);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-400);
}

/* Qualifying note closing a service entry — "Ideal for", "Outcome". Set
   like a footnote under a statement line. */
.service-note {
  margin-top: 1.6rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-size: 0.92rem;
  color: var(--ink-500);
}

.note-label {
  display: block;
  font-family: var(--font-label);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin-bottom: 0.35rem;
}

.definition-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  margin: 0;
  border-top: 1px solid var(--line);
}

.definition-grid > div {
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--line);
}

/* For a value too long to sit in half the card, such as a list of names. */
.definition-grid > .full {
  grid-column: 1 / -1;
}

.definition-grid dt {
  font-family: var(--font-label);
  font-size: 0.67rem;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-400);
  margin-bottom: 0.3rem;
}

.definition-grid dd {
  margin: 0;
  color: var(--forest-800);
  font-size: 0.98rem;
  font-weight: 500;
}

/* 11. Utilities ---------------------------------------------------------- */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.text-center {
  text-align: center;
}

.mt-0 {
  margin-top: 0;
}

.mt-2 {
  margin-top: 2rem;
}

.mb-0 {
  margin-bottom: 0;
}

.muted {
  color: var(--ink-500);
}

/* 12. Motion & responsive ------------------------------------------------ */
.reveal {
  /* initReveal writes --reveal-i on siblings that share a parent, so a grid
     resolves in sequence instead of every cell landing at once. The index is
     capped in JS so a ten-card grid does not trail on for a second. */
  --reveal-i: 0;
  opacity: 0;
  /* Deliberately `translate`, not `transform`: cards use transform for their
     press, and a reveal rule landing on the same property would cancel it. */
  translate: 0 14px;
  transition:
    opacity var(--dur-4) var(--ease-out),
    translate var(--dur-4) var(--ease-out);
  transition-delay: calc(var(--reveal-i) * 65ms);
}

.reveal.is-visible {
  opacity: 1;
  translate: none;
}

@media (max-width: 980px) {
  /* Holds exactly three cards. A two-column step would always strand one
     beside dead space, so it never takes one — it stays three-up until the
     columns are genuinely too narrow to read, then goes straight to one. */
  .grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.7rem;
  }

  .grid-3 > .card {
    padding: 1.1rem 1rem;
  }

  .grid-3 > .card h3 {
    font-size: 1.02rem;
  }

  .grid-3 > .card p,
  .grid-3 > .card .checklist li {
    font-size: 0.86rem;
  }

  .grid-3 > .card .checklist li {
    padding-left: 1.4rem;
  }

  .footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

}

@media (max-width: 640px) {
  :root {
    --gutter: 1.15rem;
  }

  .grid-2,
  .grid-3,
  .grid-4,
  .definition-grid,
  .footer-grid {
    grid-template-columns: 1fr;
  }


  .btn-row .btn {
    width: 100%;
  }

  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

@media print {
  .site-header,
  .site-footer,
  .cta-band,
  .nav-toggle {
    display: none !important;
  }

  body {
    color: #000;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
    /* Without this the stagger still holds each element back before it
       snaps in, which is exactly the effect the preference asks us to drop. */
    transition-delay: 0ms !important;
    animation-delay: 0ms !important;
  }

  .reveal {
    opacity: 1;
    translate: none;
    transform: none;
  }
}


/* 12b. Interaction ---------------------------------------------------------
   Motion that only exists on input: hovers, presses and focus. Everything
   here runs on the --dur/--ease tokens, and the reduced-motion block above
   flattens the lot. Nothing moves far — the point is feedback, not travel. */

/* The mark leads the card's press: it lifts and takes the accent as the
   block itself sinks, so the two read as one gesture. */
.card-hover:hover .service-mark {
  transform: translateY(-3px);
  color: var(--accent-ink);
}

.section-dark .card-hover:hover .service-mark {
  color: var(--accent-glow);
}

/* The arrow is the only thing that should look impatient. */
.link-arrow::after {
  transition: transform var(--dur-2) var(--ease-out);
}

.link-arrow:hover::after {
  transform: translateX(5px);
}


/* Focus is a first-class state, not a fallback for hover: same accent, same
   curve, and it never depends on colour alone to be visible. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  transition:
    outline-color var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out);
}


/* Labelled value pairs. A category set beside the thing itself reads as a
   record rather than a decorative chip — and where the value is still a
   placeholder, the label states exactly what is wanted. */
.meta-pairs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.1rem 2rem;
  margin: 1.75rem 0 0;
  padding-top: 1.35rem;
  border-top: 1px solid var(--rule-dark);
}

.meta-pair dt {
  font-family: var(--font-label);
  font-size: 0.64rem;
  font-weight: 400;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--on-dark-muted);
}

.meta-pair dd {
  margin: 0.35rem 0 0;
  font-size: 0.95rem;
  line-height: 1.4;
  color: #fff;
}

@media (max-width: 560px) {
  .meta-pairs {
    grid-template-columns: 1fr;
  }
}


/* Engagement-model cards. Flex columns so the billing note sits on a rule at
   the foot of every card, however uneven the lists above it are — one model
   carries five services and another carries one. */
.grid-3 > .card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.grid-3 > .card > * {
  align-self: stretch;
}

.grid-3 > .card .list-label {
  margin-top: 1.4rem;
}

.grid-3 > .card .model-services {
  margin-top: 0;
}

.grid-3 > .card .service-note {
  margin-top: auto;
}

/* The services in a model are the services documented above on this page,
   so they behave as the links they are. */
.model-services a {
  color: var(--forest-800);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
  transition:
    color var(--dur-1) var(--ease-out),
    text-decoration-color var(--dur-1) var(--ease-out);
}

.model-services a:hover {
  color: var(--accent-ink);
  text-decoration-color: var(--accent-ink);
}


/* Below this the three columns stop being readable — the longest service
   name breaks across three lines — so the models stack instead. It goes
   from three to one, never two, which would strand the third card. */
@media (max-width: 700px) {
  .grid-3 {
    grid-template-columns: 1fr;
    gap: clamp(0.9rem, 1.6vw, 1.35rem);
  }

  .grid-3 > .card {
    padding: clamp(1.5rem, 2.4vw, 2rem);
  }

  .grid-3 > .card h3 {
    font-size: 1.15rem;
  }

  .grid-3 > .card p,
  .grid-3 > .card .checklist li {
    font-size: 0.95rem;
  }
}


/* The card you just jumped to. It lifts clear of the page — deeper block
   edge, travelling up and left by the same amount, so the extrusion reads as
   height rather than a bigger shadow — holds there long enough to be seen,
   then settles back. The lift uses the depth language the cards already
   carry rather than bolting a generic glow onto them.

   Holds at full through the first fifth: the previous version began decaying
   at 0% and was most of the way gone before a tap had finished registering.

   Keyframes end on exactly the resting values, so the class can be left in
   place and simply replayed. The reduced-motion block collapses the
   duration, which is right — the jump still works, it just does not move. */
@keyframes land {
  0%,
  20% {
    transform: translate(-4px, -4px);
    border-color: var(--orange-500);
    box-shadow:
      9px 9px 0 var(--block-edge),
      0 0 0 4px rgba(225, 59, 6, 0.3);
  }

  100% {
    transform: translate(0, 0);
    border-color: var(--line-strong);
    box-shadow:
      5px 5px 0 var(--block-edge),
      0 0 0 4px rgba(225, 59, 6, 0);
  }
}

.service-row.is-landed {
  animation: land 1.9s var(--ease-out);
}


/* 13. Touch sizing -----------------------------------------------------------
   Keyed to pointer, not viewport width. A tablet at 834px and a laptop at
   834px want different targets, and only the pointer query knows which is
   which. Everything here is inert on a mouse. */
@media (pointer: coarse) {
  /* Footer link lists were 20px tall — under the 24px WCAG minimum and far
     under comfortable. The row gap comes down as the padding goes up, so the
     footer grows far less than seventeen links at full height would cost. */
  .footer-links {
    gap: 0.15rem;
  }

  .footer-links a {
    display: block;
    padding-block: 0.55rem;
  }

  .footer-email,
  .link-arrow,
  .model-services a,
  .card-link a {
    display: inline-block;
    padding-block: 0.5rem;
  }

  .legal-links a,
  .footer-bottom a {
    display: inline-block;
    padding-block: 0.45rem;
  }

  /* A link that is the whole of its list item is navigation rather than
     prose, so it gets a real target. Links inside a sentence are left inline
     on purpose: making those inline-block stops them wrapping. */
  .checklist li > a:only-child {
    display: inline-block;
    padding-block: 0.35rem;
  }

  /* The phone number and the address on the contact page are the most
     tapped things on the site. They sit inline in a paragraph, so they take
     padding rather than a layout change — each is on its own line already. */
  .card address a,
  .card p a {
    display: inline-block;
    padding-block: 0.35rem;
  }

  .nav-toggle {
    width: 48px;
    height: 48px;
  }
}

/* The mono labels are small by design — uppercase and letterspaced, which
   carries further than the size suggests — but the smallest were landing near
   9.9px, which is too fine to read on a phone held at arm's length. They get
   a floor on narrow screens only; the desktop sizes are untouched. */
@media (max-width: 700px) {
  .rail-label {
    font-size: 0.68rem;
  }

  .list-label,
  .note-label,
  .meta-pair dt,
  .media-empty .spec {
    font-size: 0.72rem;
  }

  .eyebrow {
    font-size: 0.73rem;
  }
}


/* Large screens. The fixed 1160px cap held the page at laptop width no
   matter how much room there was, so a 1600px display got 140px of margin a
   side against a laptop's 60px and the content read as marooned. The
   container is proportional above 1400px instead, so the margin stays about
   the same fraction of the screen it is on a laptop, and stops growing at
   1600px — past that, centring is the right answer rather than more width.

   The measure stays honest throughout: paragraphs carry their own ch-based
   caps, so the container grows around the text rather than stretching it. */
@media (min-width: 1280px) {
  :root {
    /* max() so this can only ever widen the container, never narrow it —
       a plain min() undercut the 1160px base on the smaller laptops. */
    --container: max(1160px, min(94vw, 1920px));
  }

  .hero h1 {
    /* 15ch stopped the headline filling its column long before the container
       stopped growing, which is what left the hero looking empty on the right. */
  }

  .hero p,
  .page-hero p {
    max-width: 62ch;
  }

  .hero h1 {
    /* Floor at the base clamp's own ceiling. Without it the headline shrank
       as the screen grew, because 4vw at 1440 is less than the 4.2rem it had
       already reached at 1280. */
    font-size: clamp(4.2rem, 4.4vw, 6.4rem);
  }

  /* Kept in step with the base rule. This is the one that actually
     applies on a desktop; editing the base alone changed nothing at
     1280, where 74vh of a 900px window was resolving to 666. */
  .hero-inner {
  }

  /* A card two columns wide at this size would run its description past a
     comfortable measure, which the container growing cannot fix on its own. */
  .service-row > div > p,
  .service-row .muted {
    max-width: 62ch;
  }
}


/* 14. Entrances --------------------------------------------------------------
   Motion that runs once, on arrival. Everything here is flattened by the
   reduced-motion block, which zeroes both duration and delay. */

/* The hero is above the fold, so it is not on the scroll reveal — it would
   simply appear. It resolves in reading order instead: label, headline,
   paragraph, actions. Uses `translate` rather than `transform` so it cannot
   collide with anything that animates transform later. */
@keyframes hero-in {
  from {
    opacity: 0;
    translate: 0 16px;
  }
  to {
    opacity: 1;
    translate: 0 0;
  }
}

.hero-inner > * {
  animation: hero-in 620ms var(--ease-out) both;
}

.hero-inner > *:nth-child(1) { animation-delay: 40ms; }
.hero-inner > *:nth-child(2) { animation-delay: 130ms; }
.hero-inner > *:nth-child(3) { animation-delay: 220ms; }
.hero-inner > *:nth-child(4) { animation-delay: 310ms; }

/* The stack builds a layer at a time, bottom up, the same direction the
   diagram is read — 01 sources arriving first and 05 decisions last. It
   sits inside a .reveal, so it waits until the figure is on screen.  Cross-document transitions, so moving between pages is a settle rather
   than a cut. Chrome honours this today; every other browser ignores the
   at-rule entirely and navigates as before, which is why it is worth having
   — it costs nothing where it is not understood. */
@view-transition {
  navigation: auto;
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
}


/* 15. Inner-page entrances ---------------------------------------------------
   Same idea as the hero: things that arrive should resolve rather than
   appear. All of it is flattened by the reduced-motion block. */

/* Every page but home opens on .page-hero, and it was doing nothing. It
   takes the hero's treatment so the three subpages open the way home does. */
.page-hero .container > * {
  animation: hero-in 620ms var(--ease-out) both;
}

.page-hero .container > *:nth-child(1) { animation-delay: 40ms; }
.page-hero .container > *:nth-child(2) { animation-delay: 130ms; }
.page-hero .container > *:nth-child(3) { animation-delay: 220ms; }
.page-hero .container > *:nth-child(4) { animation-delay: 310ms; }

/* Six numbered steps read as a sequence, so they arrive as one. */
.reveal .step,
.reveal > .card,
.reveal .meta-pair,
.reveal tbody tr {
  opacity: 0;
  translate: 0 10px;
}

.reveal.is-visible .step,
.reveal.is-visible > .card,
.reveal.is-visible .meta-pair,
.reveal.is-visible tbody tr {
  opacity: 1;
  translate: 0 0;
  transition:
    opacity var(--dur-3) var(--ease-out),
    translate 420ms var(--ease-out);
  transition-delay: calc(var(--i, 0) * 85ms);
}

/* Table rows come left to right rather than up, which is the direction a
   row is read. */
.reveal tbody tr {
  translate: -10px 0;
}

.reveal .step:nth-child(1),
.reveal > .card:nth-child(1),
.reveal .meta-pair:nth-child(1),
.reveal tbody tr:nth-child(1) { --i: 0; }

.reveal .step:nth-child(2),
.reveal > .card:nth-child(2),
.reveal .meta-pair:nth-child(2),
.reveal tbody tr:nth-child(2) { --i: 1; }

.reveal .step:nth-child(3),
.reveal > .card:nth-child(3),
.reveal .meta-pair:nth-child(3),
.reveal tbody tr:nth-child(3) { --i: 2; }

.reveal .step:nth-child(4),
.reveal .meta-pair:nth-child(4),
.reveal tbody tr:nth-child(4) { --i: 3; }

.reveal .step:nth-child(5),
.reveal tbody tr:nth-child(5) { --i: 4; }

.reveal .step:nth-child(6),
.reveal tbody tr:nth-child(6) { --i: 5; }


/* 16. Contact ----------------------------------------------------------------
   The questions resolve one after another rather than all at once.
   Flattened by the reduced-motion block like everything else. */
.reveal .accordion details {
  opacity: 0;
  translate: 0 8px;
}

.reveal.is-visible .accordion details {
  opacity: 1;
  translate: 0 0;
  transition:
    opacity var(--dur-3) var(--ease-out),
    translate 400ms var(--ease-out);
  transition-delay: calc(var(--i, 0) * 55ms);
}

.accordion details:nth-child(1) { --i: 0; }
.accordion details:nth-child(2) { --i: 1; }
.accordion details:nth-child(3) { --i: 2; }
.accordion details:nth-child(4) { --i: 3; }
.accordion details:nth-child(5) { --i: 4; }
.accordion details:nth-child(6) { --i: 5; }
.accordion details:nth-child(7) { --i: 6; }

/* A validation message that simply appears is easy to miss, and the field
   it belongs to has usually just scrolled under your thumb. It drops in
   from the control above it instead. */
 /* The field itself flinches once when it fails, so the eye is drawn to the
   control and not only to the message under it. */
@keyframes field-reject {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  75% { transform: translateX(3px); }
}


/* Past 2000px the container has stopped growing but the hero had not caught
   up with it — the headline was still capped at 20ch, so it sat in the left
   half with a void beside it. It takes the width it has here, which is what
   makes the composition read as deliberate rather than as content that ran
   out. The paragraph deliberately does not follow: its measure is set by
   what is comfortable to read, not by what space exists. */
@media (min-width: 2000px) {
  .hero h1 {
    font-size: clamp(6.4rem, 5.2vw, 8.4rem);
  }

  /* Grows, but nothing like the home headline. Floored at the base clamp's
     own ceiling, or 2.1vw at 2000px would come out smaller than the 3rem it
     had already reached at 1280. */
  .page-hero h1 {
    font-size: clamp(3rem, 2.1vw, 3.6rem);
  }

  .hero .eyebrow-list {
    font-size: 0.82rem;
  }

  .hero p,
  .page-hero p {
    font-size: 1.32rem;
  }

  .hero-inner {
  }
}

/* 17. Legal pages ------------------------------------------------------------
   Long-form prose, which nothing else on the site is. The measure is held
   near 68 characters and the vertical rhythm is looser than a card's, because
   these pages are read rather than scanned. */

.legal-updated {
  font-family: var(--font-label);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-400);
  margin-bottom: 1.75rem;
}

.legal-body {
  max-width: 68ch;
}

.legal-body h2 {
  font-size: clamp(1.12rem, 1.7vw, 1.3rem);
  margin-top: 2.5rem;
  margin-bottom: 0.75rem;
}

.legal-body h2:first-child {
  margin-top: 0;
}

.legal-body p {
  margin-bottom: 1rem;
  line-height: 1.72;
}

/* The 404's routes onward. Not .checklist: a tick reads as "we deliver
   this", and these are places to go, not things being promised. */
.wayfinder {
  list-style: none;
  display: grid;
  gap: 0.85rem;
  max-width: 68ch;
}

/* 18. When-to-call cards -----------------------------------------------------
   Five numbered moments, each with its own mark. Three across then two, so
   the row that carries the remainder sits under the start of the row above
   rather than stranding a lone card. */

/* One panel, five moments, laid across it as five columns rather than
   flowed down two.

   Two columns was the shape the content fell into, not a shape chosen for
   it: five never divides into two, so the second column always stopped a
   row short and left a hole in the bottom-right of the panel, while the
   labels — none of them longer than five words — trailed off into half a
   container of empty space on each side. Five columns fills the panel it
   is given, finishes level, and says the true thing about these five:
   they are alternatives, any one of which can be the reason a startup
   calls, not a list that runs in an order.

   Flex rather than grid for the same reason the service grid is: when the
   row cannot hold five it breaks to three and two, and justify-content
   centres the short row under the long one instead of stranding it left. */
.moments {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  list-style: none;
  margin: 0;
  --moment-gap: clamp(1.1rem, 2vw, 1.75rem);
  gap: var(--moment-gap);
  padding-block: clamp(1rem, 1.9vw, 1.6rem);
}

.moment {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(0.7rem, 1.1vw, 0.95rem);
  flex: 0 1 calc((100% - 4 * var(--moment-gap)) / 5);
}

/* The mark stands on the card the way every other mark on the site does.
   It used to sit in a 56px filled circle, and those circles were the only
   round, solid, dark objects on a site built out of squared blocks and
   stroked marks: five foreign badges in a row, heavier than the words they
   introduced, which is why the panel read as borrowed from somewhere else.
   Dropping the wells also drops the orange accent strokes they carried, so
   the marks are one forest line throughout, like the service marks. */
.moment-icon {
  display: inline-flex;
  flex: 0 0 auto;
  color: var(--forest-700);
}

.moment-icon svg {
  /* Big enough on a wide screen to be the thing the eye lands on, and held
     at 60px below 800px or so, where a column is narrow enough that a mark
     scaled to match would push its own label off the bottom of the panel. */
  width: clamp(3.75rem, 7.5vw, 6rem);
  height: clamp(3.75rem, 7.5vw, 6rem);
  /* Stroke width is in viewBox units, so it scales with the mark. Left at
     1.7 these would be drawn in a line two and a half times heavier than
     the service marks below rather than the same line larger. */
  stroke-width: 0.95;
}

.moment-label {
  margin: 0;
  font-size: var(--step-card);
  font-weight: 500;
  line-height: 1.35;
  color: var(--forest-800);
  /* Five narrow columns wrap short phrases badly left alone: "Pre-seed,
     seed or Series" over a line holding nothing but "A". */
  text-wrap: balance;
}

/* The two-column splits hold to 940px, not 980.

   A phone in desktop mode reports 980 CSS pixels exactly, and the old
   breakpoint was max-width: 980px — inclusive, so it caught that width by
   a single pixel and stacked every split on the device most likely to hit
   it. On About that meant the facts card dropping below the headline and
   the registrations below the checklist, taking the page from 2443px to
   3222px. 940 is the same line the moments row now breaks on. */
@media (max-width: 940px) {
  /* The four standards hold one row to 940 as well: at 980 they were going
     two-up while the splits beside them stayed two-column, which is the
     one thing still different from the zoomed view. */
  .grid-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .split,
  .hero-grid,
  .service-row,
  .cta-band {
    grid-template-columns: 1fr;
  }
}

/* Three and two, then two, on the same divisors the service grid breaks on.

   The five-across row holds down to 940px rather than 1080px. A phone in
   desktop mode reports about 980 CSS pixels, which landed inside the
   three-across tier and broke the row there while the same phone at 90%
   zoom — about 1089 — kept it. There is room for five at 980: the cells
   come out 171px, enough for the mark and a label over two or three
   lines. */
@media (max-width: 940px) {
  .moment {
    flex-basis: calc((100% - 2 * var(--moment-gap)) / 3);
  }
}

@media (max-width: 760px) {
  .moment {
    flex-basis: calc((100% - var(--moment-gap)) / 2);
  }
}

/* One per row, and at that width a mark above a single short label wastes
   the height it costs — so the row turns back on its side. */
@media (max-width: 520px) {
  .moments {
    justify-content: flex-start;
  }

  .moment {
    flex-basis: 100%;
    flex-direction: row;
    align-items: center;
  }
}

/* 19. Services dropdown in the menu -------------------------------------------
   Services has no page of its own any more, so it is a disclosure rather than
   a link. The button carries the state; the chevron only illustrates it. */

.nav-group-toggle {
  display: flex;
  align-items: center;
  /* The chevron sits against the word, not against the far side of the
     panel. Pushed to the right edge it was a quarter of a screen away from
     the label it belongs to, which made it read as a separate control and
     put it under the thumb's reach on a wide phone. fit-content so the
     button is as wide as its own contents rather than as wide as the row. */
  justify-content: flex-start;
  gap: 0.4rem;
  width: fit-content;
  padding-block: clamp(0.85rem, 1.9vh, 1.15rem);
  /* A button brings its own horizontal padding; zero it or "Services" sits
     a few pixels right of the links above and below it. */
  padding-inline: 0;
  border: 0;
  background: transparent;
  color: var(--on-dark);
  font-family: inherit;
  font-size: clamp(1.02rem, 1.3vw, 1.2rem);
  font-weight: 400;
  text-align: left;
  cursor: pointer;
  transition: color var(--dur-1) var(--ease-out);
}

.nav-group-toggle:hover {
  color: #fff;
}

.nav-group-toggle:focus-visible {
  outline: 2px solid var(--accent-glow);
  outline-offset: 3px;
}

.nav-chevron {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  transition: transform var(--dur-2) var(--ease-out);
}

.nav-group-toggle[aria-expanded="true"] .nav-chevron {
  transform: rotate(180deg);
}

/* No rule down the side. The indent alone says these belong to Services. */
.nav-sub {
  list-style: none;
  display: grid;
  padding-left: 1.1rem;
  max-height: 0;
  overflow: hidden;
  /* Hidden as well as collapsed, so the ten links inside a closed group are
     not reachable by Tab. */
  visibility: hidden;
  transition:
    max-height var(--dur-3) var(--ease-out),
    visibility var(--dur-3);
}

.nav-group.is-open .nav-sub {
  max-height: 34rem;
  visibility: visible;
}

.nav-sub a {
  display: block;
  padding-block: 0.55rem;
  font-size: 0.94rem;
  color: var(--on-dark-muted);
}

.nav-sub a:hover {
  color: #fff;
}

.nav-sub a[aria-current="page"] {
  color: var(--accent-glow);
}

/* 20. Service article --------------------------------------------------------
   One page per service: a lede, what it delivers, and where it sits in the
   finance function. Long-form, so the measure is held like the legal pages. */

.service-article {
  max-width: 68ch;
}

.service-article h2 {
  font-size: clamp(1.12rem, 1.7vw, 1.3rem);
  margin-top: 2.25rem;
  margin-bottom: 0.9rem;
}

.service-article .lede {
  margin-bottom: 0.5rem;
}

.service-article .service-note {
  margin-top: 1.5rem;
}

.related {
  list-style: none;
  display: grid;
  gap: 1.1rem;
  max-width: 68ch;
}

.related li {
  display: grid;
  gap: 0.2rem;
}

.related .muted {
  font-size: 0.92rem;
}

/* 21. Services index grid ----------------------------------------------------
   Five cards in a centred flex row; the layout rules are below, with the
   breakpoints. A grid declaration used to open this section — five rigid
   columns, from when there were ten services — but the flex block further
   down overrode every line of it, so it was describing a layout the page
   had not used for some time. */

/* Roomier than the cards were when five had to fit across one row. Three
   across leaves the padding a card that size can afford. */
.service-grid .card {
  padding: clamp(1.4rem, 2.2vw, 1.9rem);
}

.service-grid .service-mark {
  width: 52px;
  height: 52px;
  /* Stroke width is in viewBox units, so it scales with the mark. Held back
     from the 1.6 in the markup so a bigger mark is the same line larger
     rather than a heavier one. */
  stroke-width: 1.1;
  margin-bottom: 0.85rem;
}

.service-grid h3 {
  font-size: clamp(0.92rem, 1.05vw, 1.02rem);
  line-height: 1.3;
  margin-bottom: 0.4rem;
  text-wrap: balance;
}

.service-grid p {
  font-size: 0.85rem;
  line-height: 1.45;
  margin: 0;
}

/* Ten cards divide evenly by 5, by 2 and by 1, and by nothing else. Any
   three- or four-column tier leaves an orphan row, which is what the gap
   under the grid was: at four across it ran 4+4+2. So this grid only ever
   has 5, 2 or 1 columns, and the breakpoints are chosen by where five stop
   fitting rather than by the usual ladder. */
/* Five, and before that seven: both prime, so no column count but the
   count itself or one ends on a full row. Rather than chase a divisor
   every time the list changes, the row that does not fill is centred. A
   short last row reading as centred is a layout; the same row pushed left
   with a hole beside it is a mistake.

   Grid rather than a wrapping flex row, for one reason: a flex line only
   stretches its own items, so the three cards above and the two below were
   sized by different content and came out 189px and 169px. grid-auto-rows:
   1fr makes every row as tall as the tallest, whichever row the longest
   description happens to land in.

   The centring a wrapping flex row gave for free has to be built here, so
   every tier uses an even column count with each card spanning two, and
   the card that starts the short row is pushed one column right. Three
   lines per tier, and nothing depends on there being exactly five. */
.service-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  --card-gap: clamp(1rem, 1.9vw, 1.6rem);
  gap: var(--card-gap);
  /* Narrower than the container, centred. At full width the cards ran from
     one edge to the other and the set read as a band rather than as a row
     of things. */
  width: 94%;
  margin-inline: auto;
}

.service-grid > .card {
  grid-column: span 2;
}

.service-grid > .card:nth-child(4) {
  grid-column: 2 / span 2;
}

@media (max-width: 760px) {
  .service-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    width: 100%;
  }

  .service-grid > .card:nth-child(4) {
    grid-column: span 2;
  }

  .service-grid > .card:nth-child(5) {
    grid-column: 2 / span 2;
  }
}

@media (max-width: 460px) {
  .service-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .service-grid > .card:nth-child(5) {
    grid-column: span 2;
  }
}


/* 22. Engagement models ------------------------------------------------------
   Three options, compared. The same four facts about each in the same order,
   so the reader can run an eye down a column instead of reading three
   paragraphs to find the difference. */

.models {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.75rem, 1.4vw, 1.1rem);
}

.model {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: clamp(1.25rem, 2vw, 1.6rem);
  background: var(--surface-raised);
  border-radius: var(--radius);
}

/* A comparison only works if the rows line up. Without this the one-line
   description in one card lifts its billing and its rule a line above the
   next card's, and the eye has to hunt across instead of scanning down.
   Subgrid makes each card share the parent's rows; where it is unsupported
   the cards simply keep the flex stacking above. */
@supports (grid-template-rows: subgrid) {
  .models {
    grid-template-rows: auto auto auto auto 1fr;
  }

  .model {
    display: grid;
    grid-row: span 5;
    grid-template-rows: subgrid;
    align-content: start;
  }
}

.model h3 {
  margin: 0;
  font-size: clamp(1rem, 1.2vw, 1.1rem);
}

.model-line {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--ink-500);
}

.model-billing {
  margin: 0.15rem 0 0.35rem;
  font-size: 0.88rem;
  color: var(--forest-800);
}

/* The list is the payload: which services sit in this model. No ticks, since
   these are links to choose from rather than promises being made. */
.model-services {
  list-style: none;
  display: grid;
  gap: 0.35rem;
  margin: 0;
  padding-top: 0.6rem;
  border-top: 1px solid var(--line);
}

.model-services a {
  font-size: 0.9rem;
}

@media (max-width: 860px) {
  .models {
    grid-template-columns: 1fr;
  }
}

/* 23. First ninety days ------------------------------------------------------
   Three phases joined by a rule, so the order is read at a glance rather
   than inferred from three paragraphs. The rule runs behind the marks and
   stops at the first and last, so it reads as a span with ends rather than
   a line that carries on off the card. */

.ninety {
  margin: 0;
  padding: clamp(1.4rem, 2.4vw, 2rem);
  background: var(--surface-raised);
  border-radius: var(--radius);
}

.ninety-label {
  display: block;
  font-family: var(--font-label);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-400);
  margin-bottom: 1.5rem;
}

.ninety-track {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.8rem, 1.6vw, 1.4rem);
  margin: 0;
  padding: 0;
}

.phase {
  position: relative;
  display: grid;
  gap: 0.3rem;
  justify-items: start;
}

/* The connector. Drawn from each mark to the next rather than as one line
   under everything, so the last phase has no tail running off it. */
.phase:not(:last-child)::before {
  content: "";
  position: absolute;
  top: 22px;
  left: 52px;
  right: calc(-1 * clamp(0.8rem, 1.6vw, 1.4rem));
  height: 1px;
  background: var(--line-strong);
}

.phase-mark {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-pill);
  background: var(--forest-800);
  color: #fff;
  margin-bottom: 0.65rem;
}

.phase-mark svg {
  width: 22px;
  height: 22px;
}

.phase-mark .accent {
  stroke: var(--accent-glow);
}

.phase-n {
  font-family: var(--font-label);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--ink-400);
}

.ninety h3 {
  margin: 0;
  font-size: clamp(0.98rem, 1.15vw, 1.08rem);
}

.ninety p {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.45;
  color: var(--ink-500);
}

/* Below this the three columns are too narrow for a phase name, so the track
   turns vertical and the connector runs down the side of the marks. */
@media (max-width: 720px) {
  .ninety-track {
    grid-template-columns: 1fr;
    gap: 1.25rem;
  }

  .phase {
    grid-template-columns: 44px 1fr;
    column-gap: 0.9rem;
    align-items: start;
  }

  .phase-mark {
    grid-row: span 3;
    margin-bottom: 0;
  }

  .phase:not(:last-child)::before {
    top: 48px;
    left: 21px;
    right: auto;
    width: 1px;
    height: calc(100% - 48px + 1.25rem);
  }
}

/* Service ribbon ---------------------------------------------------------
   A band of the five service names travelling slowly above the footer, taken
   from the reference template's "Works ✳ Works" strip. Horizontal rather
   than diagonal: a tilted band fights the block language the rest of the
   site is built on.

   The same flat forest as the hero directly above it and as the open nav,
   so the green runs unbroken from the headline down to the first light band
   rather than stopping at a seam the strip would otherwise draw across the
   page. Set in title case, the way the names are written everywhere else on
   the site, rather than in the eyebrow's caps: these are the service names
   themselves, not a label describing them. */
.ribbon {
  overflow: hidden;
  background: var(--forest-900);
  /* Overlap the hero by one pixel, and give that pixel back as padding so
     nothing moves. The hero ends on a fractional boundary (405.91px at
     420px wide, because the page is set at 90% and everything below is
     rem-derived). Two abutting blocks that round to different device
     pixels leave a hairline between them, and the body behind is light, so
     during a fast scroll it flashes white under the hero. Both blocks are
     forest-900, so an overlap costs nothing and the gap cannot open. */
  margin-top: -1px;
  padding-block: calc(1rem + 1px) 1rem;
}

/* max-content so the track is as wide as all four copies laid end to end;
   the parent clips it, so none of this reaches the document's scroll width. */
.ribbon-track {
  display: flex;
  width: max-content;
  animation: ribbon-travel 29s linear infinite;
}

/* One copy's width, which is a quarter of four. Travelling further than one
   copy would jump; travelling less would leave a seam. Long enough to read a
   name at a glance, slow enough not to pull the eye off the page: close to
   the ten-name strip's pace, over a shorter cycle. Paused while hovered, so
   a name can be read in full. */
@keyframes ribbon-travel {
  from { transform: translateX(0); }
  to { transform: translateX(-25%); }
}

.ribbon:hover .ribbon-track {
  animation-play-state: paused;
}

.ribbon-row {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-label);
  font-size: 0.95rem;
  font-weight: 500;
  /* 0.14em was tracking tuned for capitals. Title case does not need the
     air and reads loose with it, so it drops to a hair over none. */
  letter-spacing: 0.01em;
  color: #fff;
  white-space: nowrap;
}

/* The mark is the separator now, and it carries meaning the dot did not: it
   is the same mark the service's card shows in the grid below, so the strip
   teaches the pairing while it travels. Held tighter to its own name than to
   the name before it, so each pair reads as one unit. */
.ribbon-row li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* The space between names hangs off each item rather than coming from a
     gap on the row, because a row's gap stops at its own last child: the
     final name of one copy would butt straight up against the first name of
     the next, and the seam would be the one place in the strip where two
     services touch. Owned by the item, the spacing crosses the copy
     boundary like any other, and the four copies still measure exactly four
     times one, which is what keeps the quarter-width travel seamless. */
  margin-right: 2.4rem;
}

.ribbon-mark {
  width: 1.2rem;
  height: 1.2rem;
  flex: none;
  /* A step back from the white beside it, so the mark supports the word
     rather than competing with it. */
  color: var(--on-dark);
}

/* The global reduced-motion block squeezes every animation to 0.001ms, which
   for an infinite loop means a strip frozen mid-travel. Naming no animation
   at all leaves it parked at the start instead. */
@media (prefers-reduced-motion: reduce) {
  .ribbon-track {
    animation: none;
  }
}

/* The lead ---------------------------------------------------------------
   One person, so this is a portrait beside a statement rather than a grid
   of cards. The grid it replaced was two columns for two people; with one
   it left the second column empty — a 332px hole at 1280 and 507px at
   1920 — and capping it only made a card floating in a half-container.

   The portrait column is fixed rather than fractional: a 4:5 frame given a
   share of the container grows with the screen, reaching 487x609 at 1920,
   at which point it is a poster, not a portrait. */
.lead-figure {
  display: grid;
  grid-template-columns: clamp(16rem, 24vw, 22rem) minmax(0, 1fr);
  gap: clamp(1.75rem, 4vw, 3.5rem);
  align-items: center;
}

.lead-body h3 {
  margin-bottom: 0.3rem;
  font-size: var(--step-sub);
}

/* The engagement promise, not a caption: it carries the section, so it
   takes the lede's size and its own measure. */
.lead-body .lede {
  margin-top: 1rem;
  max-width: 46ch;
}

.lead-body .btn-row {
  margin-top: 1.6rem;
}

.person-avatar {
  margin: 0;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
  overflow: hidden;
}

/* Portrait, not square and not landscape: the frame is taller than it is
   wide, so the crop is head and shoulders. Shoot or crop to 4:5 — 1000 by
   1250 covers every width the slot reaches. */
.person-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* A monogram until the photograph arrives. An empty frame reads as a
   broken image; initials read as a choice. Sized off the frame rather than
   fixed, so it fills whatever the portrait will fill. */
.avatar-initials {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  background: var(--forest-800);
  color: var(--accent-glow);
  font-family: var(--font-label);
  font-size: clamp(2.4rem, 4.5vw, 3.6rem);
  font-weight: 700;
  letter-spacing: 0.1em;
}

/* Stacked, and the portrait stops short of the full width: a 4:5 frame run
   edge to edge on a phone is most of a screen before a word is read. */
@media (max-width: 760px) {
  .lead-figure {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.25rem, 4vw, 1.75rem);
  }

  .person-avatar {
    max-width: 17rem;
  }
}

