/* Plumb marketing site — shared stylesheet for index.html, terms.html and privacy.html.

   Every colour here is a signed token from the app's own palette, carried across unchanged. No
   new colour is introduced by this site. The text ramp is an opacity of `ink`, the same
   mechanism the app uses.

   The ramp stops at 0.60 on purpose. In the light palette the app's incidental steps measure
   3.37 (0.50) and 2.55 (0.40) against `keyFill` — below the 4.5 AA bar for body text and below
   the 3.0 large-text bar for the 12px eyebrows this site sets them at.

   The three steps used here measure 4.63-18.20 in light and 6.18-17.00 in dark. The number that
   matters is the bottom of that range, not the top: the floor is `supporting` (0.60), and in
   light it clears the 4.5 AA bar by 0.13 in the worst case the contrast check considers, or by
   0.27 as the page actually renders, since no supporting text lands on `keyFill`. Either way the
   next colour move has about a quarter of a point to spend. That check prints this range on its
   last two lines, so the figure here is generated rather than transcribed.

   No webfont, no external request, no JavaScript. */

/* ---------------------------------------------------------------- tokens */

:root {
  color-scheme: dark light;

  /* Palette — Dark. The canonical appearance; light overrides below. */
  --canvas: #0a0c0f;
  --surface: #101317;
  /* `--surface-alt` is recessed chrome — the placeholder, the contents rail and the page footer.
     Content sits at `--surface`; anything that points AT the content rather than being it sits
     below it. A contents rail at the same elevation as the prose competes with what it indexes. */
  --surface-alt: #0d1013;
  --surface-hover: #151a1f;
  --key-fill: #141920;
  --hero-top: #12171a;
  --hero-bottom: #0d1013;
  --ink: 237 239 242;      /* #EDEFF2, as channels so the ramp can take an alpha */
  --accent: #5fd3ce;
  --accent-ink: #06201f;
  --overlay: 255 255 255;  /* every hairline is an opacity of this */

  /* The text ramp — Plumb.Ink, truncated at `supporting`. */
  --ink-primary: rgb(var(--ink) / 1);
  --ink-body: rgb(var(--ink) / 0.72);
  --ink-supporting: rgb(var(--ink) / 0.6);

  /* Hairlines — Plumb.Hairline. The two box edges are not interchangeable, and which one a block
     takes is decided by what the block HOLDS: `--line-container` is the edge of a block that
     holds other blocks, `--line-card` the edge of a leaf block that holds text. Read as a count
     of boxed containers rather than as a rule, the site looks like it carries a 10-2 split; read
     as this rule it is 3 of 3 and 4 of 4, and every future box has an answer before it is drawn. */
  --line-divider: rgb(var(--overlay) / 0.06);
  --line-card: rgb(var(--overlay) / 0.08);
  --line-container: rgb(var(--overlay) / 0.1);
  --line-button: rgb(var(--overlay) / 0.12);

  /* Radii — Plumb.Radius. */
  --r-sheet: 22px;
  --r-hero: 16px;
  --r-card: 13px;
  --r-button: 12px;
  --r-chip: 10px;
  --r-mark: 7px;
  --r-bar: 3px;

  /* Space — Plumb.Space, plus the web-only page rhythm. */
  --gutter: 20px;
  --card-padding: 14px;
  --hero-padding: 20px;
  --section-gap: 22px;
  --min-target: 44px;
  --measure: 62ch;
  --wrap: 1120px;
  /* The sticky header's WHOLE box: 60px of content plus its own 1px bottom divider. Declared
     here because two things have to agree with it and neither can see it — the header's own
     min-height below, and the document rail's sticky offset, which sits under it. Anything
     that clears the header clears 61px, never 60. */
  --header-h: 61px;

  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
}

