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

/* THEME

   Roles, not colours: --fg/--bg swap between themes, so anything built from
   them inverts for free. The original --black/--white/--gray/--border names
   are kept as aliases because the whole stylesheet is written against them —
   note they stop being literal in dark, where --black is a light grey.

   Dark is the default. The system preference is deliberately not consulted;
   light is opt-in through the switch, which pins data-theme on <html>. */

:root {
  color-scheme: dark;

  --bg: #0e0f10;
  --fg: #ededed;
  --muted: #8b8b8b;
  --line: #2b2d2f;
  --surface: #17181a;      /* inputs, code, other inset panels */
  --prose: #c6c6c6;        /* long-form body copy */
  --accent: #e0705f;
  --accent-faint: #bf6153;   /* pulled back, for display type */
  --navy: #9fb4e0;

  /* hero field */
  --field-dot: rgba(255, 255, 255, 0.18);
  --field-ink-1: #f0f0f0;
  --field-ink-2: #b4b4b4;
  --field-ink-3: #7c7c7c;
  --field-link: #4ec08c;

  /* Figure series, for charts in the long-form pages */
  --s1: #57b98a;
  --s2: #d8a05a;
  --s3: #e0705f;

  --black: var(--fg);
  --white: var(--bg);
  --gray: var(--muted);
  --border: var(--line);
}

:root[data-theme="light"] {
  color-scheme: light;

  --bg: #ffffff;
  --fg: #0a0a0a;
  --muted: #888888;
  --line: #e0e0e0;
  --surface: #f7f7f7;
  --prose: #222222;
  --accent: #c0392b;
  --accent-faint: #c9584a;
  --navy: #0a1f44;

  --field-dot: rgba(10, 10, 10, 0.22);
  --field-ink-1: #0a0a0a;
  --field-ink-2: #3d3d3d;
  --field-ink-3: #707070;
  --field-link: #1a7f55;

  --s1: #2f7d4f;
  --s2: #a8681f;
  --s3: #c0392b;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  background: var(--white);
  color: var(--black);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* NAV — scoped to the site header; bare `nav` would also hit the
   contents rail and the keep-reading list on the long-form pages. */

header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  background: var(--white);
  border-bottom: 1px solid var(--border);
}

header nav {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 2rem;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.logo {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}

header nav ul {
  list-style: none;
  display: flex;
  /* Without this the items stretch and the toggle's icon, being shorter than
     a line of text, rides up to the top of its row. */
  align-items: center;
  gap: 2rem;
}

header nav a {
  text-decoration: none;
  font-family: "Merriweather", "Times New Roman", serif;
  color: var(--gray);
  font-size: 0.9rem;
  transition: color 0.2s;
}

header nav a:hover,
header nav a.is-current {
  color: var(--black);
}

/* Five nav items plus the toggle get tight on small screens. */
@media (max-width: 560px) {
  header nav {
    padding: 0 1.25rem;
  }
  header nav ul {
    gap: 1.1rem;
  }
  header nav a {
    font-size: 0.82rem;
  }
}

/* Below this the row cannot fit at any readable size, so the links scroll
   under the wordmark rather than pushing the document wider than the phone. */
@media (max-width: 480px) {
  header nav {
    padding: 0 1rem;
    gap: 0.75rem;
  }
  header nav ul {
    gap: 0.9rem;
    overflow-x: auto;
    scrollbar-width: none;
    /* Keeps the flex item from refusing to shrink below its content. */
    min-width: 0;
  }
  header nav ul::-webkit-scrollbar {
    display: none;
  }
  header nav li {
    flex: 0 0 auto;
  }
  /* The theme toggle is the last item and must not scroll out of reach, so
     it stays pinned to the right edge while the links pass underneath. */
  header nav li:last-child {
    position: sticky;
    right: 0;
    background: var(--white);
    padding-left: 0.6rem;
    box-shadow: -0.6rem 0 0.6rem var(--white);
  }
  header nav a {
    font-size: 0.78rem;
  }
}

/* HERO */

/* The hero owns the first screen, with no rule closing it off. Visitors were
   landing here and not realising there was anything below, which the bobbing
   cue at the bottom now answers. An earlier version instead ran the hero
   short so the next section was sliced by the fold. */
#hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
}

/* HERO FIELD

   The dot grid is a CSS background so it covers the section at any size and
   is still there with JS off. hero-field.js layers a canvas on top and draws
   only the searching pairs. Pitch and origin must match PITCH/ORIGIN there. */

/* Sits over the field, centred on the hero rather than the text column.
   The bob is the whole point, so it is the one thing on the page that
   moves without being asked to. */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 2.75rem;
  z-index: 2;
  display: block;
  color: var(--accent);
  opacity: 0.75;
  transition: opacity 0.25s ease;
  animation: cue-bob 2.4s ease-in-out infinite;
}

.scroll-cue:hover,
.scroll-cue:focus-visible {
  opacity: 1;
}

.scroll-cue svg {
  display: block;
  width: 32px;
  height: 64px;
  fill: none;
  stroke: currentColor;
  /* Scaled with the arrow: 1.4 at 40px tall reads as a hairline at 64px. */
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The translate has to carry the centring too, or the keyframe overwrites it. */
@keyframes cue-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 9px); }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue { animation: none; transform: translateX(-50%); }
}

.hero-field {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 76%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 76%, transparent 100%);
  background-image: radial-gradient(circle at 7.5px 7.5px, var(--field-dot) 1.25px, transparent 1.3px);
  background-size: 15px 15px;
}

/* Once the canvas takes over it paints the grid itself, so the cursor can
   reshape individual dots. Two copies would just double them up. */
