/* ---------------------------------------------------------------
   kvoma.com

   Fonts self-hosted (no third-party origin). No analytics, no cookies.

   The page keeps the systematic grid and the node-and-edge diagrams
   that carry the identity, and adds what a flat single-column reading
   of them was missing: layered surfaces, an accent per subject, and
   segmentation you can see from across the room.

   Motion rule that survives from the previous build: nothing on this
   page may start invisible and depend on an animation to become
   visible. Hover, focus and scroll-progress only. See the note at the
   bottom of this file.
   --------------------------------------------------------------- */

/* Display. Archivo Variable instanced to wdth 125, wght axis kept at
   400–700, subset to the characters the site sets. 88KB -> 14.9KB. */
@font-face {
  font-family: "Archivo Expanded";
  src: url("/fonts/archivo-expanded-var.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Plex Sans";
  src: url("/fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex Sans";
  src: url("/fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex Sans";
  src: url("/fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex Mono";
  src: url("/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex Mono";
  src: url("/fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------
   Tokens

   Warm grey-white paper, warm near-black ink, and an analogous warm
   accent range: mustard as the primary, clay and moss either side of
   it. One hue family rather than a spectrum, which is what keeps it
   quiet — colour marks subject, it is not decoration. Each accent
   has a fixed meaning: signal for the practice and anything that
   routes, moss for infrastructure and data residency, clay for work
   still in progress, neutral ink for the parts that are only plumbing.

   Every accent below is a text-safe value measured against --canvas:
   signal 5.1:1, clay 5.3:1, moss 5.2:1, muted 4.8:1. --signal-bright
   is the one exception — it is for strokes and fills only, where the
   3:1 non-text threshold applies, and it measures 3.4:1.
   --------------------------------------------------------------- */

:root {
  color-scheme: light;

  --canvas: #f5f3ee;
  --surface: #fdfcf9;
  --surface-2: #eeebe3;
  --surface-3: #e5e1d7;

  --ink: #17140f;
  --body: #453f36;
  --muted: #6e6a61;

  --line: #e2ded4;
  --line-strong: #c9c3b5;

  --signal: #9c5400;
  --signal-hover: #7e4300;
  --signal-bright: #b4770a;
  --signal-tint: #faefd9;
  /* Mustard is a light hue: its label is always dark ink, in both
     themes, which is what keeps the CTA at 4.9:1 rather than 3.8:1. */
  --on-signal: #17140f;
  --signal-edge: #ead3a2;

  --clay: #a6462a;
  --clay-tint: #fbe8e1;
  --clay-edge: #efc3b2;

  --moss: #5f6b25;
  --moss-tint: #eff1dc;
  --moss-edge: #cfd69f;

  /* The neutral accent, for blocks that are plumbing rather than a
     subject of their own. Warm grey, not a fourth hue. */
  --ink-accent: #3f3a31;
  --ink-tint: #e8e4da;
  --ink-edge: #c9c3b5;

  --shadow-1: 0 1px 2px rgb(46 38 26 / 5%), 0 2px 6px rgb(46 38 26 / 4%);
  --shadow-2: 0 2px 4px rgb(46 38 26 / 6%), 0 14px 32px -10px rgb(46 38 26 / 16%);
  --shadow-3: 0 4px 8px rgb(46 38 26 / 7%), 0 26px 50px -14px rgb(46 38 26 / 22%);

  --display: "Archivo Expanded", ui-sans-serif, system-ui, sans-serif;
  --sans: "Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --shell: 74rem;
  --pad: 1.25rem;
  --measure: 40rem;

  --r-xs: 4px;
  --r-sm: 8px;
  --r: 14px;
  --r-lg: 22px;
  --r-pill: 999px;

  --accent: var(--signal);
  --accent-tint: var(--signal-tint);
  --accent-edge: var(--signal-edge);
}

/* Dark is opt-in, not automatic.
 *
 * The identity is the warm paper: that is what the mark, the OG card
 * and the print stylesheet all assume, and following the system
 * preference would hand half the audience a first impression the
 * brand was not drawn for. The toggle is one click and the choice
 * persists. To make it automatic instead, wrap this block in
 * @media (prefers-color-scheme: dark) with :root:not([data-theme="light"]).
 *
 * Same hues, warmed and lifted rather than re-picked, so the two
 * themes read as one design under different light. */
[data-theme="dark"] {
  color-scheme: dark;

  --canvas: #14120e;
  --surface: #1c1915;
  --surface-2: #221f1a;
  --surface-3: #2a2620;

  --ink: #f5f2eb;
  --body: #c4bdb1;
  --muted: #948d80;

  --line: #2c2823;
  --line-strong: #3e3931;

  --signal: #e7b44a;
  --signal-hover: #f3c566;
  --signal-bright: #e7b44a;
  --signal-tint: #2a2010;
  --on-signal: #17140f;
  --signal-edge: #55411a;

  --clay: #e2937a;
  --clay-tint: #2c1a14;
  --clay-edge: #5a3226;

  --moss: #b3c266;
  --moss-tint: #1f2412;
  --moss-edge: #3e4922;

  --ink-accent: #cfc8ba;
  --ink-tint: #262219;
  --ink-edge: #4a443a;

  --shadow-1: 0 1px 2px rgb(0 0 0 / 45%);
  --shadow-2: 0 2px 4px rgb(0 0 0 / 45%), 0 14px 32px -10px rgb(0 0 0 / 65%);
  --shadow-3: 0 4px 8px rgb(0 0 0 / 50%), 0 26px 50px -14px rgb(0 0 0 / 75%);
}

@media (min-width: 48rem) {
  :root {
    --pad: 2rem;
  }
}

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

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

body {
  margin: 0;
  background: var(--canvas);
  color: var(--body);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

/* Deliberately no overflow-x:hidden on the body. It hides layout bugs
   by clipping them instead of showing a scrollbar — a 375px-wide hero
   was silently losing its right edge behind exactly that. The hero
   clips its own decorative bleed instead. */

.shell {
  width: min(100%, var(--shell));
  margin-inline: auto;
  padding-inline: var(--pad);
}

/* ---------------------------------------------------------------
   Type
   --------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  color: var(--ink);
  margin: 0;
}

h1,
h2 {
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.025em;
  text-wrap: balance;
}

h3 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.35;
}

p {
  margin: 0 0 1rem;
  max-width: var(--measure);
  text-wrap: pretty;
}

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

a {
  color: var(--signal);
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
  transition: color 140ms ease, text-decoration-color 140ms ease;
}

a:hover {
  color: var(--signal-hover);
  text-decoration-color: currentColor;
}

:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

/* Utility face. Marks a string as data rather than prose — which is
   exactly what a verifier scanning for registration numbers wants. */
.mono,
.eyebrow,
.tag,
.badge,
.wordmark,
.nav a,
.stat__key,
.reg dt,
.reg dd,
.step__num,
.footer__label,
.d-label {
  font-family: var(--mono);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--accent);
}

.eyebrow__num {
  display: inline-grid;
  place-items: center;
  min-width: 1.6rem;
  height: 1.35rem;
  padding-inline: 0.35rem;
  border-radius: var(--r-xs);
  background: var(--accent-tint);
  color: var(--accent);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
}

.skip-link {
  position: fixed;
  left: 0.75rem;
  top: -6rem;
  z-index: 100;
  background: var(--ink);
  color: var(--canvas);
  padding: 0.7rem 1.1rem;
  border-radius: var(--r-sm);
  text-decoration: none;
  font-size: 0.875rem;
}

/* No transition on this one. A transition would make the skip link's
   arrival depend on the animation clock advancing, and where the clock
   does not advance the link never becomes visible — the same failure
   the load fade had, but this time it takes keyboard access with it. */
.skip-link:focus {
  top: 0.75rem;
}

/* ---------------------------------------------------------------
   Scroll progress

   Layout-driven, not clock-driven. Where the timeline is not
   supported the bar simply stays at zero width — nothing on the page
   depends on it.
   --------------------------------------------------------------- */

.progress {
  position: fixed;
  inset: 0 0 auto;
  height: 2px;
  z-index: 60;
  pointer-events: none;
}

.progress__bar {
  height: 100%;
  background: linear-gradient(90deg, var(--signal-bright), var(--clay) 55%, var(--moss));
  transform: scaleX(0);
  transform-origin: 0 50%;
}

@supports (animation-timeline: scroll()) {
  .progress__bar {
    animation: progress-grow linear both;
    animation-timeline: scroll(root block);
  }
}

@keyframes progress-grow {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

/* ---------------------------------------------------------------
   Header
   --------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--canvas) 82%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms ease, background 200ms ease;
}

.site-header.is-stuck {
  border-bottom-color: var(--line);
  background: color-mix(in srgb, var(--canvas) 92%, transparent);
}

.header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
  padding-block: 0.85rem;
}

.wordmark {
  font-family: var(--display);
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: 0.005em;
  text-transform: none;
  color: var(--ink);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-right: auto;
}

/* The mark is the site's own vocabulary at icon scale: two inputs, a
   bus, one output. Inline rather than an <img> so it follows the
   theme instead of carrying a baked-in background. */
.wordmark__mark {
  display: block;
  width: 26px;
  height: 26px;
  flex: none;
}

.mark__plate {
  fill: var(--signal-bright);
}

.mark__ink {
  fill: var(--canvas);
}

.wordmark:hover {
  color: var(--signal);
}

.nav {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  order: 3;
  width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 0.15rem;
}

.nav::-webkit-scrollbar {
  display: none;
}

.nav a {
  font-size: 0.6875rem;
  color: var(--muted);
  text-decoration: none;
  padding: 0.4rem 0.6rem;
  border-radius: var(--r-pill);
  white-space: nowrap;
  transition: color 140ms ease, background 140ms ease;
}

.nav a:hover {
  color: var(--ink);
  background: var(--surface-2);
}

.nav a.is-active {
  color: var(--signal);
  background: var(--signal-tint);
}

.header__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

@media (min-width: 60rem) {
  .nav {
    order: 0;
    width: auto;
    overflow: visible;
    margin-right: 0.5rem;
    padding-bottom: 0;
  }
}

/* ---------------------------------------------------------------
   Buttons
   --------------------------------------------------------------- */

.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--canvas);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.7rem 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: transform 140ms ease, box-shadow 160ms ease, background 140ms ease,
    border-color 140ms ease, color 140ms ease;
}

.btn:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-2);
  color: var(--btn-fg);
}

.btn:active {
  transform: translateY(0);
  box-shadow: none;
}

/* The foreground follows the canvas rather than being pinned to white,
   so the pair stays legible when the accent lightens in dark mode. */
.btn--primary {
  --btn-bg: var(--signal-bright);
  --btn-fg: var(--on-signal);
}

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  border-color: var(--line-strong);
}

.btn--ghost:hover {
  border-color: var(--ink);
  background: var(--surface-2);
}

.btn--sm {
  padding: 0.45rem 0.85rem;
  font-size: 0.8125rem;
}

.btn__arrow {
  transition: transform 180ms ease;
}

.btn:hover .btn__arrow {
  transform: translateX(3px);
}

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 2.15rem;
  height: 2.15rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition: color 140ms ease, border-color 140ms ease, background 140ms ease;
}

.icon-btn:hover {
  color: var(--ink);
  border-color: var(--line-strong);
}

/* The toggle cannot work without script, so it is not shown without
   script. app.js sets .js on <html>. */
.theme-toggle {
  display: none;
}

.js .theme-toggle {
  display: inline-grid;
}

/* The button shows the theme it will switch you to, not the one you
   are in. */
.theme-toggle .icon-sun {
  display: none;
}

.theme-toggle .icon-moon {
  display: block;
}

[data-theme="dark"] .theme-toggle .icon-moon {
  display: none;
}

[data-theme="dark"] .theme-toggle .icon-sun {
  display: block;
}


/* ---------------------------------------------------------------
   Hero
   --------------------------------------------------------------- */

.hero {
  position: relative;
  padding-top: clamp(3rem, 1rem + 7vw, 6rem);
  padding-bottom: clamp(2.5rem, 1rem + 5vw, 4.5rem);
  overflow: hidden;
}

.hero::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto;
  height: 130%;
  background-image: radial-gradient(circle at 1px 1px, var(--line-strong) 1px, transparent 0);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(ellipse 70% 55% at 25% 15%, #000 10%, transparent 72%);
  mask-image: radial-gradient(ellipse 70% 55% at 25% 15%, #000 10%, transparent 72%);
  opacity: 0.7;
  pointer-events: none;
}

.hero::after {
  content: "";
  position: absolute;
  inset: -30% -20% auto 30%;
  height: 120%;
  background: radial-gradient(
      42rem 26rem at 70% 18%,
      color-mix(in srgb, var(--signal) 14%, transparent),
      transparent 70%
    ),
    radial-gradient(
      30rem 22rem at 96% 62%,
      color-mix(in srgb, var(--moss) 12%, transparent),
      transparent 70%
    );
  pointer-events: none;
}

.hero__inner {
  position: relative;
  display: grid;
  gap: clamp(2.5rem, 1rem + 5vw, 4rem);
  align-items: center;
}

/* Grid items size to max-content by default. Without this, a track
   inside them resolves its percentage minimum against an indefinite
   width and pushes the whole column past the viewport. */
.hero__inner > * {
  min-width: 0;
}

@media (min-width: 62rem) {
  .hero__inner {
    grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
  }
}

.hero h1 {
  font-size: clamp(2.1rem, 1.2rem + 3.4vw, 3.35rem);
  max-width: 18ch;
  margin-bottom: 1.5rem;
}

.hero h1 em {
  font-style: normal;
  color: var(--signal-bright);
}

.hero__lede {
  font-size: clamp(1.0625rem, 1rem + 0.45vw, 1.1875rem);
  max-width: 34rem;
  margin-bottom: 2rem;
}

.hero__status {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: 1.5rem;
  padding: 0.35rem 0.85rem 0.35rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--body);
}

.dot {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--moss);
  flex: none;
}

.dot::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1px solid var(--moss);
  opacity: 0.5;
  animation: ping 2.8s ease-out infinite;
}