@media (prefers-color-scheme: light) {
  :root {
    --canvas: #f7faff;
    --surface: #ebf0f6;
    --surface-alt: #f0f5f9;
    --surface-hover: #e0e7ee;
    --key-fill: #e0e7f2;
    --hero-top: #e4ecf0;
    --hero-bottom: #f0f5f9;
    --ink: 15 16 18;        /* #0F1012 */
    --accent: #007471;
    --accent-ink: #e8ffff;
    --overlay: 0 0 0;
  }
}

/* ----------------------------------------------------------------- reset */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink-body);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, p, ul, ol, figure, dl { margin: 0; }
ul, ol { padding: 0; }
img, svg { display: block; max-width: 100%; }

/* Figures line up in columns the way they do in the app's ledger. */
.num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* ------------------------------------------------------------ focus, motion */

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}
:focus:not(:focus-visible) { outline: none; }

.skip {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 10;
  padding: 10px 16px;
  background: var(--surface);
  color: var(--ink-primary);
  border: 1px solid var(--line-button);
  border-radius: var(--r-button);
  text-decoration: none;
}
.skip:focus { left: 8px; }

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

/* ---------------------------------------------------------------- layout */

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

.section { padding-block: 72px; }
.section + .section { border-top: 1px solid var(--line-divider); }

.section-head { max-width: var(--measure); margin-bottom: 32px; }

.eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-supporting);
  margin-bottom: 12px;
}

h2 {
  font-size: clamp(24px, 3.2vw, 32px);
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 650;
  color: var(--ink-primary);
}

h3 {
  font-size: 18px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  font-weight: 620;
  color: var(--ink-primary);
}

.lede {
  margin-top: 12px;
  font-size: 18px;
  color: var(--ink-body);
  max-width: var(--measure);
}

/* ------------------------------------------------------------------ mark */

/* One lockup, one proportion. The app's own app-bar lockup is a 24pt mark beside a 15px
   wordmark — 1.60, taken from the geometry the mark shipped with, as the logo generator draws
   it — and the site was carrying three different ratios instead: 28:15 in the header, 22:15
   in the footer, 20:11 in Home's device shot. Deriving the wordmark from
   the mark makes the ratio the thing that is declared and the size the thing that varies, so a
   fourth instance cannot invent a fourth proportion.

   `gap` is deliberately NOT derived: the site's wordmark carries 0.16em tracking the app's does
   not, and a letterspaced cap already reads as further from the mark than its metric distance.

   No min-height on the class itself. `--min-target` is a tap-target token and only one of the
   four lockups on this site is a control; put it on `.lockup` and it also reaches the device
   mock's `<span class="lockup lockup--sm">`, which is a PICTURE of an app bar. There it takes
   `.screen-top` from 20px to 44px inside a fixed-aspect `.screen`, and the 24px comes straight
   out of `.ledger` — `flex: 1; min-height: 0; overflow: hidden` — cutting an activity row at
   360px, a supported width. The two lockups that do need the height ask for it below, each for
   its own reason. */
.lockup {
  --mark: 24px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--ink-primary);
}
.lockup svg { width: var(--mark); height: var(--mark); }
.lockup--sm { --mark: 20px; }

/* Only the header's lockup is a link; the device mock's and the footer's are spans. It measured
   103x28 -- the one interactive element on the site under the 44px target, since every other
   link carries the minimum through .nav / .footer-links / .btn and this one is in none of them.
   The target check measures the rendered box on every page so this cannot come back. */
a.lockup { min-height: var(--min-target); }

/* The footer's lockup is a span and is NOT a tap target. It takes the same height for an
   alignment reason: `.footer-grid` aligns its two columns flex-start, and the lockup's 24px mark
   sat 11.00px above the centre of a footer link row that takes its own height from this token.
   Same token, because the thing it has to agree with is measured by it. */
.site-footer .lockup { min-height: var(--min-target); }

.wordmark {
  font-size: calc(var(--mark) / 1.6);
  font-weight: 680;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* ---------------------------------------------------------------- header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--canvas);
  border-bottom: 1px solid var(--line-divider);
}

