/* DocsFlow marketing site — shared styles.
   Official brand palette: ink #0B132B, brand #2563EB, cyan #06B6D4, green #10B981,
   slate --ink-faint #5B6878, surface #F2F4F7. Light-only theme (matches the brand guide).
   The slate is deliberately darker than the brand guide's #64748B: that hex measures 4.32:1
   on the #F2F4F7 page background and fails WCAG AA (issue #86). Do not "restore" it.
   Zero build step: plain CSS, self-hosted Inter over a system fallback stack, responsive. */

/* Inter, self-hosted. The stack below named "Inter" for a long time while nothing ever loaded it
   (no @font-face, no font stylesheet anywhere — issue #89), so the site rendered in SF Pro on
   Apple, Segoe UI on Windows and Roboto on Android. Three typefaces with three sets of metrics,
   which also quietly undermined the responsive work on this site: the widths measured in #83 and
   #109 were all against SF Pro and shifted on the other two platforms.

   One file, deliberately:

   - **Variable, not static weights.** The stylesheet uses 400/500/600/650/700/800 — six static
     files against one variable one, and 650 has no static equivalent at all.
   - **The `latin` subset only.** Every letter the four locales use (en/fr/pt-br/es) lives in
     U+0000–00FF; `latin-ext` would add ~40KB for nothing. Verified by enumerating every non-ASCII
     character in the HTML, the dictionary and this stylesheet — the only ones outside the subset
     are emoji and ✓/✕/→, which fall through to the system emoji font exactly as they do today.
   - **`font-display: swap`.** Text paints immediately in the fallback and re-renders when Inter
     arrives. `block` would hide the copy behind a font download on the cellular connections
     PRODUCT.md calls the common case.

   Licensed SIL OFL 1.1 — see fonts/Inter-LICENSE.txt, which ships beside it as the licence
   requires. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/inter-latin-variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  color-scheme: light;
  --brand: #2563eb;
  --brand-dark: #1d4ed8;
  --brand-tint: #eff4ff;
  --accent: #06b6d4;
  --ink: #0b132b;
  --ink-soft: #475569;
  /* Not the brand guide's stock slate #64748b: that measures 4.32:1 on --surface-alt, under the
     4.5:1 SC 1.4.3 floor for the 14.4px .hero-note. #5b6878 measures 5.16:1 there, 5.68:1 on
     --surface. DocsFlow-Web/tests/marketing/contrast.test.ts holds it. */
  --ink-faint: #5b6878;
  --surface: #ffffff;
  --surface-alt: #f2f4f7;
  --border: #e2e8f0;
  --ok: #10b981;
  --radius: 14px;
  --shadow: 0 1px 2px rgba(11, 19, 43, 0.04), 0 8px 24px rgba(11, 19, 43, 0.06);
  --maxw: 1120px;
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--ink);
  background: var(--surface-alt);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* text-wrap: balance evens out the last line of short headings — and, unlike a
   hardcoded <br>, it keeps working across all four translated lengths. */
h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; margin: 0 0 0.5em; text-wrap: balance; }
h1 { font-size: clamp(2.1rem, 5vw, 3.4rem); font-weight: 800; }
h2 { font-size: clamp(1.6rem, 3.5vw, 2.3rem); font-weight: 700; }
h3 { font-size: 1.15rem; font-weight: 650; }
p { margin: 0 0 1rem; color: var(--ink-soft); }
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }

/* ---------- Focus states ----------
   `.lang-select` used to be the only element in the stylesheet with an authored `:focus-visible`
   style; everything else fell back to the browser's default ring, which is low-contrast against
   the brand-blue `.btn-primary` fill in several browsers and reads as an oversight next to the one
   deliberate rule (issue #87). One shared rule now covers every hand-styled interactive element:
   buttons, nav/footer links, the language select and the FAQ disclosure. `.btn-primary` gets its
   own override because `var(--brand)` is also the button's own fill, where the ring would be
   invisible against it.

   `.audience` chips are deliberately not in this list: they are plain `<li>`s with no `href`,
   `<button>` or `tabindex` (see `index.html`), so they are never keyboard-focusable and a
   `:focus-visible` rule on them would never match — the same class of dead CSS issue #90 found in
   `.logo span b`. If the chips become interactive, add the rule then. */