.hero-field.is-live {
  background-image: none;
}

.hero-field-canvas {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.hero-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 1250px;
  margin: 0 auto;
  padding: 8rem 2rem 6rem;
}

.hero-text {
  position: relative;
  /* Sized to the longest headline line now that it breaks over three.
     Wider and the blurred halo behind it floats out past the words. */
  max-width: 34rem;
}

/* Stops the line breaking on the hyphen and stranding "Unsafe Code". */
#hero h1 .nb {
  white-space: nowrap;
}

/* text-wrap: balance gives up when an inline span is present and picks the
   lopsided split, so the break is placed by hand. It is dropped on narrow
   screens, where the space before it lets the line reflow normally. */
#hero h1 .h1-break {
  display: inline;
}

@media (max-width: 560px) {
  #hero h1 .h1-break {
    display: none;
  }
}

/* Legibility comes from a soft halo hugging the text rather than a wash
   across the whole hero, so the field stays live right up to the words. */
.hero-text::before {
  content: "";
  position: absolute;
  inset: -1.75rem -2.5rem;
  z-index: -1;
  background: var(--white);
  border-radius: 38%;
  filter: blur(30px);
  /* Enough to keep the type legible over the field without reading as a
     panel behind the text. Inset and blur are left alone so it stays as
     close to the text as before. */
  opacity: 0.78;
}

#hero h1 {
  font-family: "Merriweather", "Times New Roman", serif;
  /* Display scale. The column below had to widen to hold it. */
  font-size: clamp(2.1rem, 4.8vw, 4rem);
  font-weight: 400;
  /* Tighter tracking and leading, which large type needs and small type does not. */
  letter-spacing: -0.025em;
  line-height: 1.08;
  margin-bottom: 1.4rem;
  /* Evens the line lengths instead of leaving a long line above a stub. */
  text-wrap: balance;
}

.h1-accent,
.accent-soft {
  color: var(--accent-faint);
}

/* Sized here rather than on .hero-subtitle: this id selector outranks the
   class, so a font-size set there would never take effect. Tuned so the
   subtitle sits between the two headline line lengths. */
#hero p {
  font-size: clamp(0.85rem, 1.15vw, 1.02rem);
  color: var(--gray);
  max-width: 100%;
  margin-bottom: 1.9rem;
}

.hero-subtitle {
  font-family: "Merriweather", "Times New Roman", serif;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--gray);
  max-width: none;
}

/* Scoped past `#hero p`, which sets the size for everything in the hero.
   Larger than that default so the positioning line carries below the
   headline rather than sitting at caption weight. */
#hero .hero-subtitle {
  font-size: clamp(1rem, 1.7vw, 1.4rem);
  line-height: 1.5;
}

.accent {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.btn {
  display: inline-block;
  padding: 0.75rem 1.75rem;
  background: var(--black);
  color: var(--white);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  /* Matches .access-btn, the other CTA on the page. */
  border-radius: 6px;
  transition: opacity 0.2s;
}

.btn:hover {
  opacity: 0.75;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

/* Investor line, under the CTAs. Scoped past `#hero p`, whose id selector
   sets the subtitle's size, colour and margin and would otherwise win. */
#hero .hero-backers {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem 1.05rem;
  margin: 2.25rem 0 0;
  font-size: 0.95rem;
  letter-spacing: 0.01em;
  color: var(--muted);
}

/* Both marks are flattened to black artwork so they take the same treatment
   as the trusted row: inverted in dark, left alone in light. */
.hero-backers img {
  display: block;
  width: auto;
  opacity: 0.7;
  filter: invert(1);
  transition: opacity 0.2s;
}

:root[data-theme="light"] .hero-backers img {
  filter: none;
}

/* Sized to match each other's letter height rather than their bounding
   boxes: EF's lockup stacks over three lines, so an equal box height would
   render its type at a third the size of Transpose's single line. */
.backer-ef {
  height: 36px;
}

.backer-transpose {
  height: 18px;
}

.hero-backers a:hover img,
.hero-backers a:focus-visible img {
  opacity: 1;
}

/* Secondary CTA. Carries the page background rather than being transparent,
   so it stays legible where the animated field runs behind it, and stays
   monochrome so the one accent colour on the page is still the red one. */
.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: calc(0.75rem - 1px) 1.5rem;
  background: var(--white);
  color: var(--black);
  border: 1px solid var(--border);
}

.btn-secondary svg {
  width: 17px;
  height: 17px;
  flex: none;
}

/* SECTIONS */

section:not(#hero) {
  border-bottom: 1px solid var(--border);
}

.section-inner {
  max-width: 1100px;
  margin: 0 auto;
  /* Scales rather than sitting flat, so the extra air on a wide screen
     does not eat half a phone viewport. */
  padding: clamp(3.5rem, 6.5vw, 5.5rem) 2rem;
}

.label {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gray);
  margin-bottom: 1.5rem;
}

.section-inner h2 {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: clamp(1.8rem, 3.5vw, 2.8rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.1;
  max-width: 600px;
  margin-bottom: 1.75rem;
}

.section-inner p {
  color: var(--gray);
  max-width: 540px;
  margin-bottom: 1rem;
}

.section-inner p:last-of-type {
  margin-bottom: 0;
}

/* No column gap: the rule lives on the heading's right edge, so any gutter
   between the columns would push it off centre by half that gutter. The
   space is taken as padding inside each column instead, which puts the rule
   exactly on the midline. */
.about-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  align-items: start;
}

.about-columns h2 {
  border-right: 1px solid var(--border);
  padding-right: 3rem;
  max-width: none;
  margin-bottom: 0;
}