.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  /* minus the border-bottom on .site-header, which is outside this box and inside --header-h. */
  min-height: calc(var(--header-h) - 1px);
  flex-wrap: wrap;
}

.nav {
  display: flex;
  align-items: center;
  gap: 4px;
  list-style: none;
}

.nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--min-target);
  padding-inline: 12px;
  border-radius: var(--r-chip);
  color: var(--ink-body);
  text-decoration: none;
  font-size: 15px;
}
.nav a:hover { background: var(--surface-hover); color: var(--ink-primary); }
.nav a[aria-current="page"] { color: var(--ink-primary); }

/* A label that wraps mid-item reads as two nav items rather than one. */
.nav a, .footer-links a { white-space: nowrap; }

/* Below 560px the four items no longer fit on one row. The two that go are the in-page
   anchors, not the two pages: both are already carried by the hero's own buttons, one screen
   down, so nothing on the site becomes unreachable — while Terms and Privacy Policy are the
   only way to reach those pages from the top of the page. */
@media (max-width: 559px) {
  /* `*="#"` and not `^="#"`: on terms.html and privacy.html the same two anchors are rewritten
     to `index.html#how` and `index.html#private`, and a `^=` selector misses them — which left
     those two pages showing four nav items, and overflowing, at a width where Home showed two. */
  .nav li:has(a[href*="#"]) { display: none; }
}

/* --------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--min-target);
  padding: 0 20px;
  border-radius: var(--r-button);
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid transparent;
}

.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
}
.btn-primary:hover { filter: brightness(1.06); }

.btn-quiet {
  background: var(--key-fill);
  color: var(--ink-primary);
  border-color: var(--line-button);
}
.btn-quiet:hover { background: var(--surface-hover); }

/* ------------------------------------------------------------------ hero */

.hero { padding-block: 64px 72px; }

.hero-grid {
  display: grid;
  gap: 48px;
  align-items: center;
}

@media (min-width: 900px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 380px); gap: 64px; }
}

h1 {
  font-size: clamp(34px, 6vw, 56px);
  line-height: 1.06;
  letter-spacing: -0.03em;
  font-weight: 680;
  color: var(--ink-primary);
  max-width: 15ch;
}

.hero p {
  margin-top: 20px;
  font-size: clamp(17px, 2vw, 20px);
  color: var(--ink-body);
  max-width: 46ch;
}

.hero-actions {
  margin-top: 32px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.hero-note {
  margin-top: 20px;
  font-size: 14px;
  color: var(--ink-supporting);
  max-width: 46ch;
}

/* A rule that carries the accent without ever putting it in text. */
.accent-rule {
  width: 40px;
  height: 3px;
  border-radius: var(--r-bar);
  background: var(--accent);
  margin-bottom: 22px;
}

/* ------------------------------------------------------------ device mock */

/* A token-faithful reconstruction of Plumb's Home screen, drawn in CSS from the same
   palette, radii and copy as the app. It is not a simulator capture. */

/* The mock is a PICTURE OF A 340 x 690 SCREEN, at every width. The stage takes whatever the
   column gives it and holds the phone's proportion; the device is always laid out at exactly
   340 x 690 and scaled uniformly into that stage, bezel, radius, type and rows together.

   The alternative — the box shrinking while its fixed-size contents keep their pixel sizes —
   is what shipped, and below 355px it cut the mock's own content: `.ledger` is the flexible
   row and clips by design, so at 320 it drew 153px of 235px, dropping two of the five activity
   rows and slicing a fourth in half, while `role="img"`'s label went on naming all five
   rows. Scaling instead of squeezing is also the truthful picture: the app never lays
   its Home screen out at 266pt of usable width, so a mock that reflows to one is a screen the
   product does not have. The overflow check's vertical arm is the guard.

   Both halves are behind @supports on the one declaration that can fail to parse. Without it
   the device keeps `width: 100%` and the pre-existing behaviour — a clipped list, never a
   340px box overflowing a narrower column. */

.device-stage { width: 100%; max-width: 340px; margin-inline: auto; container-type: inline-size; }

.device {
  width: 100%;
  max-width: 340px;
  margin-inline: auto;
  aspect-ratio: 340 / 690;
  padding: 10px;
  border-radius: 44px;
  background: var(--surface);
  border: 1px solid var(--line-container);
}

@supports (transform: scale(calc(100cqi / 340px))) {
  /* The stage is what reserves space in the flow, and it takes the proportion rather than the
     mock: a transform is visual only, so an in-flow device would hold its untransformed 690px
     of layout height and leave a 105px gap under the painted phone at 320. Taking the device
     out of flow leaves the stage sized by nothing but its own ratio. */
  .device-stage { position: relative; aspect-ratio: 340 / 690; }

  .device {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    width: 340px;
    max-width: none;
    /* 100cqi is the stage's content width, so this is 1 at 340 and nothing moves at 372px up. */
    transform: scale(calc(100cqi / 340px));
    transform-origin: top left;
  }
}

.screen {
  height: 100%;
  border-radius: 35px;
  background: var(--canvas);
  padding: 16px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow: hidden;
}

.screen-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.screen-cycle {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--ink-supporting);
}