.btn:focus-visible, .lang-select:focus-visible, .nav-links a:focus-visible, .footer-col a:focus-visible, .faq summary:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
.btn-primary:focus-visible { outline-color: var(--ink); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  font-weight: 600; font-size: 0.98rem; padding: 0.7rem 1.3rem;
  border-radius: 10px; border: 1px solid transparent; cursor: pointer;
  transition: transform 0.06s ease, background 0.15s ease, box-shadow 0.15s ease;
  /* Only above the phone breakpoint — see the @media (max-width: 640px) block, where this comes
     off. A button that cannot wrap has a min-content width equal to its whole label, and as a
     flex/grid item that floor is imposed on its parent (issue #109). */
  white-space: nowrap;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--brand); color: #fff; box-shadow: 0 6px 16px rgba(37, 99, 235, 0.28); }
.btn-primary:hover { background: var(--brand-dark); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--border); }
.btn-ghost:hover { background: var(--surface); }
.btn-lg { padding: 0.85rem 1.6rem; font-size: 1.05rem; }

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
}
/* `flex-wrap` is a floor, not a layout: the row is sized to fit at every breakpoint (see the
   1063px block), and wrapping is what a fifth locale or a longer CTA string degrades into instead
   of overflowing a `position: sticky` box, whose overflow no gesture can scroll back into view.

   The two `margin-inline-start: auto` rules below replace what used to be `justify-content:
   space-between` on three children. `.nav-panel` is `display: contents` here (see below), so the
   row's real children on desktop are logo / links / utils / CTA — four items, and `space-between`
   would have opened a gap between "Sign in" and the trial button that belongs to neither. Two auto
   margins split the free space the same way `space-between` split it across three, and leave the
   last two items adjacent at the row's own gap. */
.nav { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 0.8rem; min-height: 66px; padding-block: 0.5rem; }
.nav-links { display: flex; align-items: center; gap: 1.6rem; margin-inline-start: auto; }
.nav-links a { color: var(--ink-soft); font-weight: 500; font-size: 0.95rem; }
.nav-links a:hover { color: var(--ink); text-decoration: none; }
.nav-utils { display: flex; align-items: center; gap: 0.8rem; margin-inline-start: auto; }
.nav-cta { display: flex; align-items: center; gap: 0.8rem; }

/* ---------- The menu (see the 1063px block for the composition it drives) ----------
   The links and the two utility controls live inside `.nav-panel` so that one breakpoint rule can
   put all of them behind a disclosure. Above 1063px the panel is `display: contents`: its
   box disappears and `.nav-links` / `.nav-utils` become direct flex items of `.nav` again, so the
   header row is composed exactly as it was before the panel existed. That is the whole reason the
   markup is not duplicated into a separate mobile menu — one `<select>`, one set of links, one
   accessible name each.

   The disclosure is a checkbox and a `<label>`, not JavaScript: every CTA on this site is a real
   `href` so the conversion path survives JS being off, and navigation has to clear the same bar.
   `assets/nav.js` only *improves* it (closes on Escape, on an in-page anchor, on an outside tap,
   and syncs `aria-expanded`); with the script blocked the menu still opens and closes. */
.nav-toggle-input { display: none; }
.nav-toggle { display: none; }
/* Three bars that become an X when the panel is open. `currentColor` so the label's colour is the
   only thing that has to be right. */
.nav-toggle-icon, .nav-toggle-icon::before, .nav-toggle-icon::after {
  content: ""; display: block; width: 18px; height: 2px; border-radius: 2px; background: currentColor;
  transition: transform 0.18s ease, background-color 0.12s ease, top 0.18s ease;
}
.nav-toggle-icon { position: relative; }
.nav-toggle-icon::before { position: absolute; top: -6px; }
.nav-toggle-icon::after { position: absolute; top: 6px; }
.nav-toggle-input:checked + .nav-toggle .nav-toggle-icon { background: transparent; }
.nav-toggle-input:checked + .nav-toggle .nav-toggle-icon::before { top: 0; transform: rotate(45deg); }
.nav-toggle-input:checked + .nav-toggle .nav-toggle-icon::after { top: 0; transform: rotate(-45deg); }
/* The input carries focus (a <label> cannot), so the ring has to be drawn on its sibling. */
.nav-toggle-input:focus-visible + .nav-toggle { outline: 2px solid var(--brand); outline-offset: 2px; }
.nav-panel { display: contents; }

/* Reachable by a screen reader, absent from the page. Used for the menu button's name, which is a
   real word rather than an `aria-label` so `data-i18n` translates it like every other string. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Language switcher */