.about-body {
  padding-left: 3rem;
}

.about-columns p {
  max-width: none;
  margin-bottom: 0;
}

/* The right-hand cell holds more than one paragraph now, and the rule above
   zeroes their margins, so the gap is put back between them. */
.about-body p + p {
  margin-top: 1.1rem;
}

/* ── WHERE WE SIT IN THE PIPELINE ───────────────────────────────────
   Four pixel glyphs in the ICP tiles' idiom. The last two are ours: guards
   go in at the build and do their work at runtime, which the bracket
   underneath ties together as one product across two stages. */

.pipe {
  margin-top: 3rem;
}

.pipe-steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  align-items: start;
  max-width: 58rem;
  margin: 0 auto;
}

.pipe-step {
  /* Pinned to the same row as the arrows. Left to auto-place they land in a
     second row and the arrows float above the glyphs. */
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.pipe-step:nth-of-type(1) { grid-column: 1; }
.pipe-step:nth-of-type(3) { grid-column: 2; }
.pipe-step:nth-of-type(5) { grid-column: 3; }
.pipe-step:nth-of-type(7) { grid-column: 4; }

/* Each arrow straddles the boundary between the two stages it joins. */
.pipe-gap {
  grid-row: 1;
  align-self: start;
  justify-self: center;
}

.pipe-gap:nth-of-type(2) { grid-column: 1 / 3; }
.pipe-gap:nth-of-type(4) { grid-column: 2 / 4; }
.pipe-gap:nth-of-type(6) { grid-column: 3 / 5; }

.pipe-pix {
  display: block;
  width: 38px;
  height: 38px;
  fill: var(--muted);
  margin-bottom: 1rem;
}

.pipe-name {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gray);
  line-height: 1.45;
  /* Two lines' worth, so a wrapped label keeps the row level. */
  min-height: 2.9em;
}

.pipe-sub {
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--prose);
  margin-top: 0.15rem;
}

/* Our two stages. */
.pipe-step.is-us .pipe-pix {
  fill: var(--accent-faint);
}

.pipe-step.is-us .pipe-name {
  color: var(--accent-faint);
}

/* Ties the build and runtime stages together as one product. */
.pipe-bracket {
  grid-column: 3 / 5;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 1.1rem;
}

.pipe-bracket i {
  display: block;
  width: 100%;
  height: 10px;
  border: 1px solid var(--accent-faint);
  border-bottom: none;
}

.pipe-bracket span {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg);
  margin-top: 0.6rem;
}

.pipe-dash {
  display: block;
  width: 52px;
  height: 42px;
  fill: var(--muted);
  opacity: 0.6;
}

@media (max-width: 700px) {
  .pipe-steps {
    max-width: none;
  }
  .pipe-pix {
    width: 28px;
    height: 28px;
  }
  .pipe-dash {
    width: 26px;
    height: 32px;
  }
  .pipe-name {
    font-size: 0.6rem;
  }
  .pipe-sub {
    font-size: 0.72rem;
  }
}

/* Two short inputs side by side, so a five-field form is three rows deep
   rather than five. */
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

@media (max-width: 560px) {
  .field-row {
    grid-template-columns: 1fr;
    gap: 0;
  }
}

/* PRESS

   Shares the 1100px column the features grid uses, so the profile tiles line
   up with the capability tiles below. Three across, hairline gaps over a
   border-coloured background for the dividers. */

/* ── WHERE THIS MATTERS ─────────────────────────────────────────────
   Left-aligned on the same 1100px grid as every other section, and using
   .section-inner directly so it inherits the 6rem rhythm rather than the
   5rem it had on its own. Statement left, evidence right, mirroring the
   About split. */

/* Statement full width, context beneath it, columns below. The lead used
   to be a two-column split with a rule down the gutter, which put a second
   set of vertical rules directly above the three-column grid at a different
   column count. One grid per section reads far cleaner. */

.press-statement {
  /* Positioning context for the hover note below it. */
  position: relative;
  font-family: "Merriweather", "Times New Roman", serif;
  /* Half the measure now that the quote sits beside it. */
  font-size: clamp(1.3rem, 1.9vw, 1.7rem);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--fg) !important;
  max-width: none !important;
  margin: 0 !important;
}

/* The context that used to sit under the statement now hangs off the
   phrase it qualifies. Dotted rather than solid, and in the accent, so it
   does not read as a link out of the page. */
.hint {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: var(--accent-faint);
  text-decoration-thickness: 1px;
  text-underline-offset: 7px;
  cursor: help;
}

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

/* Anchored to the statement, not to the phrase: the phrase wraps across two
   lines, so hanging the note off it dropped the panel into the middle of the
   sentence and covered the rest of it. Sits above and to the right. */
.hint-pop {
  position: absolute;
  bottom: 100%;
  left: 30%;
  z-index: 5;
  /* Wider than the column it sits in: it floats over the quote beside it
     rather than being squeezed into half the page. */
  width: min(32rem, 84vw);
  margin-bottom: 0.85rem;
  padding: 1.1rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  /* Body copy, not the display face the statement is set in. */
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-size: 0.92rem;
  font-weight: 400;
  line-height: 1.65;
  letter-spacing: normal;
  color: var(--prose);
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}

/* An invisible bridge across the gap, wide enough to cover the diagonal from
   the phrase up to the panel. Without it the panel closes as the pointer
   leaves the text, and the links inside are unreachable. */
.hint-pop::before {
  content: "";
  position: absolute;
  top: 100%;
  left: -45%;
  right: 0;
  height: 1.1rem;
}

/* On a phone the panel is as wide as the column, so the right offset would
   push it off screen. */