@keyframes ping {
  0% {
    transform: scale(0.7);
    opacity: 0.7;
  }
  70%,
  100% {
    transform: scale(1.5);
    opacity: 0;
  }
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 2.25rem;
}

.hero__facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  max-width: 30rem;
}

.stat {
  background: var(--surface);
  padding: 0.85rem 1rem;
}

.stat__key {
  display: block;
  font-size: 0.5625rem;
  font-weight: 500;
  color: var(--muted);
  margin-bottom: 0.25rem;
}

.stat__val {
  display: block;
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
  letter-spacing: 0;
  text-transform: none;
}

/* The hero topology is decoration, not information: it is the same
   node-and-edge vocabulary the content diagrams use, drawn large.
   It carries no labels and is hidden from assistive technology. */
/* The hero drawing is decoration, so it takes the brighter mustard
   rather than the text-safe ochre the content diagrams use. */
.hero__art {
  --accent: var(--signal-bright);
  justify-self: center;
  width: 100%;
  max-width: 34rem;
}

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

@media (max-width: 44rem) {
  .hero__art {
    max-width: 22rem;
  }
}

/* ---------------------------------------------------------------
   Bands
   --------------------------------------------------------------- */

.band {
  position: relative;
  padding-block: clamp(3.5rem, 2rem + 6vw, 6.5rem);
  border-top: 1px solid var(--line);
}

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

