/* Navis Advisory. Zero JS. Self-hosted fonts only. No em dashes anywhere on this site. */

/* ---------- Fonts (self-hosted, latin subset) ---------- */
/* Relative url(): every site output carries its own assets/fonts/ copy (build.js fans the
   one committed set out to each), so this resolves the same from /styles.css and from an
   inline <style> at a site root. */
@font-face {
  font-family: "Navis Serif";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("assets/fonts/navis-serif-700.woff2") format("woff2");
}
@font-face {
  font-family: "Navis Grotesk";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("assets/fonts/navis-grotesk-400.woff2") format("woff2");
}
@font-face {
  font-family: "Navis Grotesk";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("assets/fonts/navis-grotesk-500.woff2") format("woff2");
}


/* ---------- Tokens ---------- */
/* THE design tokens. One file, included by navisadvisory.com's styles.css and inlined into
   the gdd/ and labs/ pages. This replaces tools/check-tokens.js, which existed only to catch
   drift between three hand-synced copies: there is nothing left to drift.

   A few tokens are read by the main site only (--card, --fig-bg, --header). They cost the
   satellite pages nothing: an unreferenced custom property has no rendering effect. */
:root {
  --ink: #0E1B2A;
  --paper: #FAFAF7;
  --slate: #41546B;
  --bronze: #A8834B;
  --hairline: rgba(14, 27, 42, 0.12);
  --paper-muted: #C9D2DD;      /* paper-ish, for text on ink */
  --card: #FFFFFF;             /* raised surfaces: impact cards, quadrant tiles */
  --header: #FAFAF7;           /* the sticky bar: paper in light, a lifted surface on ink */
  --fig-bg: rgba(14, 27, 42, 0.06);
  --serif: "Navis Serif", Georgia, "Times New Roman", serif;
  --sans: "Navis Grotesk", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Monaco, monospace;
  --measure: 1040px;
  /* Type scale (McKinsey-inspired system: tight display, light body) */
  --display-leading: 1.08;
  --fs-h2: 1.7rem;
  --fs-h3: 1.22rem;
  --fs-body: 1.06rem;
  --fs-small: 0.9rem;
  --measure-text: 62ch;
  --stat-fig: clamp(2.6rem, 1.6rem + 4vw, 4.4rem);

  /* Uppercase labels. Regular weight + near-normal tracking: wide-tracked medium caps
     read as generic template, density is what makes them look editorial. */
  --caps-weight: 400;
  --caps-track: 0.05em;          /* micro-caps: eyebrows, kickers, tags, nav */
  --caps-track-display: 0.08em;  /* larger serif caps: wordmark, 404 code */
  --wordmark-track: 0.20em;      /* the logotype only: caps serif set small needs its own, wider fit */
}


/* ---------- Reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  scroll-padding-top: 5rem;   /* clears the sticky header on anchor jumps */
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 700;
  color: var(--ink);
  margin: 0;
  line-height: var(--display-leading);
  letter-spacing: 0;
}
p { margin: 0; }
a { color: inherit; }

.container {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 2.5rem);
}

/* Section rhythm */
section { scroll-margin-top: 5rem; }
/* Anchor jumps: html's scroll-padding-top (5rem) already clears the sticky header, so a
   padded section must NOT add another 5rem on top -- that plus the section's own top padding
   left the headline sitting mid-viewport. Instead cancel most of the top padding so the
   headline always lands ~6rem from the viewport top, just under the header. */
section.section-pad { scroll-margin-top: calc(1rem - clamp(3.25rem, 8vw, 7rem)); }
.section-pad { padding-block: clamp(3.25rem, 8vw, 7rem); }

.eyebrow {
  font-family: var(--sans);
  font-weight: var(--caps-weight);
  font-size: 0.75rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--slate);
  margin: 0 0 1.1rem;
}
.rule {
  width: 56px;
  height: 2px;
  background: var(--bronze);
  border: 0;
  margin: 0 0 1.6rem;
}

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--header);
  border-bottom: 1px solid var(--hairline);
}
.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.15rem;
}
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 1.02rem;
  letter-spacing: var(--wordmark-track);
  word-spacing: 0.10em;
  margin-right: calc(var(--wordmark-track) * -1);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}
.brandmark { display: block; flex: none; }
/* align-items is load-bearing: the nav row is otherwise as tall as its tallest child, and
   stretched links render their text at the TOP of that box. Once the 30px theme circle joined
   the row it dragged every link 5px above the wordmark. Centre them instead. */