@media (max-width: 760px) {
  .hint-pop {
    left: 0;
    width: 100%;
  }
  .hint-pop::before {
    left: 0;
  }
}

/* focus-within keeps it open while the links inside it are tabbed to, and
   the popup being a descendant means hovering it holds the parent's hover. */
.hint:hover .hint-pop,
.hint:focus .hint-pop,
.hint:focus-within .hint-pop {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.press-alarm {
  color: var(--accent);
}

.press-cite {
  font-weight: 700;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: opacity 0.2s;
}

.press-cite:hover {
  opacity: 0.6;
}

/* Three parallel categories, so vertical rules rather than boxes. Every
   line is visible: the FFmpeg result is the strongest single number on
   the page and was previously hidden behind a hover. */
.press-columns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  margin-top: 4.5rem;
  border-top: 1px solid var(--border);
  padding-top: 2.5rem;
}

/* Face by default, body on hover or focus. The arrow is the affordance:
   the previous version of this had no signal that the tiles did anything,
   so the copy behind them was effectively invisible. Everything is shown
   unconditionally below 860px, where there is no hover to rely on. */
.icp {
  position: relative;
  display: grid;
  padding: 1.75rem;
  border-left: 1px solid var(--border);
  min-height: 13rem;
  cursor: default;
}

.icp:first-child {
  padding-left: 0;
  border-left: none;
}

.icp:last-child {
  padding-right: 0;
}

.icp-face,
.icp-body {
  grid-area: 1 / 1;
  align-self: start;
  transition: opacity 0.28s ease;
}

.icp-pix {
  display: block;
  width: 30px;
  height: 30px;
  fill: var(--muted);
  margin-bottom: 1.4rem;
  transition: fill 0.28s ease;
}

.icp h3 {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.3;
}

.icp-arrow {
  margin-left: 0.55rem;
  color: var(--muted);
  transition: transform 0.28s ease, color 0.28s ease;
  display: inline-block;
}

.icp-body {
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--gray);
  max-width: none !important;
  margin: 0 !important;
  opacity: 0;
}

/* Same citation treatment as the notes: no hue, weight plus an underline. */
.icp-body a {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  cursor: pointer;
  transition: opacity 0.2s;
}

.icp-body a:hover {
  opacity: 0.65;
}

.icp:hover .icp-face,
.icp:focus-within .icp-face {
  opacity: 0;
}

.icp:hover .icp-body,
.icp:focus-within .icp-body {
  opacity: 1;
}

.icp:hover .icp-arrow {
  transform: translateX(3px);
  color: var(--accent-faint);
}

.icp:focus-visible {
  outline: 1px solid var(--fg);
  outline-offset: 6px;
}

@media (max-width: 860px) {
  .press-columns {
    grid-template-columns: 1fr;
    gap: 2.25rem;
    margin-top: 3rem;
  }
  /* No hover on touch, so the two states stack and both stay visible. */
  .icp {
    display: block;
    padding: 0;
    border-left: none;
    min-height: 0;
  }
  .icp-face,
  .icp-body {
    grid-area: auto;
  }
  .icp-pix {
    margin-bottom: 1rem;
  }
  .icp-body {
    opacity: 1;
    margin-top: 0.85rem !important;
  }
  .icp-arrow {
    display: none;
  }
}

/* ── HOW IT DEPLOYS ─────────────────────────────────────────────────
   Figure left, properties right. The ring is a closed loop because the
   thing being described is a build that repeats, not a one-off install. */

#how,
#value,
#compare {
  border-bottom: 1px solid var(--border);
}

/* Figure across the full measure, the four properties beneath it. */
.how-grid {
  display: block;
}

.flow-grid {
  display: block;
  width: 100%;
  height: auto;
}

/* Scaled to the column, the diagram's labels fall to about 3px on a phone.
   Below this it keeps a legible width and swipes sideways instead, the same
   bargain the comparison table makes. */
@media (max-width: 900px) {
  .how-figure {
    overflow-x: auto;
  }
  .flow-grid {
    min-width: 860px;
  }
}

/* The grid is the ground the diagram is drawn on, so it stays well below
   the traces in weight. Every corner lands on an intersection. */
.grid-lines path {
  fill: none;
  stroke: var(--border);
  stroke-width: 1;
  opacity: 0.9;
}

.flow-cell {
  fill: var(--surface);
  stroke: var(--border);
  stroke-width: 1;
}

.trace {
  fill: none;
  stroke: var(--muted);
  stroke-width: 1.5;
  stroke-linecap: square;
  stroke-linejoin: miter;
}

.trace-dot,
.trace-tip {
  fill: var(--muted);
}

/* The scroll-driven line. Same green the hero field uses for a completed
   link, so a finished connection means the same thing in both places.
   Undrawn until flow-scroll.js measures it, so it cannot flash full-length
   on first paint. */
/* Annotation on the AI-Proof stage. Blue is the one colour the page has
   not spent: red is the accent, green means a completed connection in the
   circuit, so --navy stays free to mean "aside". */
.flow-mark {
  fill: none;
  stroke: var(--navy);
  stroke-width: 1.5;
  stroke-dasharray: 3 4;
}

.flow-mark-line {
  fill: none;
  stroke: var(--navy);
  stroke-width: 1.5;
  stroke-dasharray: 3 4;
}

.flow-note-box {
  fill: var(--bg);
  stroke: var(--navy);
  stroke-width: 1.5;
  stroke-dasharray: 3 4;
}

.flow-note-text {
  font-size: 15px;
  fill: var(--navy);
}

/* Divider between the build loop and the rollout pair below it. */
.flow-rule {
  fill: none;
  stroke: var(--border);
  stroke-width: 1;
}