.section-head {
  max-width: 46rem;
  margin-bottom: clamp(2rem, 1rem + 3vw, 3.25rem);
}

.section-head .eyebrow {
  margin-bottom: 1.1rem;
}

.section-head h2 {
  font-size: clamp(1.75rem, 1.15rem + 2.4vw, 2.75rem);
  margin-bottom: 1.1rem;
}

.section-lede {
  font-size: 1.0625rem;
  max-width: 44rem;
  color: var(--body);
  margin-bottom: 0;
}

.section-lede + .section-lede {
  margin-top: 0.85rem;
}

/* ---------------------------------------------------------------
   Cards
   --------------------------------------------------------------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: clamp(1.35rem, 1rem + 1vw, 1.85rem);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: transform 200ms ease, box-shadow 220ms ease, border-color 200ms ease;
}

.card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 260ms cubic-bezier(0.2, 0.8, 0.3, 1);
}

.card:hover,
.card:focus-within {
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
  border-color: var(--accent-edge);
}

.card:hover::before,
.card:focus-within::before {
  transform: scaleX(1);
}

.card__icon {
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: var(--r-sm);
  background: var(--accent-tint);
  color: var(--accent);
  margin-bottom: 1.1rem;
}

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

.card p {
  font-size: 0.9375rem;
  max-width: none;
  color: var(--body);
}

.card__foot {
  margin-top: auto;
  padding-top: 1.25rem;
}

.cards {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  align-items: stretch;
}

/* ---------------------------------------------------------------
   Accent themes. Applied to any block that owns a subject.
   --------------------------------------------------------------- */