.site-nav {
  display: flex;
  align-items: center;
  gap: 1.9rem;
}
.site-nav a {
  font-size: 0.82rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--slate);
  text-decoration: none;
  transition: color 0.15s ease;
}
.site-nav a:hover { color: var(--ink); }

/* ---------- Hero ---------- */
.hero { padding-block: clamp(3.5rem, 10vw, 8rem); }
.hero h1 {
  font-size: clamp(2.2rem, 1.35rem + 3.4vw, 3.4rem);
  max-width: 20ch;
}
.hero-accent { color: var(--bronze); }
.hero .sub {
  margin-top: 1.6rem;
  max-width: 58ch;
  font-size: clamp(1.06rem, 1rem + 0.4vw, 1.22rem);
  line-height: 1.6;
  color: var(--slate);
}
.hero .sub strong { color: var(--ink); font-weight: 500; }

/* ---------- CTA ---------- */
.cta-row {
  margin-top: 2.4rem;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
}
.btn {
  display: inline-block;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-weight: 500;
  font-size: 0.98rem;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
  padding: 0.85rem 1.6rem;
  border: 1px solid var(--ink);
  border-radius: 2px;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn:hover { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn .arrow { color: var(--bronze); }
.btn:hover .arrow { color: var(--bronze); }
.email-inline {
  font-size: 1rem;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--bronze);
  padding-bottom: 1px;
}
.email-inline:hover { color: var(--bronze); }

/* The email field and Submit stay paired on one line (that is what nowrap bought), but
   the Turnstile widget is a fixed ~300px box: field (min 260) + widget (300) + button
   cannot share a line below ~760px, and nowrap turned that into real horizontal page
   scroll rather than a wrap. So: allow wrapping, and below the breakpoint give the
   widget its own row. Verified at 360/480/768/1440 -- no page overflow at any width. */
.contact-form { flex-wrap: wrap; }
.contact-form .cf-turnstile { flex: 0 0 auto; line-height: 0; }

/* Submit feedback. The button is the only thing that can tell a visitor their click
   registered, so it has to change the moment it is pressed (assets/form.js). */
.btn[disabled] { opacity: 0.75; cursor: default; }
.btn .spinner {
  display: inline-block;
  width: 0.8em;
  height: 0.8em;
  margin-right: 0.55em;
  vertical-align: -0.08em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: navis-spin 0.6s linear infinite;
}
@keyframes navis-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  /* Still show the ring, just do not spin it -- the state change is the point. */
  .btn .spinner { animation: none; border-right-color: currentColor; opacity: 0.5; }
}
.field {
  font-family: var(--sans);
  font-size: 0.98rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  background: var(--paper);
  color: var(--ink);
  min-width: 0;
  flex: 1 1 260px;
}
.field::placeholder { color: var(--slate); opacity: 0.7; }
.field:focus { outline: none; border-color: var(--bronze); }
/* Honeypot: invisible to sighted users and screen readers, catches basic bots. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Solutions ---------- */
.solutions { border-top: 1px solid var(--hairline); }
.solutions .grid {
  margin-top: 2.6rem;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 2.75rem);
}
.svc { border-top: 2px solid var(--bronze); padding-top: 1.4rem; }
.svc .kicker {
  font-weight: var(--caps-weight);
  font-size: 0.78rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--slate);
  margin-bottom: 0.9rem;
}
.svc h3 { font-size: 1.24rem; line-height: 1.25; }
.svc p { margin-top: 0.85rem; color: var(--slate); font-size: 1rem; line-height: 1.6; }