/* Stage two is where the guarantee starts, so it takes the accent the rest
   of the page reserves for the product's own claims. */
.flow-cell-live {
  stroke: var(--accent-faint);
}

.flow-num-live {
  fill: var(--accent-faint);
}

/* Emphasis inside a gloss line lifts out of the muted grey. */
.flow-em {
  fill: var(--fg);
  font-weight: 600;
}

/* Block mode is the state where the guarantee starts, so it takes the
   accent wherever it is named. */
.flow-accent {
  fill: var(--accent-faint);
  font-weight: 600;
}

/* Hangs the mode choice off the connector it belongs to. */
.flow-tap {
  fill: none;
  stroke: var(--muted);
  stroke-width: 1;
  stroke-dasharray: 3 4;
}

/* Sized so the longer of the two labels keeps real padding inside a 160
   unit cell, which is what lets the pair sit clear of both neighbours. */
.flow-mode {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.12em;
  fill: var(--fg);
}

.trace-live {
  fill: none;
  stroke: var(--field-link);
  stroke-width: 2;
  stroke-linecap: square;
  stroke-linejoin: miter;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.flow-num {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.12em;
  fill: var(--muted);
}

.flow-name {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: 24px;
  font-weight: 700;
  fill: var(--fg);
}

.flow-gloss,
.flow-hub-sub {
  font-size: 17px;
  fill: var(--muted);
}

.flow-hub {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 14px;
  letter-spacing: 0.16em;
  fill: var(--muted);
}

/* Qualifier under the circuit. Same register as the note beneath the
   comparison table, so the page has one voice for caveats. */
/* Shared by the notes under the circuit and under the comparison table.
   Scoped past .section-inner p, which caps paragraphs at 540px and would
   otherwise outrank a bare class, so each runs the full width of the figure
   it belongs to. */
.section-inner .section-note {
  margin-top: 2.75rem;
  max-width: none;
  font-size: 0.95rem;
  line-height: 1.75;
  color: var(--gray);
}

/* Bold inside a note is emphasis, so it lifts out of the grey rather than
   just thickening within it. */
/* Links in a note take the note's own colour, marked by weight and an
   underline rather than a hue. Left unstyled these picked up the browser's
   default blue, which was the only stock colour anywhere on the page. */
.section-note a {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: opacity 0.2s;
}

.section-note a:hover {
  opacity: 0.65;
}

.section-note strong {
  font-weight: 600;
  color: var(--fg);
}

.note-tag {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg);
  margin-right: 0.85rem;
  padding-right: 0.85rem;
  border-right: 1px solid var(--border);
}

/* ── WHAT HOLDS EITHER WAY ──────────────────────────────────────────
   Three tiles in the same construction as the ICP tiles: pixel glyph,
   serif title, prose beneath. The body stays visible rather than waiting
   on hover, because these are the claims a reviewer is looking for. */

.assure-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  margin-top: 1.5rem;
}

.assure {
  background: var(--bg);
  padding: 1.75rem 1.6rem 1.9rem;
}

.assure-pix {
  display: block;
  width: 26px;
  height: 26px;
  fill: var(--muted);
  margin-bottom: 1.1rem;
}

.assure h3 {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 0.6rem;
  color: var(--fg);
}

.section-inner .assure p {
  margin: 0;
  max-width: none;
  font-size: 0.92rem;
  line-height: 1.65;
  color: var(--prose);
}

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

/* ── WHAT IT CHANGES ────────────────────────────────────────────────
   Two columns of prose rows. Wider gutters than the old four-up tiles,
   because these are arguments rather than labels. */

.value-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3rem 4rem;
  margin-top: 1rem;
}

.value-rows {
  display: grid;
  gap: 2.75rem;
}

/* ── DASHBOARD ──────────────────────────────────────────────────────
   Three panels on one row, divided by the same hairlines the rest of the
   page uses. Environment and applied-state are separate controls: only the
   patch-time bar depends on the environment, since the catalogue counts are
   a fact about the catalogue rather than about the reader. */

.dash-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin: 3.5rem 0 1.5rem;
}

.dash-seg {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
}

.dash-seg button {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.7rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.62rem 1rem;
  background: none;
  border: none;
  color: var(--gray);
  cursor: pointer;
  transition: background 0.18s, color 0.18s;
}

.dash-seg button:hover {
  color: var(--fg);
}

.dash-seg button.on {
  background: var(--surface);
  color: var(--fg);
}

.dash-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}

.dash-card {
  display: flex;
  flex-direction: column;
  background: var(--bg);
  padding: 1.7rem 1.6rem;
  min-height: 17rem;
}

.dash-cap {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.64rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1.5rem;
}

.dash-big {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: 2.9rem;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--fg);
  transition: color 0.5s ease;
}

.section-inner .dash-sub {
  margin: 0.7rem 0 0 !important;
  max-width: none !important;
  font-size: 0.86rem;
  line-height: 1.55;
  color: var(--gray);
}

/* Reserved height on everything that swaps, so toggling the state never
   moves the cards. Two lines for the notes, one for the verdict. */
.dash-foot {
  margin-top: auto;
  padding-top: 1.2rem;
  min-height: 3.55rem;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--muted);
}

/* panel 1 */
.dash-expo {
  display: flex;
  height: 26px;
  border-radius: 3px;
  overflow: hidden;
  margin: 1rem 0 0;
}

.dash-expo i {
  display: block;
  transition: background 0.6s ease;
}

.dash-expo .mem { background: var(--accent); }
.dash-expo .rest { background: rgba(255, 255, 255, 0.13); }
.is-after .dash-expo .mem { background: rgba(255, 255, 255, 0.06); }