.hero-card {
  border-radius: var(--r-hero);
  border: 1px solid var(--line-card);
  background: linear-gradient(180deg, var(--hero-top), var(--hero-bottom));
  padding: 16px 14px;
}

.stat-label {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.11em;
  color: var(--ink-supporting);
}

.stat-figure {
  margin-top: 6px;
  font-size: 34px;
  line-height: 1;
  font-weight: 620;
  letter-spacing: -0.02em;
  color: var(--ink-primary);
}

.stat-sub { margin-top: 8px; font-size: 11px; color: var(--ink-supporting); }

.track {
  margin-top: 12px;
  height: 5px;
  border-radius: var(--r-bar);
  background: rgb(var(--overlay) / 0.1);
  overflow: hidden;
}
.track > span { display: block; height: 100%; border-radius: var(--r-bar); background: var(--accent); }

.mini-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

.mini {
  border-radius: var(--r-card);
  border: 1px solid var(--line-card);
  background: var(--surface);
  padding: 10px;
}

.mini .stat-figure { font-size: 17px; margin-top: 4px; }

.afford-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  border-radius: var(--r-button);
  background: var(--key-fill);
  border: 1px solid var(--line-button);
  padding: 11px 12px;
  font-size: 12px;
  color: var(--ink-primary);
  font-weight: 600;
}

.verdict {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--accent-ink);
  background: var(--accent);
  border-radius: 999px;
  padding: 3px 9px;
}

.ledger { display: flex; flex-direction: column; }

.ledger-label { font-size: 9px; font-weight: 600; letter-spacing: 0.11em; color: var(--ink-supporting); padding-bottom: 6px; }

.ledger-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 0;
  border-top: 1px solid var(--line-divider);
}

.chip-mark {
  width: 26px;
  height: 26px;
  flex: 0 0 26px;
  border-radius: var(--r-mark);
  background: var(--key-fill);
  border: 1px solid rgb(var(--overlay) / 0.13);
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 650;
  color: var(--ink-body);
}

.ledger-row .name { font-size: 12px; color: var(--ink-primary); flex: 1; min-width: 0;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ledger-row .amt { font-size: 12px; color: var(--ink-body); font-weight: 600; }

.ledger { flex: 1; min-height: 0; overflow: hidden; }

.tabbar {
  margin-top: auto;
  padding-top: 9px;
  border-top: 1px solid var(--line-divider);
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  align-items: center;
  justify-items: center;
  gap: 4px;
}

.tab {
  font-size: 8px;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--ink-supporting);
}
.tab.is-on { color: var(--ink-primary); }

.tab.add {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  font-size: 15px;
  font-weight: 600;
  line-height: 1;
}

/* --------------------------------------------------------------- feature */

.cards {
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
}

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