/* ---------- Client impact (scroll-snap carousel, zero JS) ---------- */
.track { border-top: 1px solid var(--hairline); }
.track .track-intro {
  margin-top: 0.9rem;
  max-width: 60ch;
  color: var(--slate);
  font-size: 1rem;
}
.impact-carousel {
  margin-top: 2.2rem;
  max-width: 100%;
}
.impact-track {
  list-style: none;
  margin: 0;
  /* small side padding so card focus rings + peek aren't clipped */
  padding: 0.25rem 2px 1.25rem;
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 2px;
  scrollbar-width: thin;
  scrollbar-color: var(--bronze) var(--hairline);
}
.impact-track::-webkit-scrollbar { height: 6px; }
.impact-track::-webkit-scrollbar-thumb { background: var(--bronze); border-radius: 3px; }
.impact-track::-webkit-scrollbar-track { background: var(--hairline); }
.impact-card {
  flex: 0 0 300px;
  scroll-snap-align: start;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-top: 2px solid var(--bronze);
  border-radius: 2px;
  padding: 1.4rem 1.4rem 1.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.impact-card .card-tag {
  font-weight: var(--caps-weight);
  font-size: 0.7rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--slate);
}
.impact-card .card-body {
  color: var(--ink);
  font-size: 1.02rem;
  line-height: 1.5;
}
.track .closing {
  margin-top: 2rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--hairline);
  max-width: 68ch;
  color: var(--slate);
  font-size: 0.98rem;
}
@media (max-width: 480px) {
  .impact-card { flex-basis: 82vw; }
}

/* ---------- How it works (client journey steps) ---------- */
.method { border-top: 1px solid var(--hairline); }
.steps {
  list-style: none;
  margin: 2.6rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.step { border-top: 1px solid var(--hairline); padding-top: 1.15rem; }
.step-num {
  display: block;
  font-family: var(--mono);
  font-size: 0.88rem;
  letter-spacing: 0.1em;
  color: var(--bronze);
}
.step h3 { font-size: 1.18rem; margin-top: 0.6rem; }
.step p { margin-top: 0.65rem; color: var(--slate); font-size: 0.98rem; line-height: 1.6; }
.method-note {
  margin-top: 2.4rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline);
  color: var(--slate);
  font-size: 0.95rem;
  max-width: 68ch;
}
@media (max-width: 900px) {
  .steps { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .steps { grid-template-columns: 1fr; gap: 1.6rem; }
}

/* ---------- About ---------- */
.about { border-top: 1px solid var(--hairline); }
.about .cols {
  margin-top: 2.4rem;
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}
.about img {
  width: 220px;
  height: 220px;
  object-fit: cover;
  filter: grayscale(100%);
  border-radius: 2px;
  display: block;
}
.about .bio h3 { font-size: 1.5rem; margin-bottom: 1.1rem; }
.about .bio p { color: var(--slate); margin-bottom: 1rem; max-width: 62ch; }
.about .bio p.frontier { color: var(--ink); }
.about .edge-note {
  margin-top: 2.4rem;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1.6;
  max-width: 62ch;
}
.about .edge-cred {
  margin-top: 2.6rem;
  color: var(--slate);
  font-size: 0.95rem;
  line-height: 1.6;
  max-width: 68ch;   /* one body measure across sections (matches method/steps copy) */
}
.about .edge-founder { margin-top: 2.6rem; align-items: center; }
.about .edge-founder .edge-cred { margin-top: 0; }
.about .edge-linkedin { margin-top: 1.1rem; }
.about .edge-linkedin a { display: inline-flex; border-bottom: none; }
.about .edge-linkedin .icon {
  width: 22px;
  height: 22px;
  fill: var(--ink);
  transition: fill 0.15s ease;
}
.about .edge-linkedin a:hover .icon { fill: var(--slate); }

/* ---------- Why Navis: 2x2 quadrant (A/B winner; variant C checkmark matrix
   retired 2026-07-19, recoverable in git) ---------- */
.quad {
  margin-top: 1.2rem;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: 1fr auto;
  gap: 0.8rem 0.9rem;
  max-width: 860px;
}
.quad-axis {
  font-weight: var(--caps-weight);
  font-size: 0.72rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--slate);
}
.quad-axis .quad-arrow { color: var(--bronze); }
.quad-axis-y {
  grid-row: 1;
  align-self: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
}
.quad-axis-x { grid-column: 2; grid-row: 2; justify-self: center; }
.quad-grid {
  grid-column: 2;
  grid-row: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
  border-radius: 2px;
}
.quad-tile { background: var(--card); padding: 1.35rem 1.4rem 1.55rem; }
.quad-tile .kicker {
  font-weight: var(--caps-weight);
  font-size: 0.78rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--slate);
}
.quad-tile p:last-child { margin-top: 0.6rem; color: var(--slate); font-size: 0.95rem; line-height: 1.55; }
.quad-navis { background: var(--ink); box-shadow: inset 0 2px 0 var(--bronze); }
.quad-navis .kicker { color: var(--bronze); }
.quad-navis p:last-child { color: var(--paper); }
/* Mobile pass v2 (2026-07-17, persona-test finding + Ben's revert): the 2x2 keeps its quadrant
   shape at every width (a 1-col stack read as confusing), and every tile keeps its one-liner
   (label-only competitor tiles made the vendor tile the only one with an argument). Axis labels
   keep the desktop treatment (rotated y at the left, x centered below) per Ben's call. */