.t-signal {
  --accent: var(--signal);
  --accent-tint: var(--signal-tint);
  --accent-edge: var(--signal-edge);
}

.t-moss {
  --accent: var(--moss);
  --accent-tint: var(--moss-tint);
  --accent-edge: var(--moss-edge);
}

.t-clay {
  --accent: var(--clay);
  --accent-tint: var(--clay-tint);
  --accent-edge: var(--clay-edge);
}

.t-ink {
  --accent: var(--ink-accent);
  --accent-tint: var(--ink-tint);
  --accent-edge: var(--ink-edge);
}

/* ---------------------------------------------------------------
   Badges and tags
   --------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--r-pill);
  background: var(--accent-tint);
  color: var(--accent);
  border: 1px solid var(--accent-edge);
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.4;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tag {
  display: inline-block;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: var(--r-xs);
  background: var(--surface-2);
  color: var(--muted);
  font-size: 0.5875rem;
  font-weight: 500;
  transition: color 140ms ease, border-color 140ms ease, background 140ms ease;
}

.entry:hover .tag {
  color: var(--body);
  border-color: var(--line-strong);
}

/* ---------------------------------------------------------------
   Work entries
   --------------------------------------------------------------- */

.entries {
  display: grid;
  gap: 1.75rem;
}

.entry {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-1);
  transition: box-shadow 240ms ease, border-color 220ms ease;
}