.is-after #d-count {
  color: var(--muted);
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}

/* panel 2 */
.race-row { margin-bottom: 1.1rem; }

.race-lab {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.78rem;
  color: var(--gray);
  margin-bottom: 0.35rem;
}

.race-lab b {
  white-space: nowrap;
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.76rem;
  font-weight: 400;
  color: var(--fg);
}

.race-track {
  display: block;
  height: 12px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 2px;
  overflow: hidden;
}

.race-fill {
  display: block;
  height: 100%;
  transition: width 0.7s cubic-bezier(0.4, 0, 0.2, 1), background 0.5s ease;
}

.race-att .race-fill { background: var(--accent); }
.race-you .race-fill { background: rgba(255, 255, 255, 0.28); }
.is-after .race-att .race-fill { background: rgba(255, 255, 255, 0.1); }

.dash-verdict {
  min-height: 2.1rem;
  display: flex;
  align-items: center;
  font-size: 0.8rem;
  padding: 0.5rem 0.7rem;
  border-radius: 3px;
  background: rgba(224, 112, 95, 0.13);
  color: var(--accent);
  transition: background 0.5s ease, color 0.5s ease;
}

.is-after .dash-verdict {
  background: rgba(87, 185, 138, 0.13);
  color: var(--s1);
}

/* panel 3 */
.dash-tier {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}

.dash-tier i {
  white-space: nowrap;
  font-style: normal;
  font-size: 0.9rem;
  color: var(--gray);
}

.is-after #d-tierN { color: var(--s1); }

.dash-badge {
  display: inline-block;
  align-self: flex-start;
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.63rem;
  letter-spacing: 0.09em;
  padding: 0.3rem 0.55rem;
  border-radius: 3px;
  margin-top: 1rem;
  background: rgba(224, 112, 95, 0.16);
  color: var(--accent);
  transition: background 0.5s ease, color 0.5s ease;
}

.is-after .dash-badge {
  background: rgba(87, 185, 138, 0.16);
  color: var(--s1);
}

/* ── COMPARISON ─────────────────────────────────────────────────────── */

.compare-scroll {
  overflow-x: auto;
  /* The .sr labels in every cell are absolutely positioned. Without a
     containing block here they resolve against the page, escape this
     scroller, and stretch the document to the table's 780px, which on a
     phone lets the whole layout be zoomed out and pushed left. */
  position: relative;
}

.compare {
  width: 100%;
  min-width: 780px;
  border-collapse: collapse;
  font-size: 1.05rem;
}

.compare th,
.compare td {
  padding: 1.15rem 1rem;
  border-bottom: 1px solid var(--border);
  text-align: center;
}

.compare thead th {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gray);
  padding-bottom: 1.1rem;
  vertical-align: bottom;
}

.compare tbody th {
  text-align: left;
  font-weight: 400;
  color: var(--fg);
  padding-left: 0;
  min-width: 15.5rem;
}

.compare tbody:last-child tr:last-child th,
.compare tbody:last-child tr:last-child td {
  border-bottom: none;
}

/* The verdict is drawn from the rows above rather than adding a criterion,
   so it is ruled off from them and set in the page's own voice. */
.compare-verdict {
  border-top: 2px solid var(--border);
}

.verdict th,
.verdict td {
  padding-top: 1.5rem;
  padding-bottom: 1.5rem;
  background: var(--surface);
}

/* Our column is tinted for every other row, so inside the tinted verdict row
   it needs to go a step lighter to stay distinguishable. */
.verdict .col-us {
  background: var(--line);
}

.verdict th {
  font-weight: 600;
  color: var(--fg);
}

/* The row states a conclusion, so it carries the reason the conclusion holds
   rather than leaving it to the note below the table. */
.verdict-sub {
  display: block;
  max-width: 34rem;
  margin-top: 0.45rem;
  font-size: 0.85rem;
  font-weight: 400;
  line-height: 1.6;
  color: var(--gray);
}

.verdict .mark span[aria-hidden] {
  font-size: 1.45rem;
}

/* Our column is tinted rather than boxed, so the eye lands on it without
   the table gaining a second grid of lines. */
.col-us {
  background: var(--surface);
}

.compare thead .col-us {
  color: var(--fg);
}

.mark span[aria-hidden] {
  font-size: 1.25rem;
  line-height: 1;
}

.mark.yes {
  color: var(--s1);
}

.mark.no {
  color: var(--muted);
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 900px) {
  .value-grid {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
  .dash-grid {
    grid-template-columns: 1fr;
  }
  .dash-card {
    min-height: 0;
  }
  .value-grid {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
}


@media (max-width: 768px) {
  .hero-inner {
    padding-top: 6rem;
  }
  .hero-text {
    width: 100%;
  }
  /* Less room to spare on a phone, so the halo sits tighter still. */
  .hero-text::before {
    inset: -1.5rem -1.75rem;
    filter: blur(26px);
  }
  .about-columns {
    grid-template-columns: 1fr;
    gap: 1.5rem;
  }
  .about-columns h2 {
    border-right: none;
    border-bottom: 1px solid var(--border);
    padding-right: 0;
    padding-bottom: 1.5rem;
  }
}

/* TRUSTED MARQUEE */

#trusted {
  border-bottom: 1px solid var(--border);
  padding: 3.5rem 0;
}

.trusted-label {
  text-align: center;
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--black);
  margin-bottom: 2rem;
}

.marquee-outer {
  display: flex;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
}

.marquee-group {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  will-change: transform;
}