@media (max-width: 640px) {
  .quad { gap: 0.55rem 0.6rem; max-width: none; }
  .quad-tile { padding: 0.85rem 0.85rem 1rem; }
  .quad-tile .kicker { font-size: 0.66rem; letter-spacing: var(--caps-track); }
  .quad-tile p:last-child { font-size: 0.82rem; line-height: 1.45; margin-top: 0.45rem; }
  .quad-axis { font-size: 0.6rem; letter-spacing: var(--caps-track); }
}

/* The tracked wordmark is wide by design; at phone widths it must not crowd the nav. */
@media (max-width: 380px) {
  .wordmark { font-size: 0.95rem; letter-spacing: 0.16em; }
}

/* ---------- Stat callouts (numbers as headlines) ---------- */
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 2rem 3rem;
  margin: 2.2rem 0 2.8rem;
}
.stat-fig {
  font-family: var(--serif);
  font-weight: 700;
  font-size: var(--stat-fig);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--bronze);
}
.stat-cap {
  font-size: var(--fs-small);
  color: var(--slate);
  max-width: 26ch;
  margin-top: 0.5rem;
}
/* On ink bands: gold figures (combine with .band / .contact-band) */
.stat-band .stat-fig { color: #C9A25C; }
.stat-band .stat-cap { color: var(--paper-muted); }


/* ---------- Contact / footer band (ink) ---------- */
.band {
  background: var(--ink);
  color: var(--paper);
}
.band h2 { color: var(--paper); }
.band .rule { background: var(--bronze); }
.contact .lead {
  margin-top: 1.4rem;
  max-width: 52ch;
  color: var(--paper-muted);
  font-size: clamp(1.05rem, 1rem + 0.3vw, 1.18rem);
}
.contact .cta-row { margin-top: 2.2rem; }
.band .btn {
  background: var(--paper);
  color: var(--ink);
  border-color: var(--paper);
}
.band .btn:hover { background: transparent; color: var(--paper); border-color: var(--paper); }
.band .email-inline { color: var(--paper); border-bottom-color: var(--bronze); }
.band .email-inline:hover { color: var(--bronze); }
.band .field {
  background: rgba(250, 250, 247, 0.06);
  border-color: rgba(250, 250, 247, 0.25);
  color: var(--paper);
}
.band .field::placeholder { color: var(--paper-muted); }
.band .field:focus { border-color: var(--bronze); }
.contact .coords {
  margin-top: 2.6rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(250, 250, 247, 0.18);
  color: var(--paper-muted);
  font-size: 0.95rem;
}
.site-footer {
  padding-block: 1.6rem 2.4rem;
  color: var(--paper-muted);
  font-size: 0.85rem;
  letter-spacing: 0.02em;
}
.site-footer a {
  color: var(--paper-muted);
  text-decoration: none;
  border-bottom: 1px solid var(--bronze);
}
.site-footer a:hover { color: var(--paper); }
.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.footer-legal { margin: 0; }
.social { display: flex; align-items: center; gap: 0.9rem; }
.social a { border-bottom: none; display: inline-flex; }
.social .social-off { display: inline-flex; opacity: 0.35; }
.social .social-off .icon { fill: var(--paper-muted); }
.social .icon {
  width: 20px;
  height: 20px;
  fill: var(--paper-muted);
  transition: fill 0.15s ease;
}
.social a:hover .icon { fill: var(--paper); }

/* ---------- Legal page ---------- */
.legal-page { padding-block: clamp(2.5rem, 6vw, 5rem); }
.legal-page h1 { font-size: clamp(1.8rem, 1.3rem + 2vw, 2.6rem); }
.legal-page h2 { font-size: 1.3rem; margin-top: 2.6rem; }
.legal-page p { margin-top: 1rem; color: var(--slate); max-width: 68ch; }
.legal-page .updated { font-size: 0.85rem; color: var(--slate); margin-top: 0.8rem; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .solutions .grid { grid-template-columns: 1fr; gap: 2rem; }
}
@media (max-width: 720px) {
  .about .cols { grid-template-columns: 1fr; }
  .about img { width: 180px; height: 180px; }
}
/* Below 640px (portrait phones only) the in-page section links collapse — they
   read as an ambiguous strip under the wordmark, and this is a one-page site so
   every target is reachable by scrolling. Only the Contact CTA survives, as a
   compact bordered button. Header stays a single row (wordmark left, button right
   via the container's space-between). Zero-JS, no hamburger. Untouched above
   640px: tablets, laptops, and desktops keep the full horizontal nav. */
@media (max-width: 640px) {
  .site-nav a:not(.nav-cta) { display: none; }
  .site-nav .nav-cta {
    border: 1px solid var(--ink);
    border-radius: 2px;
    padding: 0.5rem 1.05rem;
    color: var(--ink);
    transition: background 0.15s ease, color 0.15s ease;
  }
  .site-nav .nav-cta:hover { background: var(--ink); color: var(--paper); }
}

/* ---------- 404 ---------- */
.notfound { min-height: 70vh; display: flex; align-items: center; }
.notfound .code {
  font-family: var(--serif); font-weight: 700; color: var(--bronze);
  font-size: 0.9rem; letter-spacing: var(--caps-track-display); text-transform: uppercase; margin-bottom: 1rem;
}
.notfound h1 { font-size: clamp(2rem, 1.4rem + 2.4vw, 3rem); max-width: 18ch; }
.notfound p { margin-top: 1.2rem; color: var(--slate); max-width: 46ch; }
.notfound .cta-row { margin-top: 2rem; }

/* Form-confirmation variant of the 404 layout: a real sentence as the headline needs
   more measure than "Not found", and the trailing note wants the hairline rule that
   .method-note carries on the homepage. */
.notfound.confirm h1 { max-width: 30ch; }
.notfound.confirm p { max-width: 54ch; }
.notfound.confirm .method-note { margin-top: 2rem; }
/* Keeps an address off a line break, where it reads as two broken words. */
.nowrap { white-space: nowrap; }

/* ---------- A11y / motion ---------- */
:focus-visible { outline: 2px solid var(--bronze); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}

/* ---------- Figures, case pages (2026-07-14 pass; stats strip retired 2026-07-19) ---------- */

.fig {
  font-family: var(--mono);
  font-size: 0.94em;
  letter-spacing: 0;
  background: var(--fig-bg);
  border-radius: 2px;
  padding: 0.05em 0.35em;
}

.impact-card .card-link {
  display: flex;
  flex-direction: column;
  gap: inherit;
  height: 100%;
  color: inherit;
  text-decoration: none;
}
.impact-card .card-quote {
  font-style: italic;
  color: var(--slate);
  font-size: 0.88rem;
  line-height: 1.5;
}
.impact-card .card-quote .card-quote-source {
  display: block;
  margin-top: 0.4rem;
  font-style: normal;
  font-size: 0.68rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
}
.impact-card .card-more {
  margin-top: auto;
  padding-top: 0.9rem;
  font-size: 0.78rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--bronze);
}
.impact-card:hover { border-top-color: var(--ink); }