.lang-select {
  font-family: inherit; font-size: 0.9rem; font-weight: 600; color: var(--ink-soft);
  background: transparent; border: 1px solid var(--border); border-radius: 10px;
  padding: 0.5rem 1.9rem 0.5rem 0.7rem; cursor: pointer; line-height: 1.2;
  /* Rendered 35.3px tall at 440px, under the 44x44 floor (WCAG 2.5.5 / Apple HIG) — and it is the
     only control that changes language. The chevron re-centres itself: `background-position:
     ... center` is anchored to the padding box, which grows with the min-height. */
  min-height: 44px;
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' fill='none' stroke='%2394a3b8' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.6rem center;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.lang-select:hover { color: var(--ink); border-color: var(--ink-faint); }
.lang-select option { color: initial; }

/* ---------- Logo ---------- */
/* `flex: none` keeps the wordmark out of the shrink calculation — it is the one thing in the
   header that must never absorb a neighbour's overflow. The wordmark is one element rather than a
   bare "Docs" text node plus a <span>: in a flex container those are two flex items, so the 0.6rem
   gap landed *inside* the word and rendered it "Docs Flow". */
.logo { display: inline-flex; align-items: center; gap: 0.6rem; flex: none; font-weight: 800; font-size: 1.2rem; color: var(--ink); letter-spacing: -0.02em; }
.logo:hover { text-decoration: none; }
.logo-word { white-space: nowrap; }
.logo-mark {
  width: 30px; height: 30px; border-radius: 8px;
  object-fit: contain; display: inline-block; flex: none;
}
/* Colors the "Flow" half of the wordmark. Was `.logo span b` (issue #90), which never matched —
   the markup nests a plain <span> for "Flow" inside .logo-word, not a <b> — so eight inline
   `style="color:var(--brand)"` attributes across the header/footer logo instances were doing the
   job the stylesheet was supposed to. `.logo-word span` (not `.logo span`) so it targets only the
   inner "Flow" span, not `.logo-word` itself, which would recolor "Docs" too. */
.logo-word span { color: var(--brand); }

/* ---------- Hero ---------- */
.hero { padding: clamp(3rem, 8vw, 6rem) 0 clamp(2rem, 5vw, 4rem); }
.eyebrow {
  display: inline-block; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--brand);
  background: var(--brand-tint); padding: 0.35rem 0.75rem; border-radius: 999px; margin-bottom: 1.1rem;
}
.hero p.lead { font-size: 1.2rem; }
.hero-actions { display: flex; gap: 0.9rem; flex-wrap: wrap; margin-top: 1.6rem; }
.hero-note { font-size: 0.9rem; color: var(--ink-faint); margin-top: 1rem; }

/* Centered hero (home): copy stacked above the product visual. */
.hero-centered { text-align: center; padding-bottom: 0; }
.hero-copy { max-width: 48rem; margin: 0 auto; }
.hero-centered h1 { margin-bottom: 0.4em; }
.hero-centered p.lead { max-width: 40ch; margin-left: auto; margin-right: auto; }
.hero-centered .hero-actions { justify-content: center; }
.hero-visual { max-width: 620px; margin: clamp(2.5rem, 6vw, 4rem) auto 0; text-align: left; }