/* Logos are black silhouettes on transparency, so they invert with the
   theme instead of needing a second set of files. Constraining both height
   and width contains each mark in the same box, which keeps a wide wordmark
   like Millennium from dwarfing a square one like GIAC. */
.marquee-group img {
  max-height: 30px;
  max-width: 124px;
  width: auto;
  height: auto;
  margin: 0 1.9rem;
  opacity: 0.75;
  filter: invert(1);
  transition: opacity 0.2s;
}

:root[data-theme="light"] .marquee-group img {
  filter: none;
}

.marquee-group img:hover {
  opacity: 1;
}

/* ── WHERE THIS MATTERS: TEXT AND QUOTE ─────────────────────────────
   Two columns with no rule between them: the quote is a second voice
   beside the argument, not a separate section. */

.matters-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4rem;
  align-items: start;
}

@media (max-width: 900px) {
  .matters-split {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
}

.quote {
  margin: 0;
}

.quote blockquote {
  margin: 0;
}

/* Half the measure it had as its own section, so it reads as supporting
   testimony rather than competing with the statement on the left. */
.section-inner .quote p {
  max-width: none;
  margin: 0;
  font-size: clamp(1.02rem, 1.25vw, 1.18rem);
  line-height: 1.65;
  color: var(--fg);
}

.quote-by {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.1rem 0.7rem;
  margin-top: 1.6rem;
}

.quote-name {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: 1rem;
  font-weight: 700;
  color: var(--fg);
}

.quote-role {
  font-size: 0.9rem;
  color: var(--gray);
}

/* Its own line rather than a rule and a label crammed onto the end of the
   role. Full basis forces the wrap, so the marks read as a footer to the
   attribution rather than part of the job title. */
.quote-prev {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: 0.9rem;
}

.quote-prev-label {
  font-family: "SF Mono", "Fira Mono", Menlo, monospace;
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Same treatment as the trusted row and the investor marks. */
.quote-prev img {
  display: block;
  width: auto;
  opacity: 0.8;
  filter: invert(1);
}

/* Sized to match each other's letter height, not their boxes: Arctic Wolf
   is a two-line lockup, so an equal box height renders its type at half
   Rapid7's. The wolf is a real knockout in the source, so the silhouette
   keeps it. */
.logo-aw {
  height: 26px;
}

.logo-r7 {
  height: 11px;
}

:root[data-theme="light"] .quote-prev img {
  filter: none;
}

@media (max-width: 460px) {
  .quote-prev {
    padding-left: 0;
    border-left: none;
    width: 100%;
  }
}

/* RESEARCH */

/* Two across: six links stacked ran to 509px in a column twice as wide as
   an entry needs. Single-item lists stay full width, or their rule would
   stop halfway across the section. */
.paper-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 3rem;
  border-top: 1px solid var(--border);
}

.paper-list-solo {
  grid-template-columns: 1fr;
}

@media (max-width: 760px) {
  .paper-list {
    grid-template-columns: 1fr;
  }
}

.paper-entry {
  display: block;
  padding: 1rem 0;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: inherit;
  transition: opacity 0.2s;
}

.paper-entry:hover {
  opacity: 0.55;
}

.paper-title {
  display: block;
  font-size: 0.97rem;
  font-weight: 500;
  color: var(--black);
  margin-bottom: 0.3rem;
}

.paper-desc {
  display: block;
  font-size: 0.85rem;
  color: var(--gray);
}

.label-sub {
  margin-top: 3rem;
}

/* The first sub-label sits directly under the section label, so it does not
   need the full gap the later ones use to separate one list from the next. */
.label-sub.label-first {
  margin-top: 1.75rem;
}

.paper-tag {
  margin-left: 0.6rem;
  padding: 0.1rem 0.35rem;
  border: 1px solid var(--border);
  border-radius: 2px;
  font-size: 0.66rem;
  font-weight: 400;
  letter-spacing: 0.06em;
  vertical-align: 0.12em;
  color: var(--gray);
}

/* CONTACT / EARLY ACCESS FORM */

#contact .section-inner {
  padding: clamp(3.5rem, 6vw, 5.5rem) 2rem;
}

/* Intro left, form right. The form is 364px tall and was sitting under a
   39px heading in a 1100px column, so the height was all empty gutter. */
.access-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4rem;
  align-items: start;
  max-width: 1000px;
  margin: 0 auto;
}

@media (max-width: 860px) {
  .access-grid {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
}

#contact .access-title {
  font-family: "Merriweather", "Times New Roman", serif;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.1;
  max-width: none;
  margin: 0 0 0.5rem;
  text-align: left;
}

#contact p.access-sub {
  font-size: 0.95rem;
  color: var(--gray);
  max-width: none;
  margin: 0 0 1.5rem;
  text-align: left;
}

.access-form {
  max-width: none;
  margin: 0;
  text-align: left;
}

.field {
  margin-bottom: 1.1rem;
}

.field label {
  display: block;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--black);
  margin-bottom: 0.4rem;
}

.field input,
.field select {
  width: 100%;
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--black);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.6rem 0.75rem;
  transition: border-color 0.2s, background 0.2s;
}

.field select {
  appearance: none;
  /* Chevron drawn inline so the control needs no external asset. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 16' fill='none' stroke='%23888' stroke-width='1.5'%3E%3Cpath d='M2 6.5 5 3.5l3 3'/%3E%3Cpath d='M2 9.5l3 3 3-3'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  padding-right: 2rem;
}

.field input:focus,
.field select:focus {
  outline: none;
  border-color: var(--black);
  background: var(--white);
}

.access-btn {
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--white);
  background: var(--black);
  border: none;
  border-radius: 6px;
  padding: 0.6rem 1.25rem;
  cursor: pointer;
  transition: opacity 0.2s;
}

.access-btn:hover {
  opacity: 0.8;
}

.access-status {
  margin-top: 0.75rem;
  font-size: 0.8rem;
  color: var(--gray);
  min-height: 1.2em;
}

.access-status.is-error {
  color: var(--accent);
}

#contact p.access-alt {
  max-width: none;
  margin: 0;
  font-size: 0.9rem;
  color: var(--gray);
  text-align: left;
}

/* Point-of-collection privacy notice, under each form's submit button. */
.form-privacy {
  margin: 1rem 0 0;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--gray);
}