.entry:hover {
  box-shadow: var(--shadow-2);
  border-color: var(--accent-edge);
}

.entry__body {
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  display: grid;
  gap: 1.75rem;
}

@media (min-width: 56rem) {
  .entry__body {
    grid-template-columns: 12rem minmax(0, 1fr);
    gap: 2.5rem;
  }
}

.entry__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.85rem;
}

.entry h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.25rem, 1.05rem + 0.8vw, 1.6rem);
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 1rem;
}

.entry h3 .entry__for {
  display: block;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
  margin-top: 0.55rem;
}

.entry p {
  font-size: 0.9688rem;
}

.entry__figure {
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}

/* ---------------------------------------------------------------
   Diagrams

   Geometry is asserted by tools/check-diagrams.mjs. Node coordinates
   sit on a .5 grid so 1px strokes land on whole pixels, and no label
   may cross an edge line. Read that file before moving anything.
   --------------------------------------------------------------- */

.diagram {
  overflow-x: auto;
  padding: clamp(1.1rem, 0.8rem + 1vw, 1.75rem);
  scrollbar-width: thin;
}

.diagram svg {
  display: block;
  max-width: none;
  margin-inline: auto;
}

/* The two work diagrams scroll on narrow screens because shrinking
   them would take their labels below legibility. The card diagrams
   are small enough to scale instead, which is better than a scroll
   affordance inside a card. */