.case h1 { font-size: clamp(1.6rem, 3.4vw, 2.3rem); line-height: 1.25; margin: 0.4rem 0 1.2rem; max-width: 30ch; }
.case .kicker {
  font-weight: var(--caps-weight);
  font-size: 0.72rem;
  letter-spacing: var(--caps-track);
  text-transform: uppercase;
  color: var(--slate);
}
.case-section { margin-top: 2.2rem; }
.case-section h2 { font-size: 1.05rem; letter-spacing: 0.04em; margin-bottom: 0.8rem; }
.case-section p, .case-section li { color: var(--slate); max-width: 68ch; }
.case-section ul { padding-left: 1.1rem; }
.case-section li { margin-bottom: 0.55rem; }
.testimonial { margin: 1.4rem 0 0; padding-left: 1.1rem; border-left: 2px solid var(--bronze); }
.testimonial blockquote { font-style: italic; color: var(--ink); max-width: 62ch; }
.testimonial figcaption { margin-top: 0.5rem; font-size: 0.85rem; color: var(--slate); }
.case-disclosure { margin-top: 2rem; font-size: 0.8rem; color: var(--slate); }
.case-back { margin-top: 2.6rem; }
.case-back a { color: var(--slate); }

/* ---------- Secondary button (case-page back nav) ---------- */
.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  background: transparent;
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 500;
  font-size: 0.92rem;
  letter-spacing: 0.01em;
  text-decoration: none;
  padding: 0.7rem 1.3rem;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.btn-secondary:hover { background: var(--paper); border-color: var(--ink); }