/* Product mock card */
.mock {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 1.1rem;
}
.mock-title { font-weight: 700; margin-bottom: 0.7rem; }
.mock-progress-label { font-size: 0.85rem; color: var(--ink-faint); margin-top: 0.8rem; }
.mock-bar { display: flex; gap: 0.4rem; margin-bottom: 0.9rem; }
.mock-bar i { width: 11px; height: 11px; border-radius: 50%; background: var(--border); display: inline-block; }
.mock-row { display: flex; align-items: center; justify-content: space-between; padding: 0.7rem 0.85rem; border: 1px solid var(--border); border-radius: 10px; margin-bottom: 0.55rem; background: var(--surface-alt); }
.mock-row .name { font-weight: 600; font-size: 0.92rem; }
.pill { font-size: 0.72rem; font-weight: 700; padding: 0.2rem 0.6rem; border-radius: 999px; }
.pill.ok { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
.pill.wait { color: #b45309; background: #fef3c7; }
.progress { height: 8px; border-radius: 999px; background: var(--border); overflow: hidden; margin-top: 0.4rem; }
.progress i { display: block; height: 100%; background: var(--brand); }

/* ---------- Sections ---------- */
section { padding: clamp(3rem, 7vw, 5rem) 0; }
.section-tight { padding-top: clamp(2rem, 4vw, 3rem); }
/* Alternating band: tints a section against the page background. */
.band { background: var(--surface); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.section-head { text-align: center; max-width: 42rem; margin: 0 auto 3rem; }
.section-head p { font-size: 1.1rem; }

/* ---------- Audience chips ---------- */
.audience-grid {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; gap: 0.7rem; justify-content: center;
}
.audience {
  display: inline-flex; align-items: center; gap: 0.55rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
  padding: 0.6rem 1.1rem; font-weight: 600; font-size: 0.98rem; color: var(--ink);
  transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.audience:hover { border-color: var(--brand); transform: translateY(-2px); box-shadow: var(--shadow); }
.audience-ico { font-size: 1.15rem; line-height: 1; }

/* Feature grid */
.grid { display: grid; gap: 1.2rem; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1.5rem; box-shadow: var(--shadow);
}
.card .ico {
  width: 42px; height: 42px; border-radius: 10px; background: var(--brand-tint);
  display: inline-flex; align-items: center; justify-content: center; font-size: 1.3rem; margin-bottom: 0.9rem;
}
.card h3 { margin-bottom: 0.3rem; }
.card p { margin: 0; font-size: 0.96rem; }

/* Plan name called out beside a section heading. Uppercased in CSS, not in the
   markup, so the text itself stays translatable via the plan.pro key. */
.plan-tag {
  font-size: 0.6em; vertical-align: middle; color: var(--brand);
  text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700;
}

/* "Coming soon" badge on a feature card heading */
.badge-soon {
  display: inline-block; vertical-align: middle; font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--brand);
  background: var(--brand-tint); border-radius: 999px; padding: 0.15rem 0.55rem;
}

/* ---------- How it works: 4-step flow ---------- */
.flow {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem;
}
.flow-step { position: relative; padding-top: 0.5rem; }
.flow-step h3 { margin-bottom: 0.35rem; }
.flow-step p { font-size: 0.95rem; margin: 0; }
.flow-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--brand); color: #fff; font-weight: 700; font-size: 1.02rem;
  margin-bottom: 0.9rem; position: relative; z-index: 1;
}
/* Connector between consecutive steps: a rule on desktop, an arrow on mobile. */
.flow-step + .flow-step::before {
  content: ""; position: absolute; top: 19px; left: -1.5rem; width: 1.5rem;
  border-top: 2px dashed var(--border);
}
/* The step pops when it scrolls into view (see .reveal below). */
.flow-step .flow-num { transition: transform 0.4s cubic-bezier(0.2, 0.9, 0.3, 1.4) 0.15s; }
.flow-step.reveal:not(.is-visible) .flow-num { transform: scale(0.6); }

/* ---------- Comparison tables: the shared scroll box ----------
   `.table-wrap` is one element serving both comparisons — index.html's before/after table and
   pricing.html's plan comparison — so the affordance below is written once rather than twice. Both
   tables are sized to fit the container below 640px (see the 640px block); this is the floor for
   the viewport or locale where even min-content does not.

   Scrolling shadows, no JavaScript. The two `local` layers are surface-coloured panels anchored to
   the *content*, so each scrolls away from its edge and uncovers a `scroll`-attached shadow pinned
   to the *box*. A shadow is therefore drawn exactly when there is content hidden past that edge,
   and fades as the edge is reached — no false positive at the desktop widths where both tables
   already fit. `overflow-x: auto` on its own showed nothing at all: iOS keeps overlay scrollbars
   hidden until a scroll is already under way, so 130px of pricing.html's Professional column sat
   off-screen behind a table that looked finished (issue #85).

   The `role="region"` + `tabindex="0"` half lives in the markup: a box only a swipe can reach is
   not operable from a keyboard, and a focus stop needs a name — which is the section's own <h2>
   via `aria-labelledby`, so no new string has to be translated for it. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border); border-radius: var(--radius);
  background:
    linear-gradient(to right, var(--surface) 30%, rgba(255, 255, 255, 0)) 0 0 / 44px 100% no-repeat local,
    linear-gradient(to left, var(--surface) 30%, rgba(255, 255, 255, 0)) 100% 0 / 44px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, rgba(11, 19, 43, 0.17), rgba(11, 19, 43, 0)) 0 0 / 16px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(11, 19, 43, 0.17), rgba(11, 19, 43, 0)) 100% 0 / 16px 100% no-repeat scroll,
    var(--surface);
}
.table-wrap:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ---------- Without / with comparison ---------- */
/* Carries `.table-wrap` for the box itself; this rule is only its placement. */
.versus { max-width: 780px; margin: 0 auto; }
.versus-table { width: 100%; border-collapse: collapse; min-width: 420px; }
.versus-table th, .versus-table td { padding: 0.95rem 1.3rem; border-bottom: 1px solid var(--border); text-align: left; width: 50%; }
.versus-table thead th { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; }
.versus-table .col-without { color: var(--ink-faint); }
.versus-table .col-with { color: var(--brand); background: var(--brand-tint); }
.versus-table .cell-with { background: color-mix(in srgb, var(--brand-tint) 55%, transparent); font-weight: 600; }
.versus-table .cell-without { color: var(--ink-faint); }
.versus-table td { display: table-cell; font-size: 0.98rem; }
.versus-table .mark { display: inline-block; width: 1.2em; font-weight: 800; }
.versus-table .mark.no { color: #cbd5e1; }
.versus-table .mark.yes { color: var(--ok); }
.versus-table tr:last-child td { border-bottom: none; }

/* ---------- Pricing ---------- */
.pricing { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem; max-width: 780px; margin: 0 auto; }
.plan {
  background: var(--surface); border: 1px solid var(--border); border-radius: 18px;
  padding: 2rem; box-shadow: var(--shadow); display: flex; flex-direction: column;
}
/* Emphasis only — deliberately no "Most popular" ribbon. With a single paid
   plan the claim is meaningless, and it is unevidenced social proof besides.
   A CSS `content` string is also unreachable by i18n.js, so it could never
   have been translated. */
.plan.featured { border-color: var(--brand); box-shadow: 0 10px 40px rgba(37, 99, 235, 0.18); position: relative; }
.plan h3 { font-size: 1.3rem; }
.plan .price { font-size: 2.6rem; font-weight: 800; color: var(--ink); letter-spacing: -0.03em; margin: 0.3rem 0 0; }
.plan .price small { font-size: 1rem; font-weight: 500; color: var(--ink-faint); }
.plan .tagline { color: var(--ink-soft); min-height: 2.6em; }
.plan ul { list-style: none; padding: 0; margin: 1.4rem 0; display: grid; gap: 0.7rem; }
.plan li { display: flex; gap: 0.6rem; align-items: flex-start; font-size: 0.96rem; }
.plan li .check { color: var(--ok); font-weight: 800; flex: none; }
.plan li .dash { color: var(--ink-faint); flex: none; }
.plan li.muted { color: var(--ink-faint); }
.plan .btn { margin-top: auto; }

/* Comparison table (the box is `.table-wrap`, shared with `.versus` — see above) */
table.compare { width: 100%; border-collapse: collapse; min-width: 520px; }
table.compare th, table.compare td { text-align: left; padding: 0.9rem 1.2rem; border-bottom: 1px solid var(--border); }
table.compare thead th { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-faint); }
table.compare th[scope="col"]:not(:first-child), table.compare td:not(:first-child) { text-align: center; width: 22%; }
table.compare tbody th { font-weight: 600; color: var(--ink); }
table.compare .yes { color: var(--ok); font-weight: 800; }
table.compare .no { color: var(--ink-faint); }
table.compare tr:last-child td, table.compare tr:last-child th { border-bottom: none; }

/* CTA band */
.cta {
  /* var(--accent) instead of the off-palette #7c3aed (issue #90) — PRODUCT.md's binding palette
     has no violet, and --accent was declared but never used anywhere in the stylesheet. */
  background: linear-gradient(135deg, var(--brand), var(--accent)); color: #fff;
  border-radius: 22px; padding: clamp(2.2rem, 5vw, 3.5rem); text-align: center;
}
.cta h2 { color: #fff; }
.cta p { color: rgba(255, 255, 255, 0.9); max-width: 46ch; margin: 0 auto 1.6rem; }
.cta .btn-primary { background: #fff; color: var(--brand-dark); box-shadow: none; }
.cta .btn-primary:hover { background: #f1f5f9; }

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--border); background: var(--surface); padding: 3rem 0 2rem; margin-top: 2rem; }
.footer-grid { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 2rem; }
.footer-col h4 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-faint); margin: 0 0 0.8rem; }
/* `:not(.logo)`: `.footer-col a` (0,1,1) otherwise beats `.logo`'s own inline-flex/color/weight
   rule (0,1,0) by specificity, collapsing the footer wordmark to a block link with no gap between
   the mark and "Docs"/"Flow", and recoloring it to the muted link color instead of --ink. */
