/* ClaimSpy — claimspy.io
 *
 * Standalone static marketing site. No build step and no framework: this file
 * and index.html are the whole thing. It deploys as its own Netlify site so a
 * copy change never rebuilds the app, and so an anonymous visitor never
 * downloads React and a Supabase client to read a headline.
 *
 * The tokens below are copied from the app's tailwind.config.js on purpose.
 * claimspy.io and app.claimspy.io should look like one surface, so when a
 * colour changes there it must be changed here by hand — there is no shared
 * build to keep them honest.
 */

:root {
  --canvas:      #F7F8FA;
  --card:        #FFFFFF;
  --line:        #E9EBF0;
  --line-soft:   #F1F3F7;

  --ink:         #0E1116;
  --ink-2:       #3D4550;
  --ink-3:       #6B7480;
  --ink-4:       #9AA2AE;

  --brand:       #2E5BFF;
  --brand-hover: #2148E5;
  --brand-tint:  #EEF2FF;
  --brand-line:  #D6E0FF;

  --pos:         #0E9F6E;
  --pos-tint:    #E7F8F1;
  --warn:        #B45309;
  --warn-tint:   #FEF6E7;
  --neg:         #DC2B2B;
  --neg-tint:    #FDECEC;

  --shadow-card: 0 1px 2px rgba(14, 17, 22, .04), 0 1px 3px rgba(14, 17, 22, .03);
  --shadow-lift: 0 2px 4px rgba(14, 17, 22, .04), 0 8px 24px -12px rgba(14, 17, 22, .12);
  --shadow-deep: 0 4px 8px rgba(14, 17, 22, .03), 0 24px 56px -24px rgba(14, 17, 22, .22);

  --sans: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;

  --gutter: 24px;
  --wide: 1120px;
  --narrow: 760px;
}

/* The app is light-only by an explicit product decision. Saying so here stops
   a dark-mode browser from inverting form controls and scrollbars underneath
   a page that has no dark palette to fall back to. */
:root { color-scheme: light; }

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

html {
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  font-feature-settings: "cv11", "ss01";
  overflow-x: hidden;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

img, svg { display: block; max-width: 100%; }
h1, h2, h3, h4, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

::selection { background: var(--brand-tint); }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Visually hidden, still announced. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Numbers line up in every table and stat on this product, same as the app. */
.tnum { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); }

/* Slides down rather than parking at left:-9999px, which in a right-to-left
   locale would push the document's scroll width out sideways. */
.skip {
  position: absolute;
  left: 16px;
  top: 12px;
  z-index: 200;
  background: var(--ink);
  color: #fff;
  padding: 10px 16px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  transform: translateY(-250%);
  transition: transform .15s ease;
}
.skip:focus { transform: none; }

/* ── Layout ─────────────────────────────────────────────────────────────── */

.wrap {
  width: 100%;
  max-width: var(--wide);
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.wrap--narrow { max-width: var(--narrow); }

/* 104px was a lot of air to scroll through nine times. The page reads denser
   at 84 without any section running into its neighbour — the hairline rules
   are doing more of that work than the padding was. */
.section { padding: 84px 0; }
.section--tight { padding: 60px 0; }

@media (max-width: 720px) {
  .section { padding: 68px 0; }
  .section--tight { padding: 48px 0; }
}

.rule { height: 1px; background: var(--line); border: 0; margin: 0; }

/* ── Type ───────────────────────────────────────────────────────────────── */

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-4);
}

.eyebrow--brand { color: var(--brand); }

/* Numbered section markers. They give the page a spine to scroll down and
   make the argument feel sequential rather than like a bag of features. */
.eyebrow__num {
  color: var(--ink-4);
  opacity: .6;
  margin-right: 10px;
}

h1, h2, h3 { font-weight: 600; letter-spacing: -0.025em; line-height: 1.1; }

/* Headings set their own line breaks. Left to the normal greedy algorithm a
   heading fills each line to the margin and drops whatever is left over onto
   the last one, which is how "This is." and "watched." ended up alone. balance
   evens the lines out instead; pretty only guards the last line, which is what
   body copy needs. Both degrade to normal wrapping where unsupported. */
.h1, .h2, .h3, h1, h2, h3 { text-wrap: balance; }
.lede, .fine, .faq__answer p, .step__body p, .ev-point p,
.tier__blurb, .tier__note, .ev-note, .inbox__foot { text-wrap: pretty; }

.h1 {
  font-size: clamp(2.35rem, 6.2vw, 4.1rem);
  letter-spacing: -0.035em;
  line-height: 1.03;
  font-weight: 600;
}

.h2 {
  font-size: clamp(1.85rem, 3.6vw, 2.6rem);
  letter-spacing: -0.03em;
  line-height: 1.08;
}

.h3 { font-size: 1.0625rem; letter-spacing: -0.015em; line-height: 1.35; }

.lede {
  font-size: clamp(1.0625rem, 1.6vw, 1.1875rem);
  line-height: 1.6;
  color: var(--ink-3);
}

.fine { font-size: 13px; line-height: 1.6; color: var(--ink-4); }

.section-head { max-width: 660px; }
.section-head .h2 { margin-top: 14px; }
.section-head .lede { margin-top: 16px; }

.center { text-align: center; }
.center .section-head { margin-left: auto; margin-right: auto; }

/* ── Buttons ────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid transparent;
  border-radius: 10px;
  font-weight: 500;
  font-size: 14px;
  padding: 10px 16px;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease,
              color .15s ease, box-shadow .15s ease, transform .15s ease;
  white-space: nowrap;
}

.btn svg { flex: none; }

.btn--primary {
  background: var(--brand);
  color: #fff;
  box-shadow: 0 1px 2px rgba(46, 91, 255, .24), 0 4px 14px -6px rgba(46, 91, 255, .45);
}
.btn--primary:hover { background: var(--brand-hover); }

.btn--secondary {
  background: var(--card);
  color: var(--ink-2);
  border-color: var(--line);
  box-shadow: var(--shadow-card);
}
.btn--secondary:hover { color: var(--ink); border-color: #DCE0E8; }

.btn--ghost { background: transparent; color: var(--ink-3); }
.btn--ghost:hover { color: var(--ink); background: var(--line-soft); }

.btn--lg { font-size: 15px; padding: 13px 22px; border-radius: 11px; }
.btn--sm { font-size: 13px; padding: 7px 13px; border-radius: 9px; }
.btn--block { width: 100%; }

/* The arrow leans forward on hover. Small, but it makes the primary CTA feel
   like a door rather than a label. */
.btn__arrow { transition: transform .15s ease; }
.btn:hover .btn__arrow { transform: translateX(2px); }

/* ── Header ─────────────────────────────────────────────────────────────── */

.header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(247, 248, 250, .78);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease, background-color .2s ease;
}
.header[data-scrolled='true'] {
  border-bottom-color: var(--line);
  background: rgba(247, 248, 250, .9);
}

.header__inner {
  display: flex;
  align-items: center;
  gap: 32px;
  height: 60px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-weight: 600;
  font-size: 15.5px;
  letter-spacing: -0.02em;
  flex: none;
}

.brand__mark { width: 26px; height: 26px; border-radius: 7px; flex: none; }

.nav {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-right: auto;
}

.nav a {
  font-size: 14px;
  color: var(--ink-3);
  padding: 7px 11px;
  border-radius: 8px;
  transition: color .15s ease, background-color .15s ease;
}
.nav a:hover { color: var(--ink); background: var(--line-soft); }