.card {
  border-radius: var(--r-card);
  border: 1px solid var(--line-card);
  background: var(--surface);
  padding: 22px 20px;
}

.card h3 { margin-bottom: 8px; }
.card p { font-size: 15px; color: var(--ink-body); }

.card-icon {
  width: 34px;
  height: 34px;
  border-radius: var(--r-chip);
  background: var(--key-fill);
  border: 1px solid var(--line-button);
  display: grid;
  place-items: center;
  margin-bottom: 16px;
  color: var(--accent);
}
.card-icon svg { width: 18px; height: 18px; }

/* A two-column band for the privacy statement. */
.band {
  border-radius: var(--r-sheet);
  border: 1px solid var(--line-container);
  background: linear-gradient(180deg, var(--hero-top), var(--hero-bottom));
  padding: clamp(24px, 4vw, 44px);
}

.band-grid { display: grid; gap: 28px; }
@media (min-width: 860px) { .band-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 48px; } }

.plain {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.plain li {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  font-size: 15px;
  color: var(--ink-body);
}

.plain li::before {
  content: "";
  flex: 0 0 7px;
  width: 7px;
  height: 7px;
  margin-top: 8px;
  border-radius: 2px;
  background: var(--accent);
}

/* ----------------------------------------------------------------- prose */
/* Used by terms.html and privacy.html. */

.prose { max-width: var(--measure); }
.prose h2 { margin-top: 40px; font-size: 22px; }
/* There is deliberately no `.prose h2:first-child { margin-top: 0 }` here. It was written
   for a prose block that OPENS a page, it never matched one — both document pages start
   their prose with the draft notice, a div — and when the document split into notice,
   rail and flow it matched the flow's first heading instead, with the notice card 40px
   above it, and took that clear to 0.00px on both pages. A heading that opens a block
   FOLLOWING something needs the clear more than one opening a page needs to lose it, and
   `:first-child` cannot tell the two apart. `.clause h2` zeroes its own margin where a
   heading really does sit against its container's top border. */
.prose h3 { margin-top: 24px; }
.prose p, .prose li { font-size: 16px; color: var(--ink-body); }
.prose p { margin-top: 14px; }
/* `:where()` and not a bare `.prose ul, .prose ol`: at 0,1,1 this rule outranked every
   class-based list container inside the prose and silently replaced its declared padding —
   `.toc` asked for a 40px marker column, computed to 22px, and put `10.` on the container's
   border. `:where()` drops the selector to 0,1,0, so a class on the list wins and
   the next boxed list cannot repeat it. Baseline since 2021; if this site ever declares a
   floor below Chrome 88 / Safari 14 / Firefox 78, write `.prose ol.toc` instead. */
.prose :where(ul, ol) { margin-top: 14px; padding-left: 22px; }
.prose li { margin-top: 8px; }
.prose a { color: var(--ink-primary); text-decoration: underline; text-underline-offset: 3px; }

.placeholder {
  border-radius: var(--r-card);
  border: 1px dashed rgb(var(--overlay) / 0.2);
  background: var(--surface-alt);
  padding: 18px 20px;
  font-size: 15px;
  color: var(--ink-body);
}

.page-head { padding-block: 56px var(--section-gap); }
.page-head h1 { font-size: clamp(30px, 5vw, 42px); max-width: 20ch; }
.page-head .updated { margin-top: 14px; font-size: 14px; color: var(--ink-supporting); }

/* ------------------------------------------------------- legal document page */
/* terms.html and privacy.html. One long document, read top to bottom: a lede band that says what
   the document is, a contents rail, then numbered sections.

   Colour discipline is the app's, unchanged: accent appears as rules and fills only, never as
   text, and every text colour is a step of the ink ramp at 1.00 / 0.72 / 0.60. Re-run the
   contrast check after touching any of it. */

/* The lede band. A 3px accent edge — a page-level notice, against the 2px the page uses for a
   repeating annotation. Square left corners and an 18px text inset: every boxed block on these
   pages insets its text 18px horizontally from the inner face of its own edge. */
.doc-status {
  border: 1px solid var(--line-container);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--r-card) var(--r-card) 0;
  background: var(--surface);
  padding: 18px;
  font-size: 15px;
}
.doc-status > :first-child { margin-top: 0; }
.doc-status p { font-size: 15px; }
.doc-status-title {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink-primary);
}