.footer-col a:not(.logo) { display: block; color: var(--ink-soft); margin-bottom: 0.5rem; font-size: 0.95rem; }
.footer-bottom { margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border); color: var(--ink-faint); font-size: 0.88rem; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem; }

/* Footer links on a touch device (issue #88).

   As authored these are 24.3px tall with 8px between them — 0.3px over the WCAG 2.5.8 (AA) 24x24
   minimum and 20px under the 2.5.5 (AAA) / Apple HIG target of 44x44. They are full-width, so the
   miss happens vertically: a thumb aiming at Pricing has a 24px band with How it works 8px below
   it. Same floor the header was brought up to in #104 — stated rather than inherited by luck.

   Keyed on `(pointer: coarse)`, not a width breakpoint, because the defect is width-independent:
   measured in Chrome 151 over CDP, the links were 24.3px/8px at 320, 375, 440, 768, 820 and 1024px
   in all four locales. `.footer-grid` only stacks below 640px, but above that the links are still a
   vertical list inside each column — so a width-keyed fix would leave every tablet exactly as it
   was. Coarse pointer means the primary input is a finger, which is the thing that actually needs
   the bigger box; a trackpad laptop with a touchscreen still reports `fine` and keeps the tighter
   desktop footer (verified unchanged at 375, 1024 and 1440px).

   Dropping the margin to 0 is deliberate: at 44px the boxes themselves provide the separation and
   adjacent targets touch, which is the right trade — 8px of dead space between two 24px targets
   protects nobody, while 44px puts every label's centre 22px from the nearest wrong destination.

   `:not(.logo)` keeps the wordmark's own box out of the flex/stretch treatment; it gets the floor
   on its own line below, since at 37.3px it was under it too. */