.header__cta { display: flex; align-items: center; gap: 8px; flex: none; }

.nav-toggle { display: none; }

@media (max-width: 860px) {
  .nav, .header__cta .btn--ghost { display: none; }
  .header__inner { gap: 12px; justify-content: space-between; }
  .header__cta { margin-left: auto; }
  .nav-toggle {
    display: inline-grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border: 1px solid var(--line);
    background: var(--card);
    border-radius: 9px;
    cursor: pointer;
  }
  /* Open state swaps the header into a stacked sheet rather than overlaying
     the page — fewer moving parts, and it cannot trap scroll. */
  .header[data-open='true'] .nav {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    width: 100%;
    order: 3;
    padding: 6px 0 16px;
    border-top: 1px solid var(--line);
    margin-top: 4px;
  }
  .header[data-open='true'] .header__inner { flex-wrap: wrap; height: auto; padding-top: 10px; }
  .header[data-open='true'] .nav a { padding: 11px 12px; font-size: 15px; }
}

/* ── Hero ───────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  padding: 84px 0 0;
  overflow: hidden;
}

/* A single soft brand wash behind the headline. On a light page a gradient
   this quiet is the difference between "clean" and "unfinished" — it gives the
   type something to sit on without becoming decoration. */
.hero::before {
  content: '';
  position: absolute;
  inset: -220px 0 auto;
  height: 720px;
  background:
    radial-gradient(58% 52% at 50% 34%, rgba(46, 91, 255, .10), transparent 68%),
    radial-gradient(38% 40% at 82% 12%, rgba(14, 159, 110, .05), transparent 70%);
  pointer-events: none;
}

/* Faint graph paper, masked so it fades out before it reaches the content. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 560px;
  background-image:
    linear-gradient(to right, rgba(14, 17, 22, .045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(14, 17, 22, .045) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: radial-gradient(64% 62% at 50% 26%, #000 0%, transparent 76%);
  mask-image: radial-gradient(64% 62% at 50% 26%, #000 0%, transparent 76%);
  pointer-events: none;
}

.hero__inner { position: relative; z-index: 1; text-align: center; }

.hero .h1 { margin-top: 22px; max-width: 21ch; margin-inline: auto; }
.hero .h1 em {
  font-style: normal;
  /* The one coloured phrase on the page. It carries the whole promise, so it
     gets the accent and nothing else does. */
  color: var(--brand);
}

.hero__lede { margin: 22px auto 0; max-width: 60ch; }

.hero__actions {
  margin-top: 30px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

.hero__note {
  margin-top: 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  justify-content: center;
  font-size: 13px;
  color: var(--ink-4);
}
.hero__note span { display: inline-flex; align-items: center; gap: 6px; }
.hero__note svg { color: var(--pos); flex: none; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px 5px 8px;
  border-radius: 999px;
  background: var(--card);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
  font-size: 12.5px;
  color: var(--ink-2);
}
.pill b { font-weight: 600; color: var(--ink); }
.pill__dot {
  width: 6px; height: 6px; border-radius: 999px;
  background: var(--pos);
  box-shadow: 0 0 0 3px var(--pos-tint);
  margin-left: 4px;
}

/* ── Product frame (the app, rebuilt in HTML) ───────────────────────────── */

/* These are not screenshots. They are the app's own markup rewritten in plain
   CSS so they stay sharp at any zoom, stay readable to a screen reader, and
   never go stale against a redesign the way a PNG does. */

.frame {
  position: relative;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-deep);
  overflow: hidden;
}

.frame__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  height: 40px;
  background: var(--line-soft);
  border-bottom: 1px solid var(--line);
}

.frame__dots { display: flex; gap: 6px; flex: none; }
.frame__dots i {
  width: 9px; height: 9px; border-radius: 999px;
  background: #DDE1E8; display: block;
}

.frame__url {
  flex: 1;
  min-width: 0;
  text-align: center;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-4);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 4px 10px;
  max-width: 320px;
  margin: 0 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.frame__foot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 18px;
  border-top: 1px solid var(--line);
  background: var(--line-soft);
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-4);
}
.frame__foot-sep {
  width: 3px;
  height: 3px;
  border-radius: 999px;
  background: currentColor;
  opacity: .45;
}

.hero__frame {
  margin-top: 56px;
  position: relative;
  z-index: 1;
}

/* A gentle tilt on wide screens. It reads as a product shot rather than an
   embedded iframe, and it flattens out entirely on small screens where the
   perspective would just cost legibility. */
@media (min-width: 1000px) {
  .hero__frame .frame {
    transform: perspective(2400px) rotateX(2.4deg);
    transform-origin: 50% 0;
  }
}

/* ── Claim rows ─────────────────────────────────────────────────────────── */

.panel__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}

.panel__title { font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; }
.panel__count { font-size: 12px; color: var(--ink-4); font-family: var(--mono); }
.panel__spacer { margin-left: auto; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 500;
  padding: 3px 8px;
  border-radius: 6px;
  background: var(--line-soft);
  color: var(--ink-3);
}
.chip--on { background: var(--brand-tint); color: var(--brand); }

.claims { display: block; }

.claim {
  display: flex;
  gap: 14px;
  padding: 15px 18px;
  border-bottom: 1px solid var(--line-soft);
  transition: background-color .15s ease;
}
.claim:last-child { border-bottom: 0; }
.claim:hover { background: rgba(241, 243, 247, .5); }

/* Score in a left gutter, exactly as the app does it: a list sorted by
   relevance is unreadable if the score is one small chip among small chips.
   In the gutter the eye gets a rail to run down. */
.claim__gutter {
  width: 42px;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding-top: 1px;
}

.score {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.score--3 { background: var(--warn-tint); color: var(--warn); }
.score--2 { background: var(--brand-tint); color: var(--brand); }
.score--1 { background: var(--line); color: var(--ink-2); }
.score--0 { background: var(--line); color: var(--ink-4); }

.pips { display: flex; gap: 2px; }
.pips i {
  display: block;
  width: 6px;
  height: 3px;
  border-radius: 2px;
  background: currentColor;
  opacity: .2;
}
.pips i.on { opacity: .6; }
.pips--3 { color: var(--warn); }
.pips--2 { color: var(--brand); }
.pips--1, .pips--0 { color: var(--ink-4); }

.claim__main { min-width: 0; flex: 1; }

.claim__text {
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.claim__ctx {
  margin-top: 4px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-3);
}

.claim__meta {
  margin-top: 9px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px 9px;
  font-size: 11px;
}

.claim__src {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-4);
  white-space: nowrap;
}

/* Claim-type badges. Quiet and evenly weighted — the taxonomy is a category,
   and nothing here should out-shout the claim itself. Values mirror
   src/lib/taxonomy.js. */