.form-privacy a {
  color: var(--gray);
  text-decoration: underline;
  transition: color 0.2s;
}

.form-privacy a:hover {
  color: var(--black);
}

.email-inline {
  font-weight: 400;
  color: var(--black);
  text-decoration: underline;
  transition: opacity 0.2s;
}

.email-inline:hover {
  opacity: 0.5;
}

/* FOOTER */

footer {
  overflow: hidden;
  padding: 2rem 2rem 0;
}

.footer-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  /* Four items rather than two: on a narrow screen the link group drops to
     its own line instead of crushing the copyright. */
  flex-wrap: wrap;
  gap: 1.5rem;
  max-width: 1100px;
  margin: 0 auto;
  font-size: 0.8rem;
  color: var(--gray);
  padding-bottom: 1.5rem;
  /* Sits above the wordmark, whose line box overflows up into this row. */
  position: relative;
  z-index: 1;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.footer-bar a {
  color: var(--gray);
  text-decoration: none;
  transition: color 0.2s;
}

.footer-bar a:hover {
  color: var(--black);
}

.footer-wordmark {
  font-family: "Merriweather", "Times New Roman", serif;
  /* Merriweather sets far wider than Times — "Cofibrant" ran to 103vw at the
     old 22vw. Measured ink is 4.674x the font size, so dividing the available
     width by 4.75 fits it snugly at any viewport, padding included, instead
     of overflowing on wide screens or narrow ones. */
  font-size: calc((100vw - 4rem) / 4.75);
  font-weight: 700;
  letter-spacing: -0.04em;
  white-space: nowrap;
  color: var(--black);
  text-align: center;
  /* The word sits whole, resting on the bottom of the page. "Cofibrant" has
     no descenders, so its lowest ink is the slight overshoot of the round
     letters — measured at 0.011em below the baseline in Merriweather. This
     line-height sizes the box to end exactly there: tight to the letterforms,
     nothing clipped. Re-derived from the font's own metrics; the old 0.707
     was Times' figure and leaves this face short.
     A negative margin can't be used instead — it would shrink the footer and
     leave the glyph bottoms outside the page, which is the bug we're fixing. */
  line-height: 0.731;
  /* Purely decorative: its line box is taller than the element and would
     otherwise intercept clicks on the footer links above it. */
  pointer-events: none;
  user-select: none;
}

/* Where supported, trim to the real font metrics instead of the estimate
   above: top to the ascent (so nothing clips), bottom to the baseline. */
@supports (text-box: trim-both text alphabetic) {
  .footer-wordmark {
    line-height: 1;
    text-box: trim-both text alphabetic;
    /* The trim cuts at the baseline, so the overshoot still needs its room. */
    padding-bottom: 0.012em;
  }
}

/* FORM TEXTAREAS — same treatment as .field input / .field select above. */

.field textarea {
  width: 100%;
  font-family: inherit;
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--black);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.6rem 0.75rem;
  resize: vertical;
  transition: border-color 0.2s, background 0.2s;
}

.field textarea:focus {
  outline: none;
  border-color: var(--black);
  background: var(--white);
}

/* SECURITY PAGE */

/* Term/definition rows, ruled like .bench-table so the page reads as part
   of the same set as the other sub-pages. */
.disclosure-list {
  margin: 1.5rem 0 1.75rem;
  border-top: 1px solid var(--black);
}

.disclosure-list > div {
  display: grid;
  grid-template-columns: 210px 1fr;
  gap: 1.5rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--border);
}

.disclosure-list > div:last-child {
  border-bottom: 1px solid var(--black);
}

/* A linked name keeps the row's weight and takes an underline rather than a
   colour, so a linked and an unlinked advisor still read as the same list. */
.disclosure-list dt a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: opacity 0.2s;
}

.disclosure-list dt a:hover {
  opacity: 0.65;
}

/* Deep links to a single row land below the fixed header. */
.disclosure-list > div[id] {
  scroll-margin-top: 6rem;
}

.disclosure-list dt {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--black);
}

.disclosure-list dd {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.65;
  color: var(--prose);
}

/* Deep links land below the fixed header rather than under it. */
.paper-body h2[id] {
  scroll-margin-top: 5rem;
}

/* The form is centred at 520px inside #contact; here it fills the column. */
.paper-body .access-form {
  max-width: none;
  margin-top: 1.75rem;
}

.paper-body .security-alt {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  font-size: 0.88rem;
  color: var(--gray);
}

@media (max-width: 640px) {
  .disclosure-list > div {
    grid-template-columns: 1fr;
    gap: 0.35rem;
  }
}

/* THEME SWITCH — injected into the header nav by theme.js. */

.theme-toggle {
  display: flex;
  align-items: center;
  /* The nav items are box-centred exactly, but Merriweather's glyphs sit a
     little low in their line box, so the icon needs a nudge to look level. */
  transform: translateY(1px);
  padding: 0;
  background: none;
  border: none;
  color: var(--gray);
  cursor: pointer;
  transition: color 0.2s;
}

.theme-toggle:hover {
  color: var(--black);
}