@media (pointer: coarse) {
  .footer-col a:not(.logo) { display: flex; align-items: center; min-height: 44px; margin-bottom: 0; }
  .footer-col .logo { min-height: 44px; }
}

/* ---------- Contact form ----------
   The only form on the marketing site. Two rules here are correctness rather than taste:

   * **16px on every control, unconditionally.** iOS Safari zooms the page when a focused input's
     font is under 16px and never zooms back out — the same defect the app avoids with
     `NO_ZOOM_INPUT_FONT_SIZE`. The app scopes that to `(pointer: coarse)` because it has a dense
     desktop layout to protect; this form is five stacked fields in a 560px column, where 16px is
     the right size on a desktop too, so it is stated once at the top rather than per media query.
   * **44px minimum height**, the WCAG 2.5.5 floor this stylesheet has already had to be brought up
     to twice (#88, #104). At 0.8rem of vertical padding the inputs clear it on their own; the
     `min-height` states it so a future padding tweak cannot quietly drop under. */
.contact-form, .contact-sent { max-width: 560px; margin: 0 auto; }
.contact-form {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: clamp(1.4rem, 4vw, 2.2rem);
}
.field { margin-bottom: 1.1rem; }
.field label { display: block; font-weight: 600; font-size: 0.95rem; margin-bottom: 0.4rem; }
.field input, .field select, .field textarea {
  width: 100%; font-family: inherit; font-size: 1rem; line-height: 1.5; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
  padding: 0.7rem 0.85rem; min-height: 44px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.field textarea { resize: vertical; min-height: 8.5rem; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-faint); }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--ink-faint); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  outline: 2px solid var(--brand); outline-offset: 1px; border-color: var(--brand);
}
/* Matches `.lang-select`'s chevron so the two selects on the page look like one control. */
.field select {
  -webkit-appearance: none; -moz-appearance: none; appearance: none; cursor: pointer;
  padding-right: 2.2rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' fill='none' stroke='%2394a3b8' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.8rem center;
}
.contact-form .btn { width: 100%; min-height: 48px; }
/* Empty until something is said, so it must not reserve a gap while it holds nothing. */
.form-status { margin: 0 0 0.9rem; font-size: 0.95rem; font-weight: 600; }
.form-status:empty { margin: 0; }
/* #b91c1c on --surface measures 6.4:1, clearing SC 1.4.3 for this 15.2px text. The message is
   never the *only* signal — focus also moves to the offending control. */
.form-status.is-error { color: #b91c1c; }
.form-note { margin: 0.9rem 0 0; font-size: 0.85rem; color: var(--ink-faint); text-align: center; }

.contact-sent {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: clamp(1.8rem, 5vw, 2.8rem); text-align: center;
}
.contact-sent:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.contact-sent .ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; margin-bottom: 0.8rem; border-radius: 50%;
  font-size: 1.5rem; font-weight: 700; color: var(--ok);
  background: color-mix(in srgb, var(--ok) 14%, transparent);
}

.faq { max-width: 720px; margin: 0 auto; }
.faq details { border: 1px solid var(--border); border-radius: 12px; background: var(--surface); padding: 0.4rem 1.1rem; margin-bottom: 0.8rem; }
.faq summary { cursor: pointer; font-weight: 600; padding: 0.7rem 0; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; float: right; color: var(--brand); font-weight: 700; }
.faq details[open] summary::after { content: "–"; }
.faq p { padding-bottom: 0.6rem; margin: 0; }

.center { text-align: center; }
.mt-2 { margin-top: 2rem; }

/* ---------- Scroll reveal ----------
   assets/reveal.js adds .is-visible when the element enters the viewport.
   Elements only start hidden once the script has confirmed it is running
   (html.js-reveal), so with JavaScript off the page renders fully visible. */