/* Inline code, if a document page ever needs it. `overflow-wrap: anywhere` is load-bearing: an
   unbroken token wider than the 320px floor's text column pushes the page into a horizontal
   scroll, and the overflow check fails on it rather than the eye catching it. */
.prose code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", monospace;
  font-size: 0.88em;
  background: var(--key-fill);
  border-radius: 5px;
  padding: 1.5px 5px;
  overflow-wrap: anywhere;
}

/* Contents. Rows are links, so they take the 44px target the nav and footer take — and the
   row NUMBER is set with a counter inside the anchor rather than left as the list's own marker.
   Two things were wrong with the marker: it sits outside the link, so the numeral beside a 44px
   row was not part of it, and its column is padding, which any more specific rule can take away
   — which is how `10.` ended up hard against the container's border. A counter in a
   fixed 26px column is inside the target, cannot collide, and holds two digits at 14px with
   room over. `tabular-nums` keeps 1-9 and 10-12 on one column edge.

   The 12px below restates the eyebrow's own `margin-bottom`, the site's one eyebrow-to-content
   step: the two margins collapse to the larger, so any bigger figure here overrides it. */
.toc {
  margin-top: 12px;
  padding: 2px 18px;
  border: 1px solid var(--line-card);
  border-radius: var(--r-card);
  background: var(--surface-alt);
  list-style: none;
  counter-reset: toc;
}
.toc li {
  margin-top: 0;
  font-size: 14px;
  color: var(--ink-supporting);
  counter-increment: toc;
}
.toc li + li { border-top: 1px solid var(--line-divider); }
.toc a {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--min-target);
  padding-block: 8px;
  font-size: 16px;
  color: var(--ink-body);
  text-decoration: none;
}
.toc a::before {
  content: counter(toc) ".";
  flex: 0 0 26px;
  /* right-aligned, so the stops form a column and every label starts exactly 10px from one:
     left-aligned, 1-9 leave a ragged edge against 10 and the labels stay put anyway. */
  text-align: right;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-supporting);
}
.toc a:hover { color: var(--ink-primary); text-decoration: underline; }
.toc a:hover::before { color: var(--ink-primary); }

/* ------------------------------------------- document page composition */
/* The plates, the measurements and the rejected alternatives are kept with this page's design
   notes. At 1440px the shell and the body disagreed about how wide this page is: header and footer
   content ran x180-1260 while the prose ran x180-766.17, leaving 493.83px of the wrap and 674px
   of the viewport carrying nothing for roughly 4,720px of continuous scroll. The 62ch
   measure is not what is wrong — it is the reading decision and it stands — so the remedy fills
   the space rather than shrinking the page to fit the column, and it fills it with the one thing
   a reader of a twelve-section agreement actually wants: the contents, held beside the text
   instead of scrolled past once at the top.

   Three things this deliberately does NOT do.
   1. It does not centre the measure. The strongest fact in the current composition is that 44
      stacked blocks, the header lockup and the footer all share x=180.00; centring trades a void
      for two smaller voids and spends that spine to do it. Here the prose keeps the lockup's
      left edge and the rail lands on the nav's right edge, so BOTH outer edges are on the shell.
   2. It does not narrow the wrap on document pages. The header is sticky and shared: a narrower
      wrap here would visibly slide the mark sideways every time you navigate Home -> Terms.
   3. It does not highlight the section you are reading. That needs scroll position, and these
      pages carry no JavaScript at all — adding any is the Product Technical Lead's call, not a
      picture's. The rail is ten or twelve plain anchors.

   Below 1024px the grid collapses and the contents return to the flow, one block lower than they
   sit today: draft notice, then contents, then the document. Nothing about the narrow layouts
   changes, and the 320px floor is untouched. */

