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

   Every colour here is a signed token from Sources/PlumbUI/PaletteValues.swift, carried across
   unchanged. No new colour is introduced by this site. The text ramp is an opacity of `ink`,
   the same mechanism Plumb.Ink uses in the app.

   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 tools/contrast.py 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. The tool 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: #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;
  --alarm: #e2b254;
  --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. */
  --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;

  --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;
    --alarm: #8b5f00;
    --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 */

.lockup {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--ink-primary);
}

/* 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.
   tools/check-targets.py measures the rendered box on every page so this cannot come back. */
a.lockup { min-height: var(--min-target); }

.wordmark {
  font-size: 15px;
  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;
  min-height: 60px;
  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. */

.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);
}

.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; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin-top: 24px; }
.prose p, .prose li { font-size: 16px; color: var(--ink-body); }
.prose p { margin-top: 14px; }
.prose ul, .prose 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. A draft agreement is two kinds of text interleaved — the clause, which is legal
   copy nobody here writes, and the product fact it will govern, which comes out of the app's
   source. They must never be mistakable for each other, so each has its own container and the
   clause carries a visible PENDING chip until real copy lands.

   Colour discipline is the app's, unchanged: accent and alarm appear 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. Run
   tools/contrast.py after touching any of it. */

/* The status band. `alarm` as a 3px edge — a draft notice, not a text colour. */
.doc-status {
  border: 1px solid var(--line-container);
  border-left: 3px solid var(--alarm);
  border-radius: var(--r-card);
  background: var(--surface);
  padding: 18px 20px;
  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);
}

/* Where a figure or a phrase came from. Always the last line of its container. */
.prose .cite {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-supporting);
}

/* Paths and symbol names break anywhere: `Resources/en.lproj/Localizable.strings` is wider than
   the 320px floor's text column, and without this it pushes the page into a horizontal scroll. */
.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. */
.toc {
  margin-top: 18px;
  padding: 2px 18px 2px 40px;
  border: 1px solid var(--line-card);
  border-radius: var(--r-card);
  background: var(--surface-alt);
}
.toc li { margin-top: 0; font-size: 14px; color: var(--ink-supporting); }
.toc li + li { border-top: 1px solid var(--line-divider); }
.toc a {
  display: flex;
  align-items: center;
  min-height: var(--min-target);
  padding-block: 8px;
  font-size: 16px;
  color: var(--ink-body);
  text-decoration: none;
}
.toc a:hover { color: var(--ink-primary); text-decoration: underline; }

/* 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;
}

/* The chip that stops a scaffold heading reading as a delivered clause. */
.pending, .tag-inline {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink-supporting);
  background: var(--key-fill);
  border: 1px solid var(--line-button);
  border-radius: var(--r-chip);
  padding: 4px 9px;
}
.tag-inline { letter-spacing: 0.06em; }

/* What the app does today. Accent edge, because this is the half that is true. */
.fact {
  margin-top: 18px;
  padding: 14px 18px;
  border-left: 2px solid var(--accent);
  border-radius: 0 var(--r-card) var(--r-card) 0;
  background: var(--surface-alt);
}
.fact > :first-child { margin-top: 0; }
.fact p { font-size: 15px; }
.fact-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-supporting);
}
.fact-label + p { margin-top: 8px; }
/* Privacy's data inventory is a list inside a fact block. Without this it inherits `.prose li`
   at 16px and sits a step larger than the 15px paragraphs it is part of. */
.fact li { font-size: 15px; }

/* Copy that already ships in the app, reproduced rather than rewritten. */
.shipped-copy {
  margin: 18px 0 0;
  padding: 16px 18px;
  border: 1px solid var(--line-card);
  border-radius: var(--r-card);
  background: var(--surface);
}
.shipped-copy > :first-child { margin-top: 0; }
.shipped-copy p { font-size: 15px; color: var(--ink-primary); }
/* The one substitution the shipped string takes, marked so nobody reads it as fixed wording. */
.slot { background: var(--key-fill); border-radius: 5px; padding: 1px 6px; }

/* ---------------------------------------------------------------- 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); }

.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%; }
}