.js-reveal .reveal { opacity: 0; transform: translateY(18px); }
.reveal { transition: opacity 0.55s ease, transform 0.55s cubic-bezier(0.2, 0.7, 0.3, 1); }
.reveal.is-visible { opacity: 1; transform: none; }
.reveal-delay-1 { transition-delay: 0.09s; }
.reveal-delay-2 { transition-delay: 0.18s; }
.reveal-delay-3 { transition-delay: 0.27s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js-reveal .reveal { opacity: 1; transform: none; }
  .reveal, .flow-step .flow-num { transition: none; }
  .nav-toggle-icon, .nav-toggle-icon::before, .nav-toggle-icon::after { transition: none; }
  .flow-step.reveal:not(.is-visible) .flow-num { transform: none; }
}

/* ---------- The header below 1064px ----------
   The breakpoint is where the desktop row stops fitting, in the widest locale rather than in
   English. Laid out in full the row asks for ~853px in English and ~982px in French — logo 137 +
   four links 308 + language 116 + Sign in 94 + CTA 147, plus gaps — against a container of
   viewport minus 48px. So the row needs a viewport of at least 982 + 48 = 1030px, and what shipped
   depended on how far below that you were:

     * 901-1029px: `.nav`'s `flex-wrap` caught it and the header stood in two rows, 105px of sticky
       chrome, for fr / es / pt-br. English fitted, so this was invisible to anyone testing in one
       language.
     * 641-900px: two rows in every locale.
     * <=640px: the stylesheet hid `.nav-links` outright and put nothing in its place, leaving the
       phone with no route to Features, Pricing, How it works or FAQ except the footer 7.6 screens
       down `index.html` (issue #84).

   One composition replaces all three: everything but the logo and the trial CTA moves into
   `.nav-panel` behind a menu button, and the row comes back to a single 67px line at every width
   from 320px to 1063px in all four locales (measured in Chrome 151). Collapsing on the widest
   locale rather than on English is the point — otherwise a French visitor on a 1000px window keeps
   the two-row header that an English-speaking reviewer never sees.

   The breakpoint is 1063px, not the 1030px the arithmetic requires exactly: the first fix (#108)
   rounded to 1024px instead, which is 6px short of the 1030px floor and left fr/es standing in two
   rows at exactly 1024px — the iPad landscape viewport and a common desktop window (issue #132).
   1063px clears the 1030px floor with room to spare instead of chasing the boundary pixel-exact
   again.

   The disclosure is CSS-only (`.nav-toggle-input:checked ~ .nav-panel`) for the same reason every
   CTA on this site is a real href: the site has to work with JavaScript off, and below 640px this
   menu is the *only* route to four of the five pages. `assets/nav.js` improves it (Escape, outside
   tap, in-page anchors, `aria-expanded`) but is never what makes it work. */