.card .diagram {
  margin-top: 1.25rem;
  padding: 1rem 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: visible;
}

.card .diagram svg {
  width: 100%;
  max-width: 300px;
  height: auto;
}

.d-node {
  fill: var(--surface);
  stroke: var(--line-strong);
  stroke-width: 1;
  transition: fill 160ms ease, stroke 160ms ease;
}

.d-node--process {
  fill: var(--accent-tint);
  stroke: var(--accent);
}

.d-node--moss {
  fill: var(--moss-tint);
  stroke: var(--moss);
}

.d-node--clay {
  fill: var(--clay-tint);
  stroke: var(--clay);
}

.d-node--ink-accent {
  fill: var(--ink-tint);
  stroke: var(--ink-accent);
}

.d-edge {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1;
  opacity: 0.85;
}

.d-edge--soft {
  stroke: var(--line-strong);
  stroke-dasharray: 3 3;
  opacity: 1;
}

.d-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  fill: var(--muted);
  transition: fill 160ms ease;
}

.d-group {
  cursor: default;
}

.d-group:hover .d-node {
  fill: var(--accent);
  stroke: var(--accent);
}

.d-group:hover .d-node--process {
  fill: var(--accent);
}

.d-group:hover .d-label {
  fill: var(--ink);
}

/* The hero topology gets the one piece of ambient motion on the page:
   a short dash travelling along the routes, drawn on top of the solid
   edges. If the animation never runs the topology is still fully
   drawn — the flow paths are additive, not the picture itself. */
.d-edge--flow {
  stroke: var(--signal);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 10 260;
  opacity: 1;
  animation: dash-flow 5s linear infinite;
}

.d-edge--flow-2 {
  stroke: var(--moss);
  animation-delay: -1.25s;
}

.d-edge--flow-3 {
  stroke: var(--clay);
  animation-delay: -2.5s;
}

.d-edge--flow-4 {
  stroke: var(--ink-accent);
  animation-delay: -3.75s;
}

@keyframes dash-flow {
  from {
    stroke-dashoffset: 270;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* A frozen dash sitting on the page is worse than none. */
@media (prefers-reduced-motion: reduce) {
  .d-edge--flow {
    display: none;
  }
}

/* ---------------------------------------------------------------
   How I work — steps
   --------------------------------------------------------------- */

.steps {
  counter-reset: step;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
}

.steps > li {
  counter-increment: step;
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 1.5rem;
  box-shadow: var(--shadow-1);
  transition: transform 200ms ease, box-shadow 220ms ease, border-color 200ms ease;
}

.steps > li:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
  border-color: var(--accent-edge);
}

.step__num {
  display: inline-grid;
  place-items: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  border: 1px solid var(--accent-edge);
  background: var(--accent-tint);
  color: var(--accent);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  margin-bottom: 1rem;
  transition: background 200ms ease, color 200ms ease;
}

.steps > li:hover .step__num {
  background: var(--accent);
  color: var(--canvas);
}

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

.steps p {
  font-size: 0.9063rem;
  max-width: none;
  margin: 0;
}

/* The rail behind the numbers, drawn only where four cards sit in
   one row. It reads as a sequence rather than four unrelated boxes. */
@media (min-width: 64rem) {
  .steps {
    position: relative;
  }

  .steps::before {
    content: "";
    position: absolute;
    top: 2.55rem;
    left: 2.5rem;
    right: 2.5rem;
    height: 1px;
    background: repeating-linear-gradient(
      90deg,
      var(--line-strong) 0 4px,
      transparent 4px 9px
    );
    z-index: 0;
  }

  .steps > li {
    z-index: 1;
  }
}

/* ---------------------------------------------------------------
   Approach — principle rows
   --------------------------------------------------------------- */

.points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}