.btn-secondary .arrow-back { color: var(--bronze); }

/* ---------- Night mode (2026-07-22) ----------
   Zero JS, in keeping with the rest of the site: a visually hidden checkbox in the header
   plus :has() on <html>. That is a deliberate trade. The site ships script-src 'none' in
   _headers, so a localStorage toggle (what the internal archive dashboard uses) would need
   the CSP relaxed to allow an inline script. The cost of staying script-free is that the
   choice does NOT persist: it is per page, and a navigation returns to light. Nothing is
   stored, so the privacy page's "no cookies, nothing asked of you" claim still holds.

   Only the tokens move. Every rule above reads them, so dark mode is a palette swap, not a
   second stylesheet. The one exception is the two surfaces defined as "ink ground, light
   type" in BOTH themes (the contact band and the Navis quadrant tile): a naive swap would
   turn them into the brightest things on a dark page, so they re-invert the two tokens
   locally and keep their existing rules verbatim. */
.theme-input, .theme-toggle { display: none; }

/* The site hairline (12% ink) is calibrated for long rules and card edges; on a 30px ring it
   disappears. The ring gets its own weight, matching the presence the dashboard's toggle has. */
:root { --toggle-line: rgba(14, 27, 42, 0.3); }

@supports selector(html:has(*)) {
  .theme-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
  }
  .theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 30px;
    height: 30px;
    /* Optical, not arbitrary: the nav gap is measured for text links, and a ringed circle
       carries more visual weight than a word, so it needs to sit slightly tighter to read as
       part of the same row. Its right edge stays flush with the content measure. */
    margin-left: -0.55rem;
    border: 1px solid var(--toggle-line);
    border-radius: 50%;
    background: transparent;
    color: var(--slate);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
  }
  .theme-toggle:hover { color: var(--ink); border-color: var(--ink); }
  .theme-icon { width: 15px; height: 15px; display: block; }
  .theme-sun { display: none; }
  .theme-input:focus-visible + .theme-toggle { outline: 2px solid var(--bronze); outline-offset: 3px; }

  html:has(.theme-input:checked) .theme-moon { display: none; }
  html:has(.theme-input:checked) .theme-sun { display: block; }

  /* The ground is the archive dashboard's dark palette, adopted deliberately: the two Navis
     surfaces Ben works in daily should share one dark ground, and that one is already proven
     in use. Only the colour matches; the site keeps its own serif, measure, and rhythm.

     What was missing in the first cut was ELEVATION. Light mode gets its structure from white
     cards on off-white paper; inverting the tokens alone flattened all of that into one field
     of near-black. So dark mode builds an explicit ladder, darkest to lightest:
       band .......... #080D13   the contact/footer band, the floor
       page .......... #0F151B   --paper
       header ........ #141C25   the sticky bar, lifted just enough to read as chrome
       cards ......... #19212B   --card, the raised surfaces
     with hairlines a solid slate (#2A3542) rather than a low-alpha white, which is what makes
     the dashboard's edges look crisp instead of hazy. */
  html:has(.theme-input:checked) {
    --ink: #E6E8EA;
    --paper: #0F151B;
    --slate: #A2AEBB;           /* the dashboard's --muted, opened up: this carries body copy here */
    --bronze: #C9A25C;          /* lifted off #A8834B: the brand bronze goes muddy on ink */
    --hairline: #2A3542;
    --paper-muted: #B6C0CB;
    --card: #19212B;
    --header: #141C25;
    --fig-bg: rgba(230, 232, 234, 0.08);
    --toggle-line: rgba(230, 232, 234, 0.4);
  }
  html:has(.theme-input:checked) .band,
  html:has(.theme-input:checked) .quad-navis {
    --ink: #080D13;
    --paper: #E6E8EA;
    --paper-muted: #AFBAC7;
    --hairline: #2A3542;
  }
  /* The founder portrait is the one image on the site; full-strength white on ink glares. */
  html:has(.theme-input:checked) .about img { filter: grayscale(100%) brightness(0.86); }
}