@media (max-width: 1063px) {
  .nav-cta { margin-inline-start: auto; }
  /* 44x44 (WCAG 2.5.5) is a floor the header has already had to be brought up to once (#104) —
     state it rather than inherit it by luck. The CTA is not otherwise shrunk: English is the widest
     of the four CTA strings at 147.4px and the row has ~80px of slack at 375px. */
  .nav-cta .btn { min-height: 44px; }

  .nav-toggle-input {
    /* Visually gone but still focusable and still checkable — `display: none` would take the menu
       out of the tab order entirely and leave the label inert for keyboard users. */
    display: block; position: absolute; width: 1px; height: 1px;
    margin: 0; opacity: 0; pointer-events: none;
  }
  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center; flex: none;
    /* Below 640px this button is the only route to four of the site's five pages. */
    width: 44px; height: 44px;
    color: var(--ink); border: 1px solid var(--border); border-radius: 10px;
    background: transparent; cursor: pointer;
  }

  /* Anchored to `.site-header` — the nearest positioned ancestor, since `position: sticky` is a
     positioned box — so the panel hangs below the bar instead of growing it. A sticky header that
     grew to fit six items would eat a quarter of an iPhone SE viewport on every page. */
  .nav-panel {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch;
    padding: 0.4rem 24px 1rem; background: var(--surface);
    border-bottom: 1px solid var(--border); box-shadow: var(--shadow);
    max-height: calc(100vh - 66px); overflow-y: auto;
  }
  .nav-toggle-input:checked ~ .nav-panel { display: flex; }
  .nav-links { display: flex; flex-direction: column; align-items: stretch; gap: 0; margin: 0; }
  .nav-links a {
    display: flex; align-items: center; min-height: 48px;
    color: var(--ink); font-size: 1.05rem; font-weight: 600;
    border-bottom: 1px solid var(--border);
  }
  .nav-utils { margin: 0; padding-top: 0.9rem; gap: 0.6rem; }
  /* Sign in comes back here — #83 took it out of the *bar*, not off the phone, and the footer copy
     of it is 7.6 screens down. Both controls share the row and stay above the touch floor. */
  .nav-utils .lang-select, .nav-utils .btn-ghost { flex: 1 1 0; min-width: 0; }
  .nav-utils .btn-ghost { min-height: 44px; }
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .grid-3 { grid-template-columns: 1fr 1fr; }
  .flow { grid-template-columns: 1fr 1fr; }
  .flow-step + .flow-step::before { display: none; }
}
@media (max-width: 640px) {
  /* The one piece of the header that is phone-specific rather than "the desktop row does not fit"
     (which the 900px block above handles). The wordmark is worth 107px, and at 320px the bar has
     only ~50px of slack left once the mark, the menu button and the CTA have taken their share —
     so below 640px the logo drops to the mark alone. The <a> keeps `aria-label="DocsFlow"`, so
     hiding its only text does not leave an unnamed link (issue #83). */
  .nav .logo-word { display: none; }

  /* Buttons wrap here instead of holding the page open (issue #109).

     `white-space: nowrap` on `.btn` makes a button's min-content width its entire label, and a
     flex/grid item's automatic minimum size is that min-content — so the parent cannot shrink past
     it and the *page*, not a scroll box, overflows. Three strings are long enough for that in the
     locales the product actually ships: `pp.professional.cta` and `teaser.professional.cta` ("Passer
     à Professional — 29 $/mois", "Assinar o Professional — US$ 29/mês") and `feat.explore`
     ("Découvrir toutes les fonctionnalités →"). Measured in Chrome 151 over CDP before the change,
     3 pages x 6 widths x 4 locales: `.plan` rendered 361.8px wide inside a 272px container on
     `pricing.html`, dragging every section of the page off-centre — 66px past the edge at 320px in
     pt-br, 26px at 360px, 11px at 375px, and 10px even in English at 320px. `document.scrollingElement`
     is what scrolls, so this is not the plan card sliding under a thumb; it is the whole page, with
     the purchase button running off it.

     Two lines of button is a fine outcome and an unreachable CTA is not, so the nowrap floor comes
     off for every button on the phone — including the header's, where wrapping is likewise the
     recoverable degradation the sticky bar wants (#83). `text-align: center` is not decoration:
     `.btn` is an inline-flex box, so `justify-content` centres the text block while the lines
     *inside* it would otherwise sit left. `overflow-wrap` is the safety valve for the future locale
     whose longest single word is wider than the card. */
  .btn { white-space: normal; text-align: center; overflow-wrap: break-word; }

  /* Comparison tables: reflowed to the container rather than scrolled sideways.
     `min-width: 520px` on `table.compare` inside a 342px container put 130px off the right edge at
     440px — the whole Professional column, the plan the page exists to sell, showing 22px of one
     glyph — and `.versus-table`'s 420px clipped the "With DocsFlow" payoff column the same way.
     Neither had any affordance at all (issue #85); the shadows on `.table-wrap` are now the floor,
     but a 3-column comparison a visitor has to swipe through is the wrong shape on a phone whether
     or not it advertises itself.

     Taking the floor off lets the columns size themselves, because the values are short in every
     locale — "Ilimitado", "Somente leitura", a glyph — so what wraps is the feature name and all
     three columns stay on screen. Measured in Chrome 151 over CDP, 2 pages x 11 widths x 4 locales:
     both tables now come out exactly the width of their box from 375px up, in every locale, and
     `.versus-table` fits all the way down to 320px. `table.compare` is the one that still needs
     the scroll box below 375px — 12px past the edge at 360px in pt-br, 28-52px at 320px — which is
     what the shadows above are for.

     The column heads drop their uppercasing here because that is what made *them* the binding
     constraint: "PROFESSIONAL" is a single unbreakable word, wider than any value under it. */
  table.compare { min-width: 0; font-size: 0.9rem; }
  .versus-table { min-width: 0; }
  table.compare th, table.compare td, .versus-table th, .versus-table td { padding: 0.55rem 0.6rem; overflow-wrap: break-word; }
  table.compare thead th, .versus-table thead th { text-transform: none; letter-spacing: 0; font-size: 0.8rem; }
  .versus-table td { font-size: 0.92rem; }

  .grid-3, .grid-2, .pricing, .flow { grid-template-columns: 1fr; }
  .footer-grid { flex-direction: column; }
  .audience { font-size: 0.92rem; padding: 0.5rem 0.9rem; }
  /* Vertical chain: a downward arrow between stacked steps. */
  .flow-step + .flow-step::before {
    display: block; content: "↓"; top: -1.15rem; left: 12px; width: auto;
    border: 0; color: var(--brand); font-weight: 700; line-height: 1;
  }
}