.doc-body { display: block; }

/* Below 1024px the rail is the next BLOCK after the lede band, not a second column, so it owes
   the page's own block-to-heading rhythm — the 40px every numbered section keeps. Without it the
   clear from the band's bottom border to the `CONTENTS` label was 0.00px at every width from the
   320px floor to 1023, the only 0.00 among the page's thirteen block-to-heading transitions:
   2px of clear above the label against 21px below it, so it grouped with the band it follows
   instead of with the list it names. The reset inside the query below is load-bearing. */
.doc-rail { margin-top: 40px; }

@media (min-width: 1024px) {
  .doc-body {
    display: grid;
    /* space-between spends the slack as one gutter between two occupied columns instead of as
       trailing emptiness after one: 586.17 + 153.83 + 340 = 1080 at 1440px. A text column and a
       navigation rail should not be adjacent, so a wide gutter here is the point, not a residue. */
    grid-template-columns: minmax(0, var(--measure)) minmax(0, 340px);
    justify-content: space-between;
    column-gap: 64px;
    align-items: start;
  }
  .doc-flow { grid-column: 1; grid-row: 1; }
  /* Column 2 while the markup stays first: reading and focus order are contents-then-document,
     which is the order the page has today and the meaningful one for a table of contents. */
  .doc-rail {
    grid-column: 2;
    grid-row: 1;
    /* Two columns, not two blocks: here the rail starts level with the document body and the
       correct clear above it is 0.00, so the narrow-width margin is reset rather than inherited.
       Left in, it drops the rail 40px below the prose's first line. */
    margin-top: 0;
    position: sticky;
    /* The sticky header measures 61px, not 60: 60px of content plus its own 1px bottom divider.
       Both figures below are derived from that one, so the rail keeps 16px of clear above it and
       16px below it instead of 15 and 16. */
    top: calc(var(--header-h) + 16px);
    /* Measured on privacy.html, the longest page on the site and the twelve-row list: the rail
       is 571px tall and NOTHING wraps at 1440, 1280 or 1024 — an earlier version of this comment
       claimed four rows wrapped, which is true at the 320px floor and false at every width this
       grid applies to. So the guard is not carrying the common case: it engages only in a window
       shorter than 663px, where it trades cut-off rows for 63px of scroll inside the rail.
       The fit check measures it against a real viewport height and proves the guard fires. */
    max-height: calc(100vh - var(--header-h) - 32px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

/* One numbered section of the agreement. */
.clause {
  margin-top: 40px;
  padding-top: 28px;
  border-top: 1px solid var(--line-divider);
}
.clause h2 {
  margin-top: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px 12px;
}

/* ---------------------------------------------------------------- footer */

.site-footer {
  border-top: 1px solid var(--line-divider);
  padding-block: 40px 56px;
  background: var(--surface-alt);
}

.footer-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  align-items: flex-start;
  justify-content: space-between;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  list-style: none;
}

.footer-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--min-target);
  padding-inline: 12px;
  border-radius: var(--r-chip);
  font-size: 15px;
  color: var(--ink-body);
  text-decoration: none;
}
.footer-links a:hover { background: var(--surface-hover); color: var(--ink-primary); }
.footer-links a[aria-current="page"] { color: var(--ink-primary); }

.colophon { font-size: 14px; color: var(--ink-supporting); max-width: 44ch; }
.colophon p + p { margin-top: 8px; }

/* -------------------------------------------------- narrow viewport floor */
/* 320px is a real width — iPhone SE at Display Zoom, iPad Slide Over. */

@media (max-width: 380px) {
  :root { --gutter: 16px; }
  .section { padding-block: 52px; }
  .nav a, .footer-links a { padding-inline: 9px; font-size: 14px; }
  .hero-actions .btn { width: 100%; }
}