.points > li {
  position: relative;
  padding: 1.6rem 1.5rem 1.6rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--r);
  box-shadow: var(--shadow-1);
  transition: transform 200ms ease, box-shadow 220ms ease;
}

.points > li:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
}

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

.points p {
  font-size: 0.9063rem;
  max-width: none;
  margin: 0;
}

/* ---------------------------------------------------------------
   Contact
   --------------------------------------------------------------- */

.contact {
  display: grid;
  gap: 2rem;
  align-items: start;
}

@media (min-width: 58rem) {
  .contact {
    grid-template-columns: minmax(0, 1fr) minmax(0, 25rem);
    gap: 3rem;
  }
}

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

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}

.panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.25rem;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}

.panel__title {
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

.reg {
  margin: 0;
  padding: 0.4rem 1.25rem 1rem;
}

.reg > div {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 0.25rem 0.75rem;
  padding-block: 0.7rem;
  border-bottom: 1px solid var(--line);
}

.reg > div:last-child {
  border-bottom: 0;
}

.reg dt {
  font-size: 0.625rem;
  font-weight: 500;
  color: var(--muted);
}

.reg dd {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
}

.reg dd a {
  color: var(--ink);
  text-decoration: none;
}

.reg dd a:hover {
  color: var(--signal);
}

/* Copy buttons are script-driven, so they are absent without script.
   Every value they copy is selectable text either way. */
.copy {
  display: none;
  padding: 0.2rem;
  width: 1.6rem;
  height: 1.6rem;
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  align-self: center;
  transition: color 140ms ease, background 140ms ease, border-color 140ms ease;
}

.js .copy {
  display: inline-grid;
  place-items: center;
}

.copy:hover {
  color: var(--signal);
  background: var(--signal-tint);
  border-color: var(--signal-edge);
}

.copy[data-copied="true"] {
  color: var(--moss);
  background: var(--moss-tint);
  border-color: var(--moss-edge);
}

.copy .icon-check {
  display: none;
}

.copy[data-copied="true"] .icon-check {
  display: block;
}

.copy[data-copied="true"] .icon-copy {
  display: none;
}

@media (max-width: 30rem) {
  .reg > div {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .reg dt {
    grid-column: 1 / -1;
  }
}

/* ---------------------------------------------------------------
   Footer
   --------------------------------------------------------------- */

.footer {
  border-top: 1px solid var(--line);
  background: var(--surface-2);
  padding-block: 3rem 2rem;
}

.footer__grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  padding-bottom: 2rem;
  border-bottom: 1px solid var(--line);
}

.footer__brand p {
  font-size: 0.875rem;
  margin-top: 0.85rem;
  max-width: 22rem;
  color: var(--muted);
}

.footer__label {
  display: block;
  font-size: 0.5625rem;
  font-weight: 500;
  color: var(--muted);
  margin-bottom: 0.9rem;
}

.footer__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.footer__list a {
  font-size: 0.875rem;
  color: var(--body);
  text-decoration: none;
}

.footer__list a:hover {
  color: var(--signal);
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  align-items: center;
  justify-content: space-between;
  padding-top: 1.5rem;
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------------------------------------------------------------
   Back to top
   --------------------------------------------------------------- */

.to-top {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 40;
  width: 2.6rem;
  height: 2.6rem;
  display: none;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--body);
  box-shadow: var(--shadow-2);
  cursor: pointer;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 200ms ease, transform 200ms ease, color 140ms ease;
}

.js .to-top {
  display: grid;
}

.to-top.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.to-top:not(.is-visible) {
  pointer-events: none;
}

.to-top:hover {
  color: var(--signal);
}

/* ---------------------------------------------------------------
   Legal document pages
   --------------------------------------------------------------- */

.doc {
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 4.5rem) 4rem;
  display: grid;
  gap: 2.5rem;
}