.badge {
  display: inline-flex;
  align-items: center;
  border-radius: 5px;
  padding: 2px 7px;
  font-size: 10.5px;
  font-weight: 500;
  white-space: nowrap;
}
.badge--metric      { background: #EFF6FF; color: #1D4ED8; }
.badge--proof       { background: #F5F3FF; color: #6D28D9; }
.badge--testimonial { background: #FDF4FF; color: #A21CAF; }
.badge--position    { background: #FFFBEB; color: #B45309; }
.badge--comparison  { background: #FFF1F2; color: #BE123C; }
.badge--capability  { background: #F1F5F9; color: #475569; }
.badge--pricing     { background: #ECFDF5; color: #047857; }
.badge--guarantee   { background: #F0FDFA; color: #0F766E; }
.badge--legal       { background: #F5F5F4; color: #57534E; }
.badge--case        { background: #FFF7ED; color: #C2410C; }
.badge--aggregate   { background: #F0F9FF; color: #0369A1; }

.metric-chip {
  font-family: var(--mono);
  font-size: 10.5px;
  background: var(--line-soft);
  color: var(--ink-3);
  padding: 2px 6px;
  border-radius: 5px;
  white-space: nowrap;
}

/* ── Cards & grids ──────────────────────────────────────────────────────── */

.grid { display: grid; gap: 18px; }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

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

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 13px;
  box-shadow: var(--shadow-card);
}

/* ── Steps ──────────────────────────────────────────────────────────────── */

.steps { counter-reset: step; display: grid; gap: 0; }

.step {
  display: grid;
  /* A definite width, not minmax(). Each .step is its own grid, so a track
     sized to its own content made all three asides different widths — the
     alert card is simply wider than the URL bar. clamp() resolves to one
     length every row shares, and still gives way on a narrow screen. */
  grid-template-columns: 34px minmax(0, 1fr) clamp(300px, 42%, 460px);
  gap: 18px 28px;
  padding: 24px 0;
  border-bottom: 1px solid var(--line);
  align-items: center;
}
/* The three asides are different heights by nature — a one-line URL bar, a
   progress banner, a full alert card — so the rows they sat in came out three
   different heights and the rhythm between the dividers wobbled. A floor on
   the row height fixes the rhythm; the cards stay their natural size and sit
   centred in it. */
@media (min-width: 861px) {
  .step { min-height: 178px; }
}

@media (max-width: 860px) {
  .step { grid-template-columns: 34px minmax(0, 1fr); align-items: start; }
}
.step:last-child { border-bottom: 0; }

.step__num {
  counter-increment: step;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--brand);
  background: var(--brand-tint);
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: grid;
  place-items: center;
}
.step__num::before { content: '0' counter(step); }

.step__body p { margin-top: 6px; font-size: 14px; line-height: 1.6; color: var(--ink-3); }

.step__aside { min-width: 0; }
@media (max-width: 860px) { .step__aside { margin-top: 16px; grid-column: 2; } }

/* Terminal-ish input mock for step 01. */
.urlbar {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 12px;
  box-shadow: var(--shadow-card);
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink-2);
}
.urlbar__proto { color: var(--ink-4); }
.urlbar__caret {
  width: 1.5px;
  height: 16px;
  background: var(--brand);
  margin-left: -4px;
  animation: blink 1.1s steps(2, start) infinite;
}
@keyframes blink { to { visibility: hidden; } }
.urlbar .btn { margin-left: auto; font-family: var(--sans); }

/* Crawl progress, mirroring the app's CrawlProgress banner. */
.crawl {
  display: flex;
  flex-direction: column;
  gap: 9px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 13px 14px;
  box-shadow: var(--shadow-card);
}
.crawl__row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
}
.crawl__row .mono { margin-left: auto; color: var(--ink-4); font-size: 11.5px; }
.crawl__dot {
  width: 7px; height: 7px; border-radius: 999px; background: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-tint);
  flex: none;
}
.crawl__track {
  height: 4px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.crawl__fill {
  height: 100%;
  width: 68%;
  border-radius: 999px;
  background: var(--brand);
}

/* ── Fine print mapping ─────────────────────────────────────────────────── */

/* The claim as published: the headline in the type it was set in, and the
   footnote it depends on directly underneath. */
.fineprint__headline {
  margin-bottom: 13px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
}
.fineprint__headline sup { color: var(--brand); font-size: 12px; }

.fineprint__note {
  background: var(--warn-tint);
  border: 1px solid rgba(180, 83, 9, .14);
  border-radius: 9px;
  padding: 11px 13px;
  font-size: 12.5px;
  line-height: 1.55;
  color: #7C3D06;
}
.fineprint__note sup { font-weight: 600; }

/* Pinned to the bottom of the card so it lines up with the summary line on the
   fields card beside it, whichever of the two runs longer. */
/* ── Change feed ────────────────────────────────────────────────────────── */

.event {
  padding: 15px 18px;
  border-bottom: 1px solid var(--line-soft);
}
.event:last-child { border-bottom: 0; }

.event__head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 11.5px;
}
.event__host { font-weight: 600; color: var(--ink); }
.event__kind { font-weight: 500; }
.event__kind--changed { color: var(--warn); }
.event__kind--added   { color: var(--pos); }
.event__kind--removed { color: var(--ink-3); }
.event__when { margin-left: auto; font-family: var(--mono); color: var(--ink-4); }

/* A value change is the product's headline output, so it is the only event
   drawn as a before → after pair. */
.diff {
  margin-top: 9px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.diff__from {
  font-family: var(--mono);
  font-size: 13px;
  background: var(--line-soft);
  color: var(--ink-4);
  text-decoration: line-through;
  padding: 2px 8px;
  border-radius: 6px;
  font-variant-numeric: tabular-nums;
}
.diff__to {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  background: var(--warn-tint);
  color: var(--warn);
  padding: 2px 8px;
  border-radius: 6px;
  font-variant-numeric: tabular-nums;
}
.diff svg { color: var(--warn); flex: none; }

.event__text {
  margin-top: 9px;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
}
.event__meta {
  margin-top: 9px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 9px;
}



/* ── Beat stages ────────────────────────────────────────────────────────── */

/* Each beat closes with one drawing rather than a two-column table. The rule
   they all follow: the CSS at rest is the finished state, and .is-in — added
   by the scroll observer — is what rewinds it and plays it forward. So with
   JavaScript off, or under prefers-reduced-motion, the reader sees the answer
   and never the setup. */

.stage {
  border-top: 1px solid var(--line);
  padding: 20px;
  background: var(--line-soft);
}

.stage__cap {
  margin-top: 15px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-3);
  text-wrap: pretty;
}
.stage__cap b { color: var(--ink); font-weight: 600; }

/* Beat 01 — reach, told in two acts on one 10s loop.
   Act one: black spreads from home to two first-ring pages and stops. That is
   a chat agent, and it is the honest version — it does follow a couple of
   links, it just runs out.
   Act two: blue floods outward past it, ring by ring, and recolours the black
   pages on the way through, because we read those too.
   Every ring is its own keyframe set rather than one set on a delay: a delay
   would shift act one along with act two and the two would stop lining up. */
.webgrid {
  display: grid;
  grid-template-columns: minmax(0, 480px) minmax(0, 1fr);
  gap: 26px;
  align-items: center;
}
@media (max-width: 980px) {
  .webgrid { grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 20px; }
}

.webcol { min-width: 0; width: 100%; }
/* The web is an ellipse rather than a circle: the labels are horizontal, so
   height was the axis costing the most and buying the least. */
.web { width: 100%; max-width: 480px; height: auto; margin-inline: auto; overflow: visible; }

/* Depth reads as weight: first ring solid brand, second ring lighter and a
   size smaller, third ring dimmer still. Without it the three rings were the
   same blue and the picture said "lots of pages" rather than "four levels". */
.web__ring { fill: none; stroke: #CFD6E4; stroke-width: 1; stroke-dasharray: 3 5; }
.web__thread { stroke: #6F8DFF; stroke-width: 1.2; }
.w2.web__thread { stroke: #93A9FF; }
.w3.web__thread { stroke: #B0C0F5; stroke-width: 1; }
.web__node { fill: #9FB5FF; }

.chip rect { fill: var(--brand); stroke: var(--brand); stroke-width: 1; }
.chip text {
  font-family: var(--mono);
  font-size: 10px;
  fill: #fff;
  text-anchor: middle;
}
.w2.chip rect { fill: #8CA5FF; stroke: #8CA5FF; }
.w2.chip text { font-size: 8.6px; }
.chip--home rect { fill: var(--ink); stroke: var(--ink); }
.chip--home text { font-weight: 500; }
/* The two pages a chat agent does reach settle black and stay black — that is
   the whole point of the second colour, so it has to survive at rest. */
.agent.web__thread { stroke: var(--ink); }
.agent.chip--page rect { fill: var(--ink); stroke: var(--ink); }

/* Black and blue run together, not one after the other: from the same moment,
   black reaches two pages off home and stops, while blue keeps going ring by
   ring — including out of the two black pages, which is exactly the argument.

   Each element snaps in over ~0.2s and the stagger between them is far wider
   than that, which is what makes the order legible. The previous version faded
   over 1.2s with 0.95s of stagger between the first and last, so every
   transition overlapped every other one and the ring appeared to arrive whole.
   The stagger index is a seeded shuffle of the ring, so it scatters. */
.is-in .w1.web__thread { animation: r1-line 10s ease-in-out infinite; }
.is-in .w2.web__thread { animation: r2-line 10s ease-in-out infinite; }
.is-in .w3.web__thread { animation: r3-line 10s ease-in-out infinite; }
.is-in .w3.web__node   { animation: r3-node 10s ease-in-out infinite; }
.is-in .w1.chip--page rect { animation: r1-chip 10s ease-in-out infinite; }
.is-in .w1.chip--page text { animation: chip-text-1 10s ease-in-out infinite; }
.is-in .w2.chip--page rect { animation: r2-chip 10s ease-in-out infinite; }
.is-in .w2.chip--page text { animation: chip-text-2 10s ease-in-out infinite; }

.is-in .agent.web__thread     { animation: agent-line 10s ease-in-out infinite; }
.is-in .agent.chip--page rect { animation: agent-chip 10s ease-in-out infinite; }
.is-in .agent.chip--page text { animation: chip-text-1 10s ease-in-out infinite; }

/* backwards fill holds the grey 0% frame through the delay; nothing fills
   afterwards, so a reduced-motion reader lands on the base rules above. */
.is-in .web__thread, .is-in .web__node, .is-in .chip--page rect, .is-in .chip--page text {
  animation-fill-mode: backwards;
}
.is-in .w1.web__thread, .is-in .w1.chip--page rect, .is-in .w1.chip--page text,
.is-in .agent.web__thread, .is-in .agent.chip--page rect, .is-in .agent.chip--page text {
  animation-delay: calc(var(--k) * .13s);
}
.is-in .w2.web__thread, .is-in .w2.chip--page rect, .is-in .w2.chip--page text {
  animation-delay: calc(var(--k) * .12s);
}
.is-in .w3.web__thread, .is-in .w3.web__node {
  animation-delay: calc(var(--k) * .16s);
}

@keyframes r1-line { 0%, 4%  { stroke: #DDE2EA; } 6%, 86% { stroke: #6F8DFF; } 93%, 100% { stroke: #DDE2EA; } }
@keyframes r2-line { 0%, 13% { stroke: #DDE2EA; } 15%, 86% { stroke: #93A9FF; } 93%, 100% { stroke: #DDE2EA; } }
@keyframes r3-line { 0%, 23% { stroke: #E2E6ED; } 25%, 86% { stroke: #B0C0F5; } 93%, 100% { stroke: #E2E6ED; } }
@keyframes r3-node { 0%, 23% { fill: #DDE2EA; }   25%, 86% { fill: #9FB5FF; }   93%, 100% { fill: #DDE2EA; } }

/* Same window as ring one: the agent sets off when we do, and stops here. */
@keyframes agent-line {
  0%, 4%    { stroke: #DDE2EA; }
  6%, 86%   { stroke: var(--ink); }
  93%, 100% { stroke: #DDE2EA; }
}
@keyframes agent-chip {
  0%, 4%    { fill: #EDEFF4; stroke: #D4D9E3; }
  6%, 86%   { fill: var(--ink); stroke: var(--ink); }
  93%, 100% { fill: #EDEFF4; stroke: #D4D9E3; }
}
@keyframes r1-chip {
  0%, 4%    { fill: #EDEFF4; stroke: #D4D9E3; }
  6%, 86%   { fill: var(--brand); stroke: var(--brand); }
  93%, 100% { fill: #EDEFF4; stroke: #D4D9E3; }
}
@keyframes r2-chip {
  0%, 13%   { fill: #EFF1F5; stroke: #DBDFE7; }
  15%, 86%  { fill: #8CA5FF; stroke: #8CA5FF; }
  93%, 100% { fill: #EFF1F5; stroke: #DBDFE7; }
}
/* Text flips to white the moment its pill fills, whichever colour it fills. */
@keyframes chip-text-1 { 0%, 4%  { fill: var(--ink-4); } 6%, 86%  { fill: #fff; } 93%, 100% { fill: var(--ink-4); } }
@keyframes chip-text-2 { 0%, 13% { fill: var(--ink-4); } 15%, 86% { fill: #fff; } 93%, 100% { fill: var(--ink-4); } }

.weblegend {
  display: grid;
  gap: 7px;
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-3);
}
.webkey { display: flex; align-items: flex-start; gap: 9px; }
.webkey i { flex: none; width: 10px; height: 10px; border-radius: 3px; margin-top: 3px; }
.webkey b { color: var(--ink); font-weight: 600; }
.k-one { background: var(--ink); }
.k-all { background: #7F9BFF; }

.depths { display: grid; gap: 2px; }

/* Counted figures must not reflow their line while they climb. */
.tally { font-variant-numeric: tabular-nums; }

.depth {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: baseline;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-size: 12.5px;
  color: var(--ink-3);
}
.depth:last-child { border-bottom: 0; }
.depth__k {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.depth__t { min-width: 0; color: var(--ink-3); }
.depth__n {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.depth--sum {
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  color: var(--ink-2);
}
.depth--sum .depth__n { font-size: 17px; font-weight: 600; color: var(--brand); }

/* Each depth row lands as the flood reaches that ring. */
.is-in .depth {
  animation: depth-in 10s ease-in-out infinite;
  animation-fill-mode: backwards;
  animation-delay: calc(.15s + var(--i) * .45s);
}
@keyframes depth-in {
  0%, 3%    { opacity: 0; transform: translateY(5px); }
  9%, 88%   { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: translateY(5px); }
}

/* Browser chrome, shared by both windows in beat 02 and the page in beat 03.
   The 32px height is load-bearing: beat 03's cursor coordinates are measured
   from the top of that mock, so changing it moves every click off its target. */
.mock__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  height: 32px;
  background: var(--line-soft);
  border-bottom: 1px solid var(--line);
}
.mock__dots { display: flex; gap: 5px; flex: none; }
.mock__dots i { display: block; width: 7px; height: 7px; border-radius: 999px; background: #DDE1E8; }
.mock__url { font-family: var(--mono); font-size: 10.5px; color: var(--ink-4); }

/* Beat 02 — the same URL, side by side, because "it gets raw HTML" means
   nothing to a reader who has never run curl. What a plain fetch actually
   returns is a bot check or an unstyled page with no words on it, so that is
   what the left window shows — alternating between the two, since both happen.
   The right window assembles itself, which is the difference arriving. */
.fetchgrid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px;
}
@media (max-width: 760px) { .fetchgrid { grid-template-columns: minmax(0, 1fr); } }

.fetch { min-width: 0; }
.fetch__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 9px;
}
.fetch__label--us { color: var(--brand); }

.fetch__win {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}
.fetch__body { position: relative; height: 208px; }

.fetch__stat {
  margin-top: 11px;
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-3);
}
.fetch__stat b {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}
.fetch__stat--us { color: var(--ink-2); }
.fetch__stat--us b { color: var(--brand); }

/* The two failure states stack; only one is ever visible. The bot check is the
   resting state, so a reader with animations off still sees a real outcome. */
.state { position: absolute; inset: 0; padding: 20px 18px; }
.state--a { opacity: 1; display: grid; align-content: center; justify-items: center; gap: 12px; }
.state--b { opacity: 0; }

.is-in .state--a { animation: swap-a 11s ease-in-out infinite; }
.is-in .state--b { animation: swap-b 11s ease-in-out infinite; }
@keyframes swap-a { 0%, 40% { opacity: 1; } 46%, 94% { opacity: 0; } 100% { opacity: 1; } }
@keyframes swap-b { 0%, 40% { opacity: 0; } 46%, 94% { opacity: 1; } 100% { opacity: 0; } }

.cap {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  max-width: 250px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--line-soft);
  font-size: 12.5px;
  color: var(--ink-2);
}
.cap__box {
  flex: none;
  width: 17px;
  height: 17px;
  border: 1.6px solid #B9C0CC;
  border-radius: 3px;
  background: var(--card);
}
.is-in .cap__box { animation: cap-blink 11s ease-in-out infinite; }
@keyframes cap-blink {
  0%, 10%, 22%, 40% { border-color: #B9C0CC; }
  15%, 30%          { border-color: var(--brand); }
}
.cap__txt { flex: 1; }
.cap__mark {
  flex: none;
  width: 15px;
  height: 15px;
  border-radius: 3px;
  background: repeating-linear-gradient(45deg, #C9D0DC 0 3px, #E3E7EE 3px 6px);
}
.cap__note {
  max-width: 260px;
  text-align: center;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-4);
}

/* An unstyled document, drawn as one: browser-default serif, blue underlined
   links, a picture that never loaded. */
.state--b { font-family: Times, 'Times New Roman', serif; }
.bare__img {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 1px dashed #C4CAD6;
  border-radius: 2px;
  color: #AAB2C0;
  margin-bottom: 12px;
}
.bare__h { font-size: 21px; font-weight: 700; color: #111; }
.bare__p { margin-top: 9px; font-size: 14px; color: #111; }
.bare__links { margin-top: 13px; font-size: 13px; color: #111; }
.bare__links a { color: #0000EE; text-decoration: underline; }

/* The rendered page, assembling. */
.real { height: 208px; overflow: hidden; }
.real__nav {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--line-soft);
}
.real__logo { font-size: 10px; font-weight: 700; letter-spacing: -0.01em; color: var(--brand); }
.real__nav i { font-style: normal; font-size: 9.5px; color: var(--ink-4); }
.real__nav i:first-of-type { margin-left: 5px; }
.real__cta {
  margin-left: auto;
  padding: 3px 7px;
  border-radius: 5px;
  background: var(--brand-tint);
  color: var(--brand);
  font-size: 9.5px;
  font-weight: 500;
}

.real__h {
  padding: 13px 14px 0;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--ink);
}

.real__hero {
  margin: 11px 14px 0;
  height: 62px;
  border-radius: 8px;
  background: linear-gradient(120deg, #E8EDFF, #F3F0FF 55%, #FFF3E6);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
}
.real__badge {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  background: var(--card);
  color: var(--warn);
  font-size: 11px;
  font-weight: 700;
  box-shadow: var(--shadow-card);
}
.real__herotxt { flex: 1; min-width: 0; display: grid; gap: 3px; }
.real__herotxt b { font-size: 12px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.real__herotxt span { font-size: 11px; color: var(--ink-3); }

.real__claim {
  margin: 9px 14px 0;
  padding-left: 9px;
  border-left: 2px solid var(--brand-line);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--ink-2);
}

.is-in .real__nav, .is-in .real__h, .is-in .real__hero, .is-in .real__claim {
  animation: build 11s ease-in-out infinite;
  animation-delay: calc(var(--r) * .28s);
  animation-fill-mode: backwards;
}
@keyframes build {
  0%, 4%    { opacity: 0; transform: translateY(7px); }
  12%, 94%  { opacity: 1; transform: none; }
  99%, 100% { opacity: 0; transform: translateY(7px); }
}

/* Beat 03 — one page, one cursor. It works the slider first, then opens every
   drawer beneath it. The drawer panels are a fixed height on purpose: the
   cursor has to land on rows that move as the ones above them open, and that
   only stays honest if the offsets are known. */
.mockpage {
  position: relative;
  /* Pinned, and this is load-bearing. The drawer panels animate `height`, so
     without a fixed height here the document grew and shrank by up to 180px
     three times a loop — which, if you were reading further down the page,
     read as the whole thing vibrating. contain keeps the cursor's left/top
     animation from forcing layout outside this card too. */
  height: 486px;
  contain: layout paint;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 11px;
  overflow: hidden;
}

.carousel { border-bottom: 1px solid var(--line); }
.carousel__win { overflow: hidden; height: 110px; }
.carousel__track {
  display: flex;
  align-items: stretch;
  flex: none;
  width: 300%;
  height: 100%;
  transform: translateX(-66.6667%);
}
.carousel__slide {
  width: 33.3333%;
  flex: none;
  margin: 0;
  padding: 0 18px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.carousel__badge {
  flex: none;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 10px;
  background: var(--warn-tint);
  color: var(--warn);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.02em;
}
.carousel__slide figcaption {
  font-size: 13px;
  font-weight: 500;
  line-height: 1.45;
  color: var(--ink);
}

.carousel__foot {
  height: 38px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 13px;
  border-top: 1px solid var(--line-soft);
  background: var(--line-soft);
}
.carousel__dots { position: relative; display: flex; gap: 6px; }
.carousel__dots i { display: block; width: 6px; height: 6px; border-radius: 999px; background: #D7DBE3; }
.carousel__thumb {
  position: absolute;
  top: 0;
  left: 0;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--brand);
  transform: translateX(24px);
}
.carousel__next {
  margin-left: auto;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink-2);
}

/* Fixed, and holding more rows than fit. As the three panels open they push
   the rows below out of the clip, so the card is exactly as full whether the
   drawers are shut or open — no dead space at either end of the loop, and no
   height change escaping into the document. */
.drawer { background: var(--card); height: 302px; overflow: hidden; }
.drawer__item--shut .drawer__chev { transform: rotate(-45deg); border-color: var(--ink-4); }
.drawer__item--shut .drawer__row { color: var(--ink-3); }
.drawer__item + .drawer__item { border-top: 1px solid var(--line-soft); }
.drawer__row {
  height: 40px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  background: var(--card);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.drawer__chev {
  flex: none;
  width: 6px;
  height: 6px;
  border-right: 1.6px solid var(--brand);
  border-bottom: 1.6px solid var(--brand);
  transform: rotate(45deg);
}
.drawer__panel {
  height: 60px;
  overflow: hidden;
  background: var(--brand-tint);
}
.drawer__claim {
  padding: 10px 14px 0;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink);
}
.drawer__claim sup { color: var(--brand); }
.drawer__fine {
  padding: 3px 14px 0;
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--ink-3);
}

/* One 13s clock. The drawers share a single keyframe set and step through it
   a second apart, which keeps each press and its panel locked together. */
.is-in .carousel__track { animation: slide 13s ease-in-out infinite; }
.is-in .carousel__thumb { animation: thumb 13s ease-in-out infinite; }
.is-in .carousel__next  { animation: tap-btn 13s ease-in-out infinite; }
.is-in .pointer         { animation: tap 13s ease-in-out infinite; }
.is-in .drawer__panel {
  animation: drawer 13s ease-in-out infinite;
  animation-fill-mode: backwards;
  animation-delay: calc(var(--d) * 1s);
}
.is-in .drawer__row {
  animation: drawer-row 13s ease-in-out infinite;
  animation-fill-mode: backwards;
  animation-delay: calc(var(--d) * 1s);
}
.is-in .drawer__chev {
  animation: drawer-chev 13s ease-in-out infinite;
  animation-fill-mode: backwards;
  animation-delay: calc(var(--d) * 1s);
}

@keyframes slide {
  0%, 8%    { transform: translateX(0); }
  12%, 16%  { transform: translateX(-33.3333%); }
  20%, 90%  { transform: translateX(-66.6667%); }
  96%, 100% { transform: translateX(0); }
}
@keyframes thumb {
  0%, 8%    { transform: translateX(0); }
  12%, 16%  { transform: translateX(12px); }
  20%, 90%  { transform: translateX(24px); }
  96%, 100% { transform: translateX(0); }
}
@keyframes tap-btn {
  0%, 7%    { background: var(--card); color: var(--ink-2); }
  9%        { background: var(--brand); color: #fff; }
  13%, 15%  { background: var(--card); color: var(--ink-2); }
  17%       { background: var(--brand); color: #fff; }
  21%, 100% { background: var(--card); color: var(--ink-2); }
}
@keyframes drawer {
  0%, 32%   { height: 0; }
  36%, 88%  { height: 60px; }
  93%, 100% { height: 0; }
}
@keyframes drawer-row {
  0%, 30%   { background: var(--card); }
  33%       { background: var(--brand-tint); }
  42%, 100% { background: var(--card); }
}
@keyframes drawer-chev {
  0%, 32%   { transform: rotate(-45deg); }
  36%, 88%  { transform: rotate(45deg); }
  93%, 100% { transform: rotate(-45deg); }
}

.pointer {
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
  pointer-events: none;
  filter: drop-shadow(0 2px 4px rgba(14, 17, 22, .3));
}
/* Row centres are 201, then 302 and 403 once the panels above have opened —
   every height in this mock is explicit, so those hold at any width. Only x
   has to follow the card: the arrow sits 25px in from the right edge, so the
   cursor tip parks at calc(100% - 29px). */
@keyframes tap {
  0%       { opacity: 0; left: calc(100% - 150px); top: 300px; transform: scale(1); }
  4%       { opacity: 1; left: calc(100% - 29px);  top: 159px; transform: scale(1); }
  8%       { opacity: 1; left: calc(100% - 29px);  top: 159px; transform: scale(.74); }
  12%      { opacity: 1; left: calc(100% - 29px);  top: 159px; transform: scale(1); }
  16%      { opacity: 1; left: calc(100% - 29px);  top: 159px; transform: scale(.74); }
  20%      { opacity: 1; left: calc(100% - 29px);  top: 159px; transform: scale(1); }
  27%      { opacity: 1; left: 142px; top: 199px; transform: scale(1); }
  31%      { opacity: 1; left: 142px; top: 199px; transform: scale(.74); }
  34%      { opacity: 1; left: 142px; top: 199px; transform: scale(1); }
  36.5%    { opacity: 1; left: 142px; top: 300px; transform: scale(1); }
  39%      { opacity: 1; left: 142px; top: 300px; transform: scale(.74); }
  42%      { opacity: 1; left: 142px; top: 300px; transform: scale(1); }
  44.5%    { opacity: 1; left: 142px; top: 401px; transform: scale(1); }
  47%      { opacity: 1; left: 142px; top: 401px; transform: scale(.74); }
  50%, 88% { opacity: 1; left: 142px; top: 401px; transform: scale(1); }
  100%     { opacity: 0; left: calc(100% - 150px); top: 300px; transform: scale(1); }
}

/* ── Depth beats ────────────────────────────────────────────────────────── */

/* Replaced the collection-log card and its four bullets. That layout stated
   the depth argument; this one shows it, by putting an agent's result and
   ours in the same row at the same scale. The muted pane is deliberately
   sparse — the empty half of each beat is doing as much work as the full one. */

.beats { margin-top: 34px; display: grid; gap: 16px; }

.beat {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 13px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.beat__head {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: 7px 14px;
  align-items: start;
  padding: 20px 20px 18px;
}
/* Title and copy stack in the second column; the number keeps the first. */
.beat__copy { grid-column: 2; }
.beat__head--plain { grid-template-columns: minmax(0, 1fr); }
.beat__head--plain .beat__copy { grid-column: 1; }

.beat__num {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--brand);
  background: var(--brand-tint);
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: grid;
  place-items: center;
}

.beat__title {
  font-size: 1.1875rem;
  font-weight: 600;
  letter-spacing: -0.022em;
  line-height: 1.35;
  text-wrap: balance;
}
/* The competitor's half of the sentence, greyed. Same size, so it reads as one
   line rather than as a label over a headline. */
.beat__them { color: var(--ink-4); }

.beat__copy {
  margin-top: 0;
  max-width: 82ch;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-3);
  text-wrap: pretty;
}

.vs {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  border-top: 1px solid var(--line);
}
@media (max-width: 720px) { .vs { grid-template-columns: minmax(0, 1fr); } }

.vs__pane {
  padding: 14px 20px 16px;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.vs__pane--them { background: var(--line-soft); border-right: 1px solid var(--line); }
@media (max-width: 720px) {
  .vs__pane--them { border-right: 0; border-bottom: 1px solid var(--line); }
}

.vs__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 11px;
}
.vs__pane--us .vs__label { color: var(--brand); }

/* Pinned to the floor of the pane so the two totals sit on one line across the
   divider, whichever side ran longer. */
.vs__stat {
  margin-top: auto;
  padding-top: 16px;
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--ink-3);
}
.vs__stat b {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}
.vs__pane--us .vs__stat b { color: var(--brand); }
.vs__stat--note { font-size: 12px; line-height: 1.55; color: var(--ink-4); }
.vs__pane--us .vs__stat { color: var(--ink-2); }

/* ── Evidence ───────────────────────────────────────────────────────────── */

/* The exhibit panel, rebuilt from EvidencePanel.jsx. A legal reader is being
   asked to trust a record, so this section shows the actual record rather than
   describing it — the digest, the authority and the method disclosure are the
   argument. */

.ev-grid {
  margin-top: 34px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px;
  align-items: stretch;
}
@media (max-width: 900px) { .ev-grid { grid-template-columns: minmax(0, 1fr); } }

.ev-card { padding: 20px; display: flex; flex-direction: column; }

.ev-head { display: flex; align-items: flex-start; gap: 11px; }

.ev-shield {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  background: var(--pos-tint);
  color: var(--pos);
}

.ev-title { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.ev-body { margin-top: 5px; font-size: 13px; line-height: 1.6; color: var(--ink-3); }
.ev-strong { color: var(--ink); font-weight: 500; }

/* auto rather than a fixed gap: the record block sits on the floor of the card
   so it lines up with the last point in the list beside it. */
.ev-dl {
  margin-top: auto;
  padding-top: 18px;
  border-top: 1px solid var(--line-soft);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 22px;
}
@media (max-width: 480px) { .ev-dl { grid-template-columns: minmax(0, 1fr); } }

.ev-dl dt {
  font-size: 11px;
  color: var(--ink-4);
  font-family: var(--mono);
  letter-spacing: .04em;
}
.ev-dl dd { margin: 2px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-2); }
.ev-dl__wide { grid-column: 1 / -1; }

/* The hash is the point, so it is shown in full and allowed to wrap rather
   than truncated to look tidy. */
.ev-digest {
  font-family: var(--mono);
  font-size: 10.5px !important;
  line-height: 1.55;
  color: var(--ink-3) !important;
  word-break: break-all;
  background: var(--line-soft);
  padding: 7px 9px;
  border-radius: 7px;
}

/* One card, four rows. Four separate cards next to a single tall one always
   ended ragged at the bottom whatever the copy length. */
.ev-points {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 13px;
  box-shadow: var(--shadow-card);
  padding: 4px 20px;
}

.ev-point {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 16px 0;
  border-bottom: 1px solid var(--line-soft);
}
.ev-point:last-child { border-bottom: 0; }
.ev-point__icon {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  background: var(--brand-tint);
  color: var(--brand);
}
.ev-point__icon--warn { background: var(--warn-tint); color: var(--warn); }
.ev-point p { margin-top: 5px; font-size: 13px; line-height: 1.6; color: var(--ink-3); }

.ev-note {
  margin-top: 18px;
  padding: 14px 18px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--line-soft);
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-4);
}
.ev-note b { color: var(--ink-2); font-weight: 600; }

/* ── Alert card (step 03) ───────────────────────────────────────────────── */

/* Step 03's aside used to be five format chips, which described the output
   without ever showing it. This is the thing that actually lands in your
   inbox; the formats moved to its footer where they read as context. */
.alert {
  width: 100%;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 11px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.alert__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 13px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 11.5px;
  color: var(--ink-3);
}
.alert__head b { color: var(--ink); font-weight: 600; }
.alert__dot {
  width: 6px; height: 6px; border-radius: 999px;
  background: var(--warn);
  box-shadow: 0 0 0 3px var(--warn-tint);
  flex: none;
}
.alert__when { margin-left: auto; font-family: var(--mono); font-size: 10.5px; color: var(--ink-4); }
.alert__body { padding: 12px 13px 13px; }
.alert__body .diff { margin-top: 0; }
.alert__claim {
  margin-top: 9px;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
}
.alert__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 8px 13px;
  border-top: 1px solid var(--line-soft);
  background: var(--line-soft);
  font-size: 10.5px;
  color: var(--ink-4);
}
.alert__foot .chip { background: var(--card); font-size: 10.5px; padding: 2px 7px; }

/* ── Noise inbox ────────────────────────────────────────────────────────── */

/* Was a card of dashed bullets, which read as a feature list rather than as
   the thing it is meant to feel like: an inbox you have stopped opening. Now
   it is rows of alerts, greyed, running off the bottom of the card. */
.inbox { display: flex; flex-direction: column; height: 100%; overflow: hidden; }

.inbox__list {
  flex: 1;
  -webkit-mask-image: linear-gradient(#000 62%, rgba(0, 0, 0, .12));
  mask-image: linear-gradient(#000 62%, rgba(0, 0, 0, .12));
}

.inbox__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 12.5px;
  color: var(--ink-4);
}
.inbox__row svg { flex: none; opacity: .5; }
.inbox__when { margin-left: auto; font-family: var(--mono); font-size: 10.5px; opacity: .75; }

.inbox__foot {
  padding: 13px 18px;
  border-top: 1px solid var(--line);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-2);
  background: var(--line-soft);
}
.inbox__foot b { font-weight: 600; color: var(--ink); }

.chip--noise { background: var(--neg-tint); color: var(--neg); }

/* ── Stored fields ──────────────────────────────────────────────────────── */

/* The counterpart to the fine-print exhibit: the same claim after extraction.
   Showing the fields is a better argument for "structured, not summarised"
   than another paragraph saying so. */
.fields { border-top: 1px solid var(--line-soft); }

.fields__row {
  display: grid;
  grid-template-columns: 74px minmax(0, 1fr);
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 12.5px;
}
.fields__row:last-child { border-bottom: 0; }
.fields__k {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-top: 2px;
}
.fields__v { color: var(--ink-2); line-height: 1.45; min-width: 0; }
.fields__v .metric-chip { font-size: 10.5px; }

/* ── Comparison table ───────────────────────────────────────────────────── */

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: 13px;
  background: var(--card);
  box-shadow: var(--shadow-card);
  -webkit-overflow-scrolling: touch;
}

table.cmp {
  width: 100%;
  min-width: 720px;
  border-collapse: collapse;
  font-size: 13.5px;
}

table.cmp th, table.cmp td {
  padding: 13px 16px;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
}
table.cmp tr:last-child th, table.cmp tr:last-child td { border-bottom: 0; }

table.cmp thead th {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink-3);
  border-bottom: 1px solid var(--line);
  background: var(--line-soft);
  white-space: nowrap;
}
table.cmp thead th:first-child { background: var(--line-soft); }

/* The ClaimSpy column is tinted the whole way down so the eye can read one
   vertical strip instead of comparing cell by cell. */
table.cmp .col-us { background: rgba(238, 242, 255, .55); }
table.cmp thead .col-us { background: var(--brand-tint); color: var(--brand); }

table.cmp tbody th {
  font-weight: 500;
  color: var(--ink-2);
  width: 30%;
}

.cmp__yes { color: var(--pos); font-weight: 500; }
.cmp__no  { color: var(--ink-4); }
.cmp__cell { display: flex; align-items: flex-start; gap: 7px; line-height: 1.45; }
.cmp__cell svg { flex: none; margin-top: 2px; }

/* ── Pricing ────────────────────────────────────────────────────────────── */

.tiers {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  align-items: start;
}
@media (max-width: 1040px) { .tiers { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px)  { .tiers { grid-template-columns: minmax(0, 1fr); } }

.tier {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 22px 20px;
  display: flex;
  flex-direction: column;
  height: 100%;
  box-shadow: var(--shadow-card);
  position: relative;
}

.tier--featured {
  border-color: var(--brand-line);
  box-shadow: var(--shadow-lift), 0 0 0 1px var(--brand-line);
}

.tier__flag {
  position: absolute;
  top: -10px;
  left: 20px;
  background: var(--brand);
  color: #fff;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 999px;
}

.tier__name { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.tier__blurb { margin-top: 5px; font-size: 12.5px; color: var(--ink-3); line-height: 1.5; min-height: 38px; }

.tier__price {
  margin-top: 16px;
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.tier__amount {
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}
.tier__per { font-size: 12.5px; color: var(--ink-4); }

.tier__cta { margin-top: 16px; }

.tier__inherits {
  margin-top: 18px;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-4);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line-soft);
}

.tier__list { margin-top: 12px; display: grid; gap: 8px; }
.tier__list li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-2);
}
.tier__list svg { flex: none; margin-top: 3px; color: var(--brand); }
.tier__list b { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }

.tier__note {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-4);
}

.pricing__foot {
  margin-top: 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  justify-content: center;
  font-size: 13px;
  color: var(--ink-3);
}
.pricing__foot span { display: inline-flex; align-items: center; gap: 7px; }
.pricing__foot svg { color: var(--pos); flex: none; }

/* ── FAQ ────────────────────────────────────────────────────────────────── */

.faq { border-top: 1px solid var(--line); }

.faq details {
  border-bottom: 1px solid var(--line);
}

.faq summary {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 0;
  cursor: pointer;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.015em;
  list-style: none;
  transition: color .15s ease;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--brand); }

.faq summary::after {
  content: '';
  margin-left: auto;
  flex: none;
  width: 10px;
  height: 10px;
  border-right: 1.6px solid var(--ink-4);
  border-bottom: 1.6px solid var(--ink-4);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .18s ease;
}
.faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }

.faq__answer {
  padding: 0 40px 20px 0;
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink-3);
  max-width: 68ch;
}
.faq__answer p + p { margin-top: 10px; }
.faq__answer code {
  font-family: var(--mono);
  font-size: 12.5px;
  background: var(--line-soft);
  padding: 1px 5px;
  border-radius: 4px;
  color: var(--ink-2);
}

/* ── Closing CTA ────────────────────────────────────────────────────────── */

.cta {
  position: relative;
  overflow: hidden;
  border-radius: 18px;
  border: 1px solid var(--brand-line);
  background:
    radial-gradient(70% 120% at 50% 0%, rgba(46, 91, 255, .09), transparent 70%),
    var(--card);
  padding: 56px 32px;
  text-align: center;
  box-shadow: var(--shadow-lift);
}

.cta__actions {
  margin-top: 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

.footer { border-top: 1px solid var(--line); padding: 44px 0 56px; }

.footer__grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, minmax(0, 1fr));
  gap: 32px;
}
@media (max-width: 780px) {
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
}

.footer__brand p { margin-top: 12px; font-size: 13px; color: var(--ink-4); line-height: 1.6; max-width: 34ch; }

.footer__col h4 {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.footer__col ul { margin-top: 12px; display: grid; gap: 9px; }
.footer__col a { font-size: 13.5px; color: var(--ink-3); transition: color .15s ease; }
.footer__col a:hover { color: var(--ink); }

.footer__base {
  margin-top: 40px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  align-items: center;
  font-size: 12.5px;
  color: var(--ink-4);
}
.footer__base .right { margin-left: auto; display: flex; gap: 18px; flex-wrap: wrap; }

/* ── Pre-animation states ───────────────────────────────────────────────── */

/* Every stage's resting CSS is its FINISHED frame, so that a reader with no
   JavaScript or reduced motion gets the answer rather than the setup. The cost
   is that a browser about to animate would paint the finished frame first and
   then snap back to frame one. .js-reveal is set in <head> the moment we know
   the animations will run, so these rules paint the starting frame instead and
   nothing ever jumps backwards. They never apply to a reader who is not going
   to see the animation. */

.js-reveal .web__thread,
.js-reveal .agent.web__thread { stroke: #DDE2EA; }
.js-reveal .w3.web__thread    { stroke: #E2E6ED; }
.js-reveal .web__node         { fill: #DDE2EA; }
.js-reveal .chip--page rect,
.js-reveal .agent.chip--page rect { fill: #EDEFF4; stroke: #D4D9E3; }
.js-reveal .w2.chip--page rect    { fill: #EFF1F5; stroke: #DBDFE7; }
.js-reveal .chip--page text       { fill: var(--ink-4); }

.js-reveal .real__nav,
.js-reveal .real__h,
.js-reveal .real__hero,
.js-reveal .real__claim { opacity: 0; }

.js-reveal .drawer__panel { height: 0; }
.js-reveal .drawer__chev  { transform: rotate(-45deg); }
.js-reveal .carousel__track { transform: translateX(0); }
.js-reveal .carousel__thumb { transform: translateX(0); }

/* ── Reveal on scroll ───────────────────────────────────────────────────── */

/* Opt-in via JS: the class is only added when IntersectionObserver exists, so
   with JS off or unsupported every section is simply visible. */
.js-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .5s cubic-bezier(.2, .7, .3, 1), transform .5s cubic-bezier(.2, .7, .3, 1);
}
.js-reveal .reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js-reveal .reveal { opacity: 1; transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   Legal pages — /privacy, /terms, /crawler
   ──────────────────────────────────────────────────────────────────────
   These are the only long-form prose on the site. The landing page is all
   bespoke sections, so none of its classes fit a document you actually
   read top to bottom. Deliberately narrow (--narrow, 760px) because
   measure matters more here than on a page built out of cards.
   ══════════════════════════════════════════════════════════════════════ */

.legal {
  max-width: var(--narrow);
  margin: 0 auto;
  padding: 72px var(--gutter) 96px;
}

.legal__eyebrow {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin: 0 0 14px;
}

.legal h1 {
  font-size: clamp(30px, 4.4vw, 40px);
  line-height: 1.14;
  letter-spacing: -.022em;
  color: var(--ink);
  margin: 0 0 14px;
}

/* The standfirst carries the plain-English summary. On a legal page the
   summary is the part most people actually read, so it gets real size. */
.legal__lede {
  font-size: 17.5px;
  line-height: 1.6;
  color: var(--ink-2);
  margin: 0 0 10px;
}

.legal__updated {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-4);
  margin: 0 0 40px;
  padding-bottom: 28px;
  border-bottom: 1px solid var(--line);
}

.legal h2 {
  font-size: 20px;
  line-height: 1.3;
  letter-spacing: -.012em;
  color: var(--ink);
  margin: 44px 0 12px;
}

.legal h3 {
  font-size: 15.5px;
  line-height: 1.4;
  color: var(--ink);
  margin: 28px 0 8px;
}

.legal p,
.legal li {
  font-size: 15.5px;
  line-height: 1.68;
  color: var(--ink-2);
}

.legal p { margin: 0 0 14px; }

.legal ul,
.legal ol { margin: 0 0 16px; padding-left: 22px; }
.legal li { margin-bottom: 7px; }
.legal li::marker { color: var(--ink-4); }

.legal a {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.legal a:hover { color: var(--brand-hover); }

.legal code {
  font-family: var(--mono);
  font-size: .89em;
  background: var(--line-soft);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1.5px 5px;
  color: var(--ink);
}

.legal strong { color: var(--ink); font-weight: 600; }

/* Pulled-out summary at the top of each document. Same shape as the note
   boxes on the landing page so the two feel like one site. */
.legal__box {
  background: var(--brand-tint);
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  padding: 18px 20px;
  margin: 0 0 8px;
}
.legal__box p:last-child { margin-bottom: 0; }
.legal__box h2 { margin-top: 0; font-size: 15px; }

/* Table for the data / retention rows. Scrolls on its own rather than
   letting the page scroll sideways on a phone. */
.legal__tablewrap { overflow-x: auto; margin: 0 0 18px; }
.legal table {
  width: 100%;
  min-width: 460px;
  border-collapse: collapse;
  font-size: 14.5px;
}
.legal th,
.legal td {
  text-align: left;
  padding: 10px 14px 10px 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
  color: var(--ink-2);
  line-height: 1.55;
}
.legal th {
  color: var(--ink);
  font-weight: 600;
  font-size: 12.5px;
  letter-spacing: .02em;
  text-transform: uppercase;
  border-bottom-color: var(--ink-4);
}

.legal__contact {
  margin-top: 48px;
  padding-top: 28px;
  border-top: 1px solid var(--line);
}

@media (max-width: 640px) {
  .legal { padding: 48px var(--gutter) 72px; }
  .legal__updated { margin-bottom: 30px; }
}