@media (min-width: 60rem) {
  .doc {
    grid-template-columns: minmax(0, 1fr) 14rem;
    gap: 3.5rem;
    align-items: start;
  }

  .doc__aside {
    position: sticky;
    top: 6rem;
  }
}

.toc {
  border-left: 2px solid var(--line);
  padding-left: 1.1rem;
}

.toc__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
  counter-reset: toc;
}

.toc__list li {
  counter-increment: toc;
}

.toc__list a {
  display: grid;
  grid-template-columns: 1.4rem minmax(0, 1fr);
  gap: 0.4rem;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--muted);
  text-decoration: none;
  transition: color 140ms ease;
}

.toc__list a::before {
  content: counter(toc, decimal-leading-zero);
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  color: var(--line-strong);
  padding-top: 0.15em;
}

.toc__list a:hover {
  color: var(--signal);
}

.toc__list a:hover::before {
  color: var(--signal);
}

/* Below the two-column breakpoint the rail would land after the text it
   indexes, which is worse than not having it. The headings themselves
   are the navigation there. */
@media (max-width: 59.999rem) {
  .doc__aside {
    display: none;
  }
}

.doc__main h1 {
  font-size: clamp(1.85rem, 1.3rem + 2.2vw, 2.6rem);
  margin-bottom: 1.5rem;
}

.doc__updated {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 2rem;
}

.doc__main h2 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.35;
  letter-spacing: 0;
  margin: 2.5rem 0 0.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}

.doc__main h3 {
  font-size: 0.9688rem;
  margin: 1.5rem 0 0.5rem;
}

.doc__main p,
.doc__main li {
  max-width: var(--measure);
}

.doc__main ul,
.doc__main ol {
  padding-left: 1.25rem;
  margin: 0 0 1rem;
}

.doc__main li {
  margin-bottom: 0.45rem;
}

.doc__main code {
  font-family: var(--mono);
  font-size: 0.8125em;
  padding: 0.1em 0.35em;
  border: 1px solid var(--line);
  border-radius: var(--r-xs);
  background: var(--surface-2);
  color: var(--ink);
}

.doc address {
  font-style: normal;
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.8;
  padding: 1rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--signal);
  border-radius: var(--r);
  margin: 0 0 1.5rem;
  max-width: var(--measure);
}

/* ---------------------------------------------------------------
   Motion

   Everything above is additive: hover, focus, scroll progress and one
   ambient dash flow. No element on this page starts hidden and waits
   for an animation to reveal it — that failure mode was measured on
   the previous build, where a 200ms load fade left the document at
   opacity 0 in a tab that had not composited. A page whose job is to
   be read by a verifier never gets to be blank.
   --------------------------------------------------------------- */

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

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .card:hover,
  .entry:hover,
  .steps > li:hover,
  .points > li:hover,
  .btn:hover {
    transform: none;
  }
}

/* ---------------------------------------------------------------
   Print
   --------------------------------------------------------------- */

@media print {
  .site-header,
  .progress,
  .to-top,
  .hero::before,
  .hero::after,
  .copy,
  .theme-toggle {
    display: none !important;
  }

  body {
    background: #fff;
    color: #000;
  }

  .card,
  .entry,
  .panel,
  .steps > li,
  .points > li {
    box-shadow: none;
    border-color: #bbb;
    break-inside: avoid;
  }
}
