/* FormsPal OCR landing page. Design system copied from extension.formspal.com
   (page.css, 2026-07-12), which carries the shared FormsPal tokens from
   ai.formspal.com. Adapted here: mega menu dropped (simple anchor nav), the
   hero is a deep-green panel that hosts the real tool card, and the tile
   vignettes are hand-built (this page ships no screenshots). */

@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("fraunces-latin.woff2") format("woff2");
}

:root {
  --primary: #0e8a5f;
  --primary-dark: #0b6e4c;
  --primary-light: #e6f4ee;
  --ink: #1c2530;
  --ink-soft: #51606f;
  --faint: #5c6873;
  --line: #cdd5de;
  --bg: #f7f9fb;
  --card: #ffffff;
  --footbg: #11181c;
  --footink: #c4ccd4;
  --footline: #243038;
  --radius: 12px;
  --white: #ffffff;
  --headbg: rgba(247, 249, 251, 0.88);
  /* CTA orange, same pair as the extension page: bright brand orange for the
     19px-bold hero buttons (AA as large text), darker pair for the 14.5px
     header pill so white text clears 4.5:1. */
  --cta: #ea580c;
  --cta-hover: #c2410c;
  --dc-btn: #c2410c;
  --dc-btn-hover: #9a3412;
  --shadow: 0 1px 2px rgba(16, 38, 30, 0.05), 0 4px 10px rgba(16, 38, 30, 0.05), 0 12px 28px rgba(16, 38, 30, 0.06);
  --edge-hi: inset 0 1px 0 rgba(255, 255, 255, 0);
  --sp-section: 88px;
  --sp-title: 36px;
  --ease: cubic-bezier(0.2, 0, 0, 1);
}
html[data-theme="dark"] {
  --primary: #16a571;
  --primary-dark: #34c188;
  --primary-light: #143323;
  --ink: #f2f5f7;
  --ink-soft: #aab5bf;
  --faint: #8e99a4;
  --line: #2a3036;
  --bg: #15181b;
  --card: #21262d;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  --edge-hi: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  --footbg: #0c1114;
  --footink: #aab5bf;
  --footline: #1c252b;
  --white: #1e2329;
  --headbg: rgba(21, 24, 27, 0.88);
}

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

* { box-sizing: border-box; }

/* The [hidden] attribute is only a UA-stylesheet `display: none`, so any author
   `display` declaration silently outranks it. That is a live trap in this file:
   #again, #tcProgress, .d-file and #file are all toggled by their hidden
   attribute from page.js, and giving any of them a display value un-hides it on
   load. (Adding display: inline-flex to .again for its 44px hit region did
   exactly that, and shipped "Convert another file" onto a fresh page.) */
[hidden] { display: none !important; }

.skip-link {
  position: absolute; left: -9999px; z-index: 100;
  background: var(--cta); color: #fff; font-weight: 700;
  padding: 10px 18px; border-radius: 0 0 10px 0; text-decoration: none;
}
.skip-link:focus { left: 0; top: 0; }

#tool, #faq, #what-is-ocr, #pdf-to-word, #main { scroll-margin-top: 76px; }
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  color: var(--ink); background: var(--bg); line-height: 1.55;
}
html[data-theme="dark"] body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
img { max-width: 100%; height: auto; }
a { color: var(--primary-dark); }
.wrap { max-width: 1080px; margin: 0 auto; padding: 0 20px; }
h1, h2 {
  font-family: "Fraunces", Georgia, serif; font-weight: 600;
  letter-spacing: -0.018em; line-height: 1.15;
  font-optical-sizing: auto; text-wrap: balance;
}
.hero-copy .sub, .tile p, .faq details p, .privacy li, .prose p { text-wrap: pretty; }

::selection { background: rgba(14, 138, 95, 0.25); }
html[data-theme="dark"] ::selection { background: rgba(52, 193, 136, 0.38); }

a:focus-visible, button:focus-visible, summary:focus-visible,
.skip-link:focus-visible {
  outline: 3px solid var(--primary); outline-offset: 2px; border-radius: 4px;
}

/* ---------- ambient depth (from trust.formspal.com via the extension LP) ---------- */
body { overflow-x: clip; }
body::before {
  content: ""; position: fixed; inset: 0; z-index: -2; pointer-events: none;
  background:
    radial-gradient(58% 48% at 12% -4%, rgba(14, 138, 95, 0.09), transparent 70%),
    radial-gradient(52% 44% at 104% 6%, rgba(234, 88, 12, 0.06), transparent 68%),
    radial-gradient(80% 62% at 50% 108%, rgba(14, 138, 95, 0.05), transparent 72%);
}
html[data-theme="dark"] body::before {
  background:
    radial-gradient(58% 48% at 12% -4%, rgba(22, 165, 113, 0.16), transparent 70%),
    radial-gradient(52% 44% at 104% 6%, rgba(234, 88, 12, 0.10), transparent 68%),
    radial-gradient(80% 62% at 50% 108%, rgba(22, 165, 113, 0.08), transparent 72%);
}
/* Borrowed from extension.formspal.com: the ambient wash fades in on load
   instead of snapping in — one gentle orchestrated entrance for the whole page. */
@media (prefers-reduced-motion: no-preference) {
  body::before { animation: fp-glow-in 1.8s var(--ease) both; }
}
@keyframes fp-glow-in { from { opacity: 0; } }
body::after {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  opacity: 0.025; mix-blend-mode: multiply;
  background: url("grain.svg"); background-size: 140px 140px;
}
html[data-theme="dark"] body::after { opacity: 0.04; mix-blend-mode: overlay; }

.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 60;
  transform: scaleX(0); transform-origin: 0 50%; pointer-events: none;
  background: linear-gradient(90deg, var(--primary-dark), var(--primary));
  box-shadow: 0 0 10px rgba(14, 138, 95, 0.5);
}
html[data-theme="dark"] .scroll-progress { box-shadow: 0 0 10px rgba(22, 165, 113, 0.5); }

.ruled { position: relative; padding-top: 44px; }
.ruled::before {
  content: ""; position: absolute; top: 0; left: 20px; right: 20px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line) 16%, var(--line) 84%, transparent);
}

.reveal { opacity: 0; transform: translateY(16px); transition: opacity 650ms var(--ease), transform 650ms var(--ease); }
.reveal.in { opacity: 1; transform: none; }
.tile.reveal:nth-child(3n - 1) { transition-delay: 90ms; }
.tile.reveal:nth-child(3n) { transition-delay: 180ms; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

/* ---------- header (family header chrome, simple anchor nav) ---------- */
.site-head.scrolled { box-shadow: 0 6px 22px -12px rgba(16, 38, 30, 0.35); }
html[data-theme="dark"] .site-head.scrolled { box-shadow: 0 6px 22px -12px rgba(0, 0, 0, 0.6); }
/* Plan badge: revealed by /api/tier on load. Member glows in the accent with a
   live pulsing dot; free stays a quiet neutral pill. Hidden until it resolves. */
.tier-badge {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; user-select: none;
  padding: 5px 11px 5px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 650; letter-spacing: 0.03em;
  border: 1px solid var(--line); color: var(--faint); background: transparent;
}
.tier-badge .tier-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--faint); flex: none; }
.tier-badge[data-tier="member"] {
  color: var(--primary-dark); border-color: var(--primary); background: var(--primary-light);
  box-shadow: 0 0 13px -3px var(--primary);
}
.tier-badge[data-tier="member"] .tier-dot { background: var(--primary); box-shadow: 0 0 6px var(--primary); }
@media (prefers-reduced-motion: no-preference) {
  .tier-badge[data-tier="member"] .tier-dot { animation: fp-tier-pulse 2.2s ease-in-out infinite; }
}
@keyframes fp-tier-pulse { 50% { opacity: 0.5; box-shadow: 0 0 11px var(--primary); } }
/* This was `@media (max-width: 560px) { .tier-badge { display: none } }` and,
   like the nav rule below it, never applied once: (0,1,0) against the vendored
   `.site-head .tier-badge` at (0,2,0). Nothing replaces it here. The frame
   sheds the badge itself from v0.9.0: it keeps the label hidden below 430px
   and strips the pill down to its dot, which is part of how the collapsed bar
   still fits 320px once every control carries a 44px hit region. */
@media (prefers-reduced-motion: no-preference) {
  .site-cta:hover { transform: translateY(-1px); }
  .site-cta::after {
    content: ""; position: absolute; top: 0; left: -75%; width: 45%; height: 100%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.28), transparent);
    transform: skewX(-18deg); transition: left 500ms var(--ease); pointer-events: none;
  }
  .site-cta:hover::after { left: 130%; }
  .site-cta:active { transform: translateY(0) scale(0.97); }
}
/* The nav collapse used to live here as `.site-nav { display: none }`, which
   never fired: it loses to the vendored `.site-head .site-nav` (0,2,0). Do not
   put one back. From v0.9.0 the frame collapses the nav itself, and it does it
   by measuring whether the nav actually fits rather than by any breakpoint,
   because the fit point here moves with the plan pill: it is hidden for signed
   out visitors and revealed by page.js for signed in ones, which is why a
   locally calibrated number shipped with the nav still clipped at 900-999px. */
@media (max-width: 560px) {
  .site-brand .app { display: none; }
  .site-cta { padding: 8px 13px; }
}

/* ---------- hero: deep-green panel hosting the live tool ---------- */
.hero-wrap { padding: 28px 0 var(--sp-section); }
.hero-panel {
  position: relative; overflow: hidden; border-radius: 26px; isolation: isolate;
  background:
    radial-gradient(90% 130% at 0% 0%, rgba(52, 193, 136, 0.26), transparent 56%),
    radial-gradient(64% 90% at 100% 0%, rgba(234, 88, 12, 0.14), transparent 58%),
    radial-gradient(120% 150% at 50% 118%, rgba(22, 165, 113, 0.16), transparent 62%),
    linear-gradient(152deg, #0d4130 0%, #0a2f22 52%, #072118 100%);
  box-shadow: 0 28px 70px -30px rgba(7, 33, 24, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.09);
  padding: clamp(28px, 4.6vw, 56px);
  display: grid; grid-template-columns: 1.04fr 0.96fr;
  gap: clamp(26px, 4vw, 52px); align-items: center;
}
/* Aurora rim light behind the tool card: the same blurred conic circle the
   extension hero floats its screenshot on, rotated on the GPU. */
.hero-panel::before {
  content: ""; position: absolute; left: 76%; top: 42%; width: 58%; aspect-ratio: 1;
  transform: translate(-50%, -50%); border-radius: 50%; pointer-events: none; z-index: -1;
  background: conic-gradient(in oklch,
    oklch(72% 0.16 160), oklch(74% 0.12 210), oklch(68% 0.17 300),
    oklch(80% 0.13 90), oklch(72% 0.16 160));
  filter: blur(52px) saturate(1.15); opacity: 0.4;
}
@media (prefers-reduced-motion: no-preference) {
  .hero-panel::before { animation: fp-aurora 26s linear infinite; }
}
@keyframes fp-aurora { to { transform: translate(-50%, -50%) rotate(360deg); } }
.hero-panel::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  opacity: 0.07; mix-blend-mode: overlay;
  background: url("grain.svg"); background-size: 140px 140px;
}
.hero-copy { position: relative; z-index: 1; color: #eef7f2; }
.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.4px;
  color: #8fe3c0; margin: 0 0 10px;
}
.eyebrow::before {
  content: ""; width: 26px; height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, #5fd2a4, transparent);
}
.hero-copy h1 {
  font-size: clamp(36px, 4.6vw, 52px); line-height: 1.08; letter-spacing: -0.024em;
  font-weight: 640; margin: 0 0 14px; color: #fff;
}
/* Gradient sheen on the hero's key phrase, light mints tuned for the dark hero
   panel (matches extension.formspal.com's .grad, whose token gradient is for a
   light hero). Static under reduced motion. */
.grad {
  background: linear-gradient(92deg, #7be3b6, #b7f4d9, #7be3b6);
  background-size: 220% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .grad { animation: fp-sheen 9s ease-in-out infinite; }
}
@keyframes fp-sheen { 0%, 100% { background-position: 0% 0; } 50% { background-position: 100% 0; } }
.sig { display: block; width: min(240px, 62%); margin: 0 0 16px; color: #5fd2a4; }
@media (prefers-reduced-motion: no-preference) {
  .sig path { stroke-dasharray: 100; stroke-dashoffset: 100; animation: fp-sig-draw 1.5s 350ms var(--ease) forwards; }
}
@keyframes fp-sig-draw { to { stroke-dashoffset: 0; } }
.hero-copy .sub { font-size: 18px; line-height: 1.6; color: rgba(236, 247, 242, 0.85); margin: 0 0 22px; max-width: 32em; }
.hero-copy .sub b { color: #fff; font-weight: 650; }
.hero-trust {
  display: grid; grid-template-columns: max-content max-content; gap: 9px 26px;
  justify-content: start; margin: 0; padding: 0; list-style: none;
  font-size: 12.5px; letter-spacing: 0.04em; text-transform: uppercase;
  color: rgba(236, 247, 242, 0.62); font-weight: 600;
}
.hero-trust li { display: inline-flex; align-items: center; gap: 7px; }
.hero-trust li::before { content: ""; width: 4px; height: 4px; border-radius: 50%; background: #5fd2a4; }
/* White focus ring on the deep green (the brand green ring vanishes there). */
.hero-panel a:focus-visible, .hero-panel button:focus-visible,
.hero-panel .drop:focus-visible, .hero-panel input:focus-visible + span {
  outline: 3px solid #fff; outline-offset: 2px;
}

/* ---------- LIGHT MODE: airy hero, dark card ---------------------------------
   In light mode the deep-green panel read as a "dark square" floating on the
   white page. So light theme gets a soft mint panel with dark ink copy, and the
   dark tool card stays put as an intentional product mockup sitting inside it
   (a light page -> light hero -> dark screenshot is a deliberate, premium shape,
   not the muddy slab it was). Dark mode keeps the base deep-green treatment. */
html[data-theme="light"] .hero-panel {
  background:
    radial-gradient(90% 130% at 0% 0%, rgba(22, 165, 113, 0.14), transparent 56%),
    radial-gradient(64% 90% at 100% 0%, rgba(234, 88, 12, 0.06), transparent 58%),
    radial-gradient(120% 150% at 50% 118%, rgba(14, 138, 95, 0.10), transparent 62%),
    linear-gradient(152deg, #eef9f3 0%, #e3f4ec 52%, #edf6f1 100%);
  box-shadow: 0 26px 64px -34px rgba(14, 90, 62, 0.26), inset 0 1px 0 rgba(255, 255, 255, 0.7);
  border: 1px solid rgba(14, 138, 95, 0.12);
}
/* Aurora halo behind the card is tuned for a dark ground; dim it on light so it
   reads as a soft glow, not a color smear. */
html[data-theme="light"] .hero-panel::before { opacity: 0.24; filter: blur(58px) saturate(1.05); }
html[data-theme="light"] .hero-copy { color: var(--ink); }
html[data-theme="light"] .eyebrow { color: var(--primary-dark); }
html[data-theme="light"] .hero-copy h1 { color: var(--ink); }
html[data-theme="light"] .grad {
  background-image: linear-gradient(92deg, #0e8a5f, #16a571, #0e8a5f);
}
html[data-theme="light"] .sig { color: var(--primary); }
html[data-theme="light"] .hero-copy .sub { color: var(--ink-soft); }
html[data-theme="light"] .hero-copy .sub b { color: var(--ink); }
html[data-theme="light"] .hero-trust { color: var(--faint); }
/* Panel is light now, so the brand-green focus ring is visible again. */
html[data-theme="light"] .hero-panel a:focus-visible,
html[data-theme="light"] .hero-panel button:focus-visible,
html[data-theme="light"] .hero-panel .drop:focus-visible,
html[data-theme="light"] .hero-panel input:focus-visible + span {
  outline-color: var(--primary);
}

/* Light theme: the tool card becomes a clean elevated WHITE card on the mint
   hero panel. The dark-glass mockup read too contrasty on light; dark mode keeps
   it. The --tc-* tokens do most of the re-skin; the rules below override the
   dark-tuned literals (white-on-white overlays, bright-green accents that wash
   out on white, and the status hues). */
html[data-theme="light"] .tool-card {
  --tc-bg: #ffffff;
  --tc-field: #eef3f1;
  --tc-hover: #e7efec;
  --tc-line: rgba(16, 44, 32, 0.12);
  --tc-line-2: rgba(16, 44, 32, 0.22);
  --tc-ink: #1c2530;
  --tc-soft: #51606f;
  --tc-faint: #66727d;
  box-shadow:
    0 1px 2px rgba(16, 60, 42, 0.05),
    0 14px 34px -14px rgba(14, 90, 62, 0.20),
    0 4px 12px rgba(16, 38, 30, 0.05);
}
html[data-theme="light"] .drop { background: rgba(16, 44, 32, 0.015); }
html[data-theme="light"] .drop svg { color: var(--primary); }
html[data-theme="light"] .d-size { color: var(--primary-dark); }
html[data-theme="light"] .ask::after { background: linear-gradient(90deg, rgba(16, 44, 32, 0.12), transparent); }
html[data-theme="light"] .lang-select { background: rgba(16, 44, 32, 0.025); }
html[data-theme="light"] .out-btn { background: linear-gradient(180deg, rgba(16, 44, 32, 0.022), rgba(16, 44, 32, 0.008)); }
html[data-theme="light"] .tc-progress { background: rgba(16, 44, 32, 0.10); }
html[data-theme="light"] .status.err { color: #c23b2b; }
html[data-theme="light"] .status.ok { color: #0b7d55; }
html[data-theme="light"] .status.warn { color: #b1791c; }
html[data-theme="light"] .again:hover { color: var(--primary-dark); }

/* ---------- the tool card: their dark mockup card, except it works ---------- */
.tool-card {
  --tc-bg: #14191d; --tc-field: #1d242a; --tc-hover: #242c33;
  --tc-line: rgba(255, 255, 255, 0.13); --tc-line-2: rgba(255, 255, 255, 0.24);
  --tc-ink: #eef3f4; --tc-soft: #a9b6bd; --tc-faint: #7d8a92;
  position: relative; z-index: 1;
  background: var(--tc-bg); color: var(--tc-soft);
  border: 1px solid var(--tc-line); border-radius: 16px;
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.35),
    0 24px 64px rgba(0, 0, 0, 0.45), 0 4px 16px rgba(0, 0, 0, 0.3),
    0 24px 72px rgba(52, 193, 136, 0.18);
  padding: 18px 18px 20px;
}
.drop {
  position: relative; overflow: hidden;
  border: 1.5px dashed var(--tc-line-2); border-radius: 12px;
  padding: clamp(20px, 2.6vw, 26px) 16px; text-align: center; cursor: pointer;
  color: var(--tc-soft); background: rgba(255, 255, 255, 0.02);
  transition: border-color 180ms var(--ease), background-color 180ms var(--ease), color 180ms var(--ease);
}
/* A scanner's light bar sweeps the zone while you hover or hold a file over it. */
.drop::after {
  content: ""; position: absolute; left: 7%; right: 7%; top: -3px; height: 2px;
  border-radius: 2px; pointer-events: none; opacity: 0;
  background: linear-gradient(90deg, transparent, rgba(52, 193, 136, 0.9), transparent);
  box-shadow: 0 0 12px rgba(52, 193, 136, 0.55);
}
@media (prefers-reduced-motion: no-preference) {
  .drop:hover:not(.busy)::after, .drop.on::after {
    opacity: 1; animation: fp-scan 1.7s var(--ease) infinite;
  }
  .drop.busy::after { opacity: 1; animation: fp-scan 1.1s linear infinite; }
}
@keyframes fp-scan {
  0% { top: 6%; } 50% { top: calc(94% - 2px); } 100% { top: 6%; }
}
.drop:hover, .drop.on { border-color: #34c188; background: rgba(52, 193, 136, 0.08); color: var(--tc-ink); }
.drop.on { border-style: solid; }
.drop.ready { border-style: solid; border-color: #34c188; background: rgba(52, 193, 136, 0.06); }
.drop.busy { cursor: progress; border-color: var(--tc-line-2); background: var(--tc-field); }
.drop svg { display: block; margin: 0 auto 10px; color: #34c188; }
.drop b { color: var(--tc-ink); font-size: 16px; }
.d-hint { display: block; margin-top: 2px; font-size: 13.5px; }
/* balance, not pretty: this is a short centred block where pretty only guards
   the last line and still left "zip" stranded on its own. */
.d-meta { display: block; margin-top: 10px; font-size: 12px; color: var(--tc-faint); letter-spacing: 0.02em; text-wrap: balance; }
.d-name {
  display: block; color: var(--tc-ink); font-weight: 600; font-size: 15px; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.d-size { display: block; margin-top: 3px; font-size: 13px; color: #5fd2a4; }
.d-swap { display: block; margin-top: 9px; font-size: 12px; color: var(--tc-faint); }
/* One question, several answers you can combine. Each format is a slip of dark
   glass tinted in its own hue; tap to select (a check lights up), then the one
   orange Convert button below does the work. */
.ask {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 16px 2px 10px; font-size: 13.5px; font-weight: 700;
  color: var(--tc-faint); letter-spacing: 0.01em;
  transition: color 200ms var(--ease);
}
.ask-hint { font-weight: 500; font-size: 12px; color: var(--tc-faint); letter-spacing: 0; }
.ask::after {
  content: ""; flex: 1; min-width: 20px; height: 1px;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.14), transparent);
}
.tool-card.armed .ask { color: var(--tc-ink); }
.lang-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px 12px;
  flex-wrap: wrap;
  margin: 14px 2px 4px; font-size: 14px; color: var(--tc-soft);
}
/* label[for] focuses the select, so it is a tap target in its own right and
   gets the same 44px floor. */
.lang-row label { flex: none; display: inline-flex; align-items: center; min-height: 44px; }
.lang-select {
  /* min-width: 0 lets the select shrink below the width of its longest option
     ("Middle Eastern & Central Asian"); without it the control sets a 195px
     floor that propagates all the way up to the hero grid track. */
  flex: 1 1 auto; min-width: 0; max-width: 100%; min-height: 44px;
  /* 16px is the iOS Safari threshold: any smaller and focusing the control
     zooms the whole page in, with no zoom back out. */
  font-family: inherit; font-size: 16px; font-weight: 600; color: var(--tc-ink);
  background: rgba(255, 255, 255, 0.04); border: 1px solid var(--tc-line);
  border-radius: 9px; padding: 8px 30px 8px 12px; cursor: pointer; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2334c188' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center;
  transition: border-color 160ms var(--ease);
}
.lang-select:hover, .lang-select:focus-visible { border-color: #34c188; }
.lang-select option { color: #17211c; }
.out-group { display: grid; gap: 8px; }
.out-btn {
  --fx: #34c188;
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 10px 13px; text-align: left; font-family: inherit; cursor: pointer;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.02));
  border: 1px solid var(--tc-line); border-radius: 11px;
  position: relative; overflow: hidden;
  transition: background-color 200ms var(--ease), border-color 200ms var(--ease),
              box-shadow 200ms var(--ease), transform 160ms var(--ease), opacity 200ms var(--ease);
}
/* Per-format accent hue drives icon, tint, hover, and selected state. */
.out-btn[data-fx="text"] { --fx: #34c188; }
.out-btn[data-fx="word"] { --fx: #5b93d6; }
.out-btn[data-fx="gdoc"] { --fx: #5b9bff; }
.out-btn[data-fx="pdf"]  { --fx: #ef7063; }
.out-btn[data-fx="excel"] { --fx: #14a58a; }
/* The custom background: a soft wash of the button's own colour. */
.out-btn::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0.55;
  background: radial-gradient(130% 150% at 0% 0%,
    color-mix(in oklab, var(--fx) 16%, transparent), transparent 62%);
  transition: opacity 220ms var(--ease);
}
.ob-ico {
  flex: none; width: 36px; height: 36px; border-radius: 10px; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  color: var(--fx); background: color-mix(in oklab, var(--fx) 15%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fx) 24%, transparent);
}
.ob-ico svg { width: 19px; height: 19px; }
.ob-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; z-index: 1; }
.ob-main { font-size: 14.5px; font-weight: 700; color: var(--tc-ink); letter-spacing: -0.01em; }
/* 11.5px sat on Apple's absolute floor for iOS text (11pt minimum against a
   17pt default), for the line that actually says what you get back. */
.ob-sub { font-size: 12.5px; color: var(--tc-faint); letter-spacing: 0.01em; text-wrap: pretty; }
/* Action arrow: hidden until the button is live, slides in on hover. */
.ob-go {
  flex: none; width: 20px; height: 20px; z-index: 1; color: var(--fx);
  opacity: 0; transform: translateX(-5px);
  transition: opacity 200ms var(--ease), transform 200ms var(--ease);
}
.ob-go svg { width: 20px; height: 20px; display: block; }
/* Quiescent (no file yet): dim, inert. Clicks fall through to open the picker. */
/* Disabled without going illegible.

   This used to be a blanket `opacity: 0.5` on the whole button, which put
   .ob-sub at 1.99:1 against the card. Those four sub-labels are the only place
   the page explains what each format gives you, and a first-time visitor reads
   them BEFORE choosing a file, which is exactly when they were faded out.

   A 50% fade cannot be rescued by tuning: --tc-faint on --tc-bg is 4.99:1 at
   full strength, so any meaningful dimming drops it under 4.5:1. So the state
   is carried by the decoration instead: the colour wash and the format icon
   dim, the action arrow stays hidden, and the text keeps its own contrast.
   Disabled controls are exempt from 1.4.3, but the point here is that the copy
   has a job to do while the button is still inert. */
.out-btn:disabled { cursor: default; pointer-events: none; opacity: 1; }
.out-btn:disabled::before { opacity: 0.22; }
.out-btn:disabled .ob-ico { opacity: 0.5; }
.out-btn:disabled .ob-main { color: var(--tc-soft); }   /* 8.5:1 */
.out-btn:disabled .ob-sub { color: var(--tc-faint); }   /* 5.0:1 */
/* Armed: each format is live. Hover lights it up in its own colour and the
   arrow slides in; a tap converts straight to that format. */
.tool-card.armed .out-btn:not(:disabled) .ob-go { opacity: 0.4; transform: none; }
.tool-card.armed .out-btn:not(:disabled):hover,
.tool-card.armed .out-btn:not(:disabled):focus-visible {
  border-color: color-mix(in oklab, var(--fx) 65%, transparent);
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--fx) 14%, transparent),
    color-mix(in oklab, var(--fx) 6%, transparent));
  box-shadow: 0 8px 22px color-mix(in oklab, var(--fx) 24%, transparent);
}
.tool-card.armed .out-btn:not(:disabled):hover::before,
.tool-card.armed .out-btn:not(:disabled):focus-visible::before { opacity: 1; }
.tool-card.armed .out-btn:not(:disabled):hover .ob-go,
.tool-card.armed .out-btn:not(:disabled):focus-visible .ob-go { opacity: 1; transform: none; }
@media (prefers-reduced-motion: no-preference) {
  .tool-card.armed .out-btn:not(:disabled):hover { transform: translateY(-1px); }
  .tool-card.armed .out-btn:not(:disabled):active { transform: translateY(0) scale(0.99); transition-duration: 80ms; }
}
/* Converting: the tapped button carries its own progress in its own colour. */
.out-btn.working {
  border-color: var(--fx); pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--fx) 24%, transparent),
    color-mix(in oklab, var(--fx) 11%, transparent));
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--fx) 45%, transparent),
    0 8px 22px color-mix(in oklab, var(--fx) 26%, transparent);
}
.out-btn.working::before { opacity: 1; }
.out-btn.working .ob-go { opacity: 0; }
.out-btn.working::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 20%, rgba(255, 255, 255, 0.28) 50%, transparent 80%);
  background-size: 250% 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .out-btn.working::after { animation: fp-working 1.1s linear infinite; }
}
@keyframes fp-working { from { background-position: 130% 0; } to { background-position: -130% 0; } }
/* While one converts, the others hold their breath. */
.tool-card.busy .out-btn:not(.working) { opacity: 0.4; }
/* Conversion progress: real upload % (determinate), then an indeterminate sweep
   while the server works — we never fake a percentage for the opaque OCR phase. */
.tc-progress { margin: 12px 0 2px; height: 4px; border-radius: 999px; overflow: hidden;
  background: rgba(255, 255, 255, 0.10); }
.tc-progress > i { display: block; height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--primary), #5fd2a4); transition: width 200ms var(--ease); }
.tc-progress.indeterminate > i { width: 42%; transition: none; }
@media (prefers-reduced-motion: no-preference) {
  .tc-progress.indeterminate > i { animation: fp-progress 1.05s ease-in-out infinite; }
}
@keyframes fp-progress { 0% { transform: translateX(-120%); } 100% { transform: translateX(320%); } }
.status { margin-top: 11px; font-size: 13.5px; color: var(--tc-soft); min-height: 21px; line-height: 1.5; }
.status.err { color: #ff9088; }
.status.ok { color: #6fe0b0; }
.status.warn { color: #f0b24a; }
.again {
  margin-top: 8px; padding: 8px 14px; min-height: 44px;
  display: inline-flex; align-items: center;
  font-family: inherit; font-size: 14px; font-weight: 600;
  color: var(--tc-ink); background: transparent; border: 1px solid var(--tc-line-2);
  border-radius: 9px; cursor: pointer;
  transition: border-color 160ms var(--ease), color 160ms var(--ease), background-color 160ms var(--ease);
}
.again:hover { border-color: #34c188; color: #7be3b6; background: rgba(52, 193, 136, 0.08); }

/* ---------- feature vignette tiles ---------- */
/* text-wrap: balance replaces the three hard <br>s these headings used to
   carry. A <br> is a break authored for one viewport width and wrong at every
   other one; balance lets the browser pick even line lengths at whatever width
   it actually gets. */
.section-title {
  font-size: 32px; text-align: center; margin: 0 0 var(--sp-title);
  text-wrap: balance;
}

/* How-to: three numbered steps in the same card language as the feature tiles. */
.how-steps {
  list-style: none; margin: 0; padding: 0 0 var(--sp-section);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
}
@media (max-width: 760px) { .how-steps { grid-template-columns: 1fr; } }
.how-step {
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow), var(--edge-hi); background: var(--card);
  padding: 28px 26px; display: flex; flex-direction: column; gap: 8px;
}
.how-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 11px; margin-bottom: 6px;
  background: var(--primary-light); color: var(--primary-dark);
  font-weight: 800; font-size: 18px; font-variant-numeric: tabular-nums;
}
.how-step h3 { margin: 0; font-size: 19px; letter-spacing: -0.01em; }
.how-step p { margin: 0; color: var(--ink-soft); font-size: 15.5px; line-height: 1.62; }

/* Languages: all 82 as crawlable text, grouped by script (same card language). */
.lang-intro { text-align: center; max-width: 62ch; margin: -16px auto 32px; color: var(--ink-soft); }
.lang-groups {
  list-style: none; margin: 0; padding: 0 0 var(--sp-section);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px; align-items: start;
}
.lang-group {
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow), var(--edge-hi); background: var(--card); padding: 20px 22px;
}
.lang-group h3 {
  margin: 0 0 8px; font-size: 15px; color: var(--primary-dark);
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.lang-group h3 .count { font-size: 12px; font-weight: 700; color: var(--faint); font-variant-numeric: tabular-nums; }
.lang-group .names { margin: 0; font-size: 14px; line-height: 1.7; color: var(--ink-soft); }
.lang-group .note { margin: 10px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--faint); }
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; padding-bottom: var(--sp-section); }
.tile {
  border: 1px solid rgba(28, 37, 48, 0.10); border-radius: var(--radius);
  box-shadow: var(--shadow), var(--edge-hi); padding: 22px;
  display: flex; flex-direction: column; gap: 10px;
  background:
    radial-gradient(260px 220px at var(--mx, 50%) var(--my, -30%), rgba(14, 138, 95, 0.07), transparent 60%),
    var(--card);
  transition: box-shadow 200ms var(--ease), border-color 200ms var(--ease);
}
html[data-theme="dark"] .tile {
  border-color: var(--line);
  background:
    radial-gradient(260px 220px at var(--mx, 50%) var(--my, -30%), rgba(22, 165, 113, 0.10), transparent 60%),
    var(--card);
}
.tile:hover { border-color: rgba(14, 138, 95, 0.35); box-shadow: 0 10px 28px rgba(16, 38, 30, 0.12), var(--edge-hi); }
html[data-theme="dark"] .tile:hover { border-color: rgba(22, 165, 113, 0.4); box-shadow: 0 10px 28px rgba(0, 0, 0, 0.55), var(--edge-hi); }
.tile { padding: 30px 28px; min-height: 340px; }
.tile .t-ico { color: var(--primary); }
.tile .t-ico svg { width: 26px; height: 26px; display: block; }
/* Big editorial numeral: the tile's focal point, in Fraunces. */
.tile .t-num {
  font-family: "Fraunces", Georgia, serif; font-weight: 600;
  font-size: 54px; line-height: 0.9; letter-spacing: -0.02em;
  color: var(--primary); font-variant-numeric: tabular-nums;
  display: block; margin-bottom: 4px;
}
.tile .t-num small { font-size: 22px; font-weight: 600; margin-left: 2px; color: var(--primary-dark); }
html[data-theme="dark"] .tile .t-num { color: var(--primary-dark); }
.tile h3 { margin: 0; font-size: 20px; font-family: "Fraunces", Georgia, serif; font-weight: 600; letter-spacing: -0.01em; text-wrap: balance; }
.tile p { margin: 2px 0 4px; font-size: 14.5px; line-height: 1.6; color: var(--ink-soft); }
.tile .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.92em; color: var(--ink); }

/* Vignettes: little working-looking UI bits in the popup's visual language. */
.lines-demo {
  margin-top: auto; padding: 14px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--bg);
  display: flex; flex-direction: column; gap: 8px;
}
html[data-theme="dark"] .lines-demo { border-color: rgba(255, 255, 255, 0.08); }
.lines-demo i { display: block; height: 6px; border-radius: 3px; background: rgba(28, 37, 48, 0.16); }
html[data-theme="dark"] .lines-demo i { background: rgba(255, 255, 255, 0.16); }
.lines-demo .last { display: flex; align-items: center; gap: 5px; }
.lines-demo .last i { width: 52%; margin: 0; }
.lines-demo .caret { width: 2px; height: 11px; border-radius: 1px; background: var(--primary); }
@media (prefers-reduced-motion: no-preference) {
  .lines-demo .caret { animation: fp-caret 1.1s steps(2, jump-none) infinite; }
}
@keyframes fp-caret { 50% { opacity: 0; } }

.convert-demo {
  margin-top: auto; padding: 14px 0 4px;
  display: flex; align-items: center; justify-content: center; gap: 12px;
}
.fmt {
  font-size: 11px; font-weight: 700; letter-spacing: 0.04em; color: #fff;
  padding: 4px 9px; border-radius: 6px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
.fmt-pdf { background: #c1574f; }
.fmt-docx { background: #5d88bd; }
.convert-arrows { width: 24px; height: 24px; flex: none; color: var(--primary); transition: transform 250ms var(--ease); }
@media (prefers-reduced-motion: no-preference) {
  .tile:hover .convert-arrows { transform: scaleX(1.25); }
}

.find-demo { margin-top: auto; padding-top: 12px; display: flex; flex-direction: column; gap: 10px; }
.find-pill {
  display: inline-flex; align-items: center; gap: 8px; align-self: flex-start;
  border: 1px solid var(--line); background: var(--card); border-radius: 8px;
  padding: 6px 11px; font-size: 12.5px; font-weight: 600; color: var(--ink);
  box-shadow: 0 1px 3px rgba(16, 38, 30, 0.08);
}
html[data-theme="dark"] .find-pill { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); }
.find-pill svg { width: 13px; height: 13px; color: var(--faint); }
.find-pill .count { color: var(--faint); font-weight: 500; }
.find-line { font-size: 13px; color: var(--ink-soft); }
.find-line mark { background: rgba(234, 179, 8, 0.4); color: inherit; border-radius: 3px; padding: 1px 3px; }
html[data-theme="dark"] .find-line mark { background: rgba(234, 179, 8, 0.35); }

.drop-demo {
  margin-top: auto; padding: 13px 12px;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  border: 1.5px dashed rgba(14, 138, 95, 0.45); border-radius: 10px;
  color: var(--ink-soft); font-size: 13px; font-weight: 600;
  background: rgba(14, 138, 95, 0.04);
}
html[data-theme="dark"] .drop-demo { border-color: rgba(52, 193, 136, 0.4); background: rgba(22, 165, 113, 0.07); }
.drop-demo svg { width: 18px; height: 18px; flex: none; color: var(--primary); }

.priv-demo { margin-top: auto; padding-top: 14px; display: flex; flex-wrap: wrap; gap: 8px; }
.priv-pill {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--ink);
  padding: 5px 12px 5px 8px; border-radius: 999px;
  border: 1px solid rgba(14, 138, 95, 0.3); background: rgba(14, 138, 95, 0.07);
}
html[data-theme="dark"] .priv-pill { border-color: rgba(52, 193, 136, 0.32); background: rgba(22, 165, 113, 0.1); }
.priv-pill::before {
  content: "\2713"; flex: none; width: 16px; height: 16px; border-radius: 50%;
  background: var(--primary); color: #fff; font-size: 10px; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center;
}

.timer-demo { margin-top: auto; padding-top: 14px; display: flex; align-items: center; gap: 12px; }
.timer-pill {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid rgba(14, 138, 95, 0.3); background: rgba(14, 138, 95, 0.07);
  border-radius: 999px; padding: 6px 14px 6px 10px;
}
html[data-theme="dark"] .timer-pill { border-color: rgba(52, 193, 136, 0.32); background: rgba(22, 165, 113, 0.1); }
.timer-pill svg { width: 16px; height: 16px; color: var(--primary); }
.timer-pill b {
  font-family: "Fraunces", Georgia, serif; font-size: 18px; font-weight: 650;
  color: var(--primary-dark); font-variant-numeric: tabular-nums;
}
.timer-note { font-size: 12.5px; color: var(--faint); }

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

/* ---------- comparison ---------- */
.compare { max-width: 860px; margin: 0 auto var(--sp-section); }
.compare-table {
  width: 100%; border-collapse: collapse; overflow: hidden;
  border-radius: 18px; border: 1px solid var(--line);
  background: var(--card); box-shadow: var(--shadow);
}
.compare-table th, .compare-table td {
  padding: 15px 18px; text-align: left; font-size: 15px;
  border-bottom: 1px solid var(--line); vertical-align: middle;
}
.compare-table tr:last-child th, .compare-table tr:last-child td { border-bottom: 0; }
.compare-table thead th { font-family: "Fraunces", Georgia, serif; font-size: 17px; font-weight: 600; }
.compare-table .rowlabel { color: var(--ink-soft); font-weight: 500; width: 40%; }
/* Our column: highlighted rail down the middle. */
.compare-table .col-us {
  background: linear-gradient(180deg, rgba(14, 138, 95, 0.09), rgba(14, 138, 95, 0.05));
  color: var(--ink); font-weight: 600; width: 32%;
  border-left: 1px solid rgba(14, 138, 95, 0.2); border-right: 1px solid rgba(14, 138, 95, 0.2);
}
html[data-theme="dark"] .compare-table .col-us {
  background: linear-gradient(180deg, rgba(22, 165, 113, 0.15), rgba(22, 165, 113, 0.07));
  border-color: rgba(52, 193, 136, 0.28);
}
.compare-table thead .col-us { color: var(--primary-dark); font-size: 18px; }
.compare-table .col-them { color: var(--faint); width: 28%; }
.compare-table .col-us .yes { display: inline-flex; align-items: center; gap: 8px; }
.compare-table .col-us .yes::before {
  content: "\2713"; flex: none; width: 18px; height: 18px; border-radius: 50%;
  background: var(--primary); color: #fff; font-size: 10px; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center;
}
.compare-note { text-align: center; margin: 16px auto 0; font-size: 13px; color: var(--faint); max-width: 620px; }
@media (max-width: 640px) {
  .compare-table th, .compare-table td { padding: 12px 12px; font-size: 13.5px; }
  .compare-table .rowlabel { width: 44%; }
  .compare-table thead .col-us { font-size: 15px; }
  .compare-table thead .col-them { font-size: 13px; }
}

/* ---------- privacy panel ---------- */
.privacy {
  text-align: center;
  background: linear-gradient(180deg, #eaf6f0 0%, #e1f0e9 100%);
  border: 1px solid rgba(14, 138, 95, 0.24);
  border-radius: 20px; padding: 48px 48px 40px;
  max-width: 920px; margin: 0 auto var(--sp-section);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.65), 0 1px 2px rgba(16, 38, 30, 0.04);
}
html[data-theme="dark"] .privacy {
  background: linear-gradient(180deg, #17382a 0%, #102a1f 100%);
  border-color: rgba(52, 193, 136, 0.26);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.privacy-shield {
  display: inline-flex; width: 54px; height: 54px; border-radius: 16px;
  background: var(--primary); color: #fff; align-items: center; justify-content: center;
  margin-bottom: 16px;
}
.privacy-shield svg { width: 28px; height: 28px; }
.privacy h2 { font-size: 32px; margin: 0 0 24px; }
.privacy h2 em { font-style: normal; color: var(--primary-dark); font-weight: 700; }
.privacy ul {
  margin: 0 auto 20px; padding: 0; list-style: none; max-width: 680px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px 40px; text-align: left;
}
.privacy li { display: flex; align-items: flex-start; gap: 12px; font-size: 15px; color: var(--ink); line-height: 1.45; }
.privacy li::before {
  content: "\2713"; flex: none; width: 22px; height: 22px; margin-top: 1px; border-radius: 50%;
  background: var(--primary); color: #fff; font-size: 12px; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center;
}
.privacy > p { margin: 0; font-size: 14px; color: var(--ink-soft); }
.privacy > p a { color: var(--primary-dark); font-weight: 600; }

/* ---------- editorial: what is OCR ---------- */
.editorial { max-width: 720px; margin: 0 auto; padding-bottom: var(--sp-section); }
.editorial h2 { font-size: 32px; text-align: center; margin: 0 0 var(--sp-title); }
.kicker {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--primary-dark); margin: 0 0 10px;
}
.kicker::before, .kicker::after { content: ""; width: 26px; height: 2px; border-radius: 2px; }
.kicker::before { background: linear-gradient(270deg, var(--primary), transparent); }
.kicker::after { background: linear-gradient(90deg, var(--primary), transparent); }
.prose p { margin: 0 0 18px; font-size: 16.5px; color: var(--ink-soft); }
.prose p:last-child { margin-bottom: 0; }
.prose b { color: var(--ink); font-weight: 650; }

/* ---------- FAQ ---------- */
.faq { padding-bottom: var(--sp-section); max-width: 760px; margin: 0 auto; }
.faq h2 { text-align: center; font-size: 32px; margin: 0 0 var(--sp-title); }
/* The padding lives on the summary, not the details. With it on the details,
   the row LOOKED 207px tall but only the 24px summary strip was clickable:
   17px of dead zone above it and 166px below. Material puts this plainly, that
   a touch target extends past an element's visible bounds, so the padding has
   to belong to the thing you tap. */
.faq details {
  border: 1px solid rgba(28, 37, 48, 0.10); border-radius: var(--radius);
  padding: 0; margin-bottom: 12px; box-shadow: var(--edge-hi);
  background:
    radial-gradient(300px 170px at var(--mx, 50%) var(--my, -30%), rgba(14, 138, 95, 0.05), transparent 60%),
    var(--card);
}
html[data-theme="dark"] .faq details {
  border-color: var(--line);
  background:
    radial-gradient(300px 170px at var(--mx, 50%) var(--my, -30%), rgba(22, 165, 113, 0.08), transparent 60%),
    var(--card);
}
.faq summary {
  padding: 16px 20px; min-height: 44px; border-radius: var(--radius);
  font-weight: 700; font-size: 15.5px; cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 8px; height: 8px; margin-right: 2px;
  border-right: 2px solid var(--faint); border-bottom: 2px solid var(--faint);
  transform: rotate(45deg) translateY(-1px);
  transition: transform 200ms var(--ease);
}
.faq details[open] summary::after { transform: rotate(225deg) translateY(-1px); }
@media (prefers-reduced-motion: no-preference) {
  .faq details[open] > p { animation: fp-faq-open 200ms var(--ease); }
}
@keyframes fp-faq-open {
  from { opacity: 0; transform: translateY(-4px); }
}
.faq details p { margin: 0; padding: 0 20px 16px; font-size: 14.5px; color: var(--ink-soft); max-width: 62ch; }

/* ---------- closing CTA ---------- */
.closer { text-align: center; padding-bottom: 72px; }
.closer .section-title { margin-bottom: 22px; }
.cta-btn {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--cta); color: #fff; text-decoration: none;
  border-radius: 11px; padding: 14px 30px; font-size: 19px; font-weight: 700;
  position: relative; overflow: hidden;
  box-shadow: 0 1px 3px rgba(154, 52, 18, 0.25);
  transition: background-color 180ms var(--ease), box-shadow 180ms var(--ease), transform 120ms var(--ease);
}
.cta-btn:hover { background: var(--cta-hover); box-shadow: 0 5px 14px rgba(154, 52, 18, 0.3); }
.cta-btn:active { transform: scale(0.98); box-shadow: 0 1px 3px rgba(154, 52, 18, 0.25); transition-duration: 80ms; }
@media (prefers-reduced-motion: no-preference) {
  .cta-btn::after {
    content: ""; position: absolute; top: 0; left: -75%; width: 45%; height: 100%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.3), transparent);
    transform: skewX(-18deg); transition: left 600ms var(--ease); pointer-events: none;
  }
  .cta-btn:hover::after { left: 130%; }
}
.cta-ico { width: 19px; height: 19px; flex: none; color: #fff; }
.cta-alt { margin: 12px 0 0; font-size: 14px; color: var(--ink-soft); }

/* ---------- responsive ---------- */
@media (max-width: 900px) {
  /* Single column, tool first: headline, the machine itself, then the pitch.
     display:contents lets the lead and follow blocks order around the card. */
  /* minmax(0, 1fr), not 1fr: a bare 1fr floors at the track's min-content, and
     the tool card's min-content is set by the 82-option language select (195px)
     inside .lang-row (269px). At 320px that floored the track at 311px inside a
     264px content box and pushed the card 20px off-screen, where body's
     overflow-x: clip silently amputated it. WCAG 1.4.10 Reflow is measured at
     320 CSS px, so this was a real failure, not a cosmetic one. */
  .hero-panel { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  /* Ragged-right, not centred. The desktop two-column hero is left-aligned;
     only this single-column fallback centred everything, and .sub is a
     six-line, 40-character-per-line paragraph. Centring multi-line body copy
     gives every line a different starting x, so the eye loses the left edge on
     each return sweep. Short headings can carry it; running prose cannot. */
  .hero-copy { display: contents; text-align: start; }
  .hero-lead { order: 1; }
  .tool-card { order: 2; max-width: 560px; width: 100%; margin: 0 auto; }
  .hero-follow { order: 3; }
  .hero-copy .sub { margin: 0 0 18px; }
  .sig { margin: 0 0 16px; }
  .hero-trust { grid-template-columns: max-content; justify-content: start; }
  /* Same reasoning: a 62ch intro paragraph reads as prose, not as a caption. */
  .lang-intro { text-align: start; }
}
@media (max-width: 860px) {
  :root { --sp-section: 56px; --sp-title: 28px; }
  .hero-copy h1 { font-size: clamp(32px, 7.6vw, 40px); }
  .tiles { grid-template-columns: 1fr 1fr; }
  .privacy ul { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .tiles { grid-template-columns: 1fr; }
  .hero-wrap { padding-top: 16px; }
  .hero-panel { border-radius: 18px; }
  /* 19px type inside 30px of side padding left "Try FormsPal OCR, free" about
     241px of room for ~230px of text, so the label broke across lines. A
     button label that wraps stops reading as one thing to press. */
  .cta-btn { width: 100%; justify-content: center; font-size: 17px; padding: 14px 20px; }
  .cta-btn span { text-wrap: nowrap; }
  .privacy { padding: 32px 22px 28px; border-radius: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  html { scroll-behavior: auto !important; }
  .bar i { width: 100%; animation: none !important; opacity: 0.55; }
}

/* ==== FormsPal site footer, rules verbatim from the extension LP (which
   carries them verbatim from ai.formspal.com/page.css). ==== */
@media (max-width: 900px) {
  .foot-cols { grid-template-columns: 1fr 1fr; gap: 24px; }
}
@media (max-width: 560px) {
  .foot-cols { grid-template-columns: 1fr; }
}

/* Shared-frame token map (property-owned): the vendored header/footer read
   --fp-* and follow the page theme. ocr is light-default; the boot script
   always stamps data-theme, so both shared theme states are exercised. */
:root {
  --fp-header-h: 64px;
  --fp-bg: var(--bg);
  --fp-ink: var(--ink);
  --fp-green: var(--primary);
  --fp-green-soft: var(--primary-dark);
  --fp-orange: var(--dc-btn);
  --fp-orange-hover: var(--dc-btn-hover);
  --fp-orange-ink: #ffffff;
  --fp-ease: var(--ease);
}

/* Arrival pill + hinted output: extension handoff (staged, confirm-first). */
.arrival-pill {
  position: fixed; top: calc(var(--fp-header-h, 64px) + 10px); left: 50%;
  translate: -50% 0; z-index: 60;
  display: flex; align-items: center; gap: 8px;
  background: color-mix(in srgb, var(--fp-green, #0e8a5f) 16%, var(--bg, #f7f9fb));
  border: 1px solid color-mix(in srgb, var(--fp-green, #0e8a5f) 50%, transparent);
  color: var(--ink, #1c2530);
  border-radius: 999px; padding: 7px 10px 7px 16px;
  font-size: 13px; font-weight: 600; white-space: nowrap;
  opacity: 1; transition: opacity 300ms var(--fp-ease, ease), translate 300ms var(--fp-ease, ease);
}
.arrival-pill-hide { opacity: 0; translate: -50% -8px; pointer-events: none; }
.arrival-pill-x {
  border: 0; background: none; color: inherit; opacity: .7;
  font-size: 15px; line-height: 1; cursor: pointer; padding: 2px 6px;
}
.arrival-pill-x:hover { opacity: 1; }
.out-btn.hint { outline: 3px solid var(--fp-green, #0e8a5f); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .arrival-pill { transition: opacity 300ms var(--fp-ease, ease); }
  .arrival-pill-hide { translate: -50% 0; }
}

/* fp-shared-frame:start (vendored css; update via scripts/sync-shared-frame.sh) */
/* FormsPal shared header. Scope everything under .site-head (plus :root/html
   for variables and the no-JS fallback). Fleet look: dark-first, green
   primary, orange CTA. Properties override the --fp-* variables. */

/* The sticky bar would otherwise cover whatever a keyboard Tab or an anchor
   jump scrolls to the top of the viewport (WCAG 2.2 SC 2.4.11). */
html {
  scroll-padding-top: calc(var(--fp-header-h, 64px) + 8px);
}

:root {
  --fp-header-h: 64px;
  --fp-ease: cubic-bezier(0.2, 0, 0, 1);
  --fp-dur: 150ms;
}

.site-head {
  position: sticky;
  top: 0;
  z-index: 50;
  /* min-height, not height: if the measured collapse ever fails to fire, a
     wrapped nav grows the bar instead of overlapping the page beneath it.
     Content never exceeds 44px plus padding in the normal case, so the
     rendered height stays 64px and CLS is unchanged. */
  min-height: var(--fp-header-h);
  background: var(--fp-bg, #0b1f17);
  color: var(--fp-ink, #eaf5ef);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  --fp-head-soft: color-mix(in oklab, var(--fp-ink, #eaf5ef) 82%, var(--fp-bg, #0b1f17));
  --fp-head-muted: color-mix(in oklab, var(--fp-ink, #eaf5ef) 70%, var(--fp-bg, #0b1f17));
}
html[data-theme="light"] .site-head {
  background: var(--fp-bg, #f4faf7);
  color: var(--fp-ink, #10231a);
  border-bottom-color: rgba(0, 0, 0, 0.08);
  --fp-head-soft: color-mix(in oklab, var(--fp-ink, #10231a) 82%, var(--fp-bg, #f4faf7));
  --fp-head-muted: color-mix(in oklab, var(--fp-ink, #10231a) 70%, var(--fp-bg, #f4faf7));
}

/* The frame owns the box model of its own padded controls. Every control
   that combines padding with a 44px floor would otherwise render at
   44 + padding wherever the host page ships no reset: measured on a page
   with none, .site-cta, .site-nav a and .site-drop-list a all came out at
   60px instead of 44. Five properties ship a global reset, but
   formspal-legal-tools scopes its own to `.lp *` and `.dc-app *` and the
   frame sits at body level outside both, so the same markup rendered two
   different bars across the fleet. It is also latent breakage: the
   collapsed panel is positioned at top: var(--fp-header-h), so a property
   that lowered that token would grow the bar past it while the panel
   stayed put. <button> already gets border-box from the UA sheet; the
   anchors do not, and the frame should not depend on either.

   .site-nav-wrap is in this list for the same reason at a different scale.
   It is not a 44px control, but it is the one box here where padding meets
   a viewport-relative bound: collapsed, it carries
   max-height: calc(100vh - var(--fp-header-h)) together with
   padding: 8px 16px 16px. Under content-box those add rather than nest, so
   the panel's border box is the max-height plus 24px of padding plus its
   1px border. Measured at 700x600 the collapsed panel's bottom landed at
   625 against a 600px viewport, 25px past the fold, and the overshoot is
   the part holding the last row of links. Border-box makes the bound mean
   what it says. This one predates the 44px floors and is identical in
   v0.7.1, but the rule above claims the frame owns the box model of its own
   padded boxes, and this is the box where the claim pays. */
.site-head .site-cta,
.site-head .site-nav a,
.site-head .site-drop-btn,
.site-head .site-menu-btn,
.site-head .site-drop-list a,
.site-head .site-drop-list span[aria-current],
.site-head .site-nav-wrap,
/* The frame's own layout containers must not inherit the host page's box model.
   A property whose reset is scoped (e.g. `.lp * { box-sizing: border-box }`)
   leaves these in content-box, where max-width applies to the CONTENT box and
   the 16px padding is added on top: the bar then renders 32px wider than the
   footer's matching 1120px container and the two land on different edges. */
.site-head-inner {
  box-sizing: border-box;
}

.site-head-inner {
  max-width: 1120px;
  min-height: var(--fp-header-h);
  margin: 0 auto;
  padding: 0 16px;
  display: flex;
  align-items: center;
  gap: 20px;
}

.site-head .site-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  /* 44px floor: Apple HIG's default control size, and WCAG 2.5.5 AAA. The
     64px bar absorbs a 44px control with no change to its own height.
     min-width is deliberately NOT set here: on a flex item it would replace
     the automatic minimum size (min-width: auto, i.e. min-content) and let
     the brand be squeezed below its own nowrap content. Measured at 480px
     with the app name "Statute of Limitations", a 44px floor gave an 85px
     box around 202.6px of content: the trailing text ran out over the
     hamburger and, with justify-content: center, the logo mark clipped off
     the left edge. The floor is needed only below 430px, where the wordmark
     and app name are both hidden and the 28px mark alone would be the whole
     target, so it lives in that breakpoint with the centering it needs. */
  min-height: 44px;
  color: inherit;
  text-decoration: none;
  font-size: 17px;
  white-space: nowrap;
}
.site-head .site-brand svg { width: 28px; height: 28px; flex: none; }
.site-head .site-brand .app {
  color: var(--fp-head-soft);
  font-weight: 500;
}

.site-head .site-nav-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  flex: 1;
}

.site-head .site-dropdown { position: relative; }

.site-head .site-drop-btn {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  gap: 4px;
  font: inherit;
  font-size: 14px;
  color: inherit;
  background: none;
  border: 0;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
}
.site-head .site-drop-btn:hover,
.site-head .site-drop-btn[aria-expanded="true"] {
  background: rgba(255, 255, 255, 0.08);
}
html[data-theme="light"] .site-head .site-drop-btn:hover,
html[data-theme="light"] .site-head .site-drop-btn[aria-expanded="true"] {
  background: rgba(0, 0, 0, 0.06);
}
.site-head .site-drop-btn .caret { width: 14px; height: 14px; }

.site-head .site-drop-list {
  list-style: none;
  margin: 0;
  padding: 6px;
}
.site-head .site-drop-list a,
.site-head .site-drop-list span[aria-current] {
  display: block;
  padding: 8px 12px;
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
  font-size: 14px;
  white-space: nowrap;
}
.site-head .site-drop-list a:hover {
  background: var(--fp-green, #0e8a5f);
  color: #fff;
}
.site-head .site-drop-list span[aria-current] { color: var(--fp-head-muted); }

/* JS-enabled: dropdowns collapse into popovers. Without the fp-js class
   (JS disabled or failed) the lists stay in normal flow, fully visible. */
html.fp-js .site-head .site-drop-list {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 230px;
  background: var(--fp-bg, #0e2a1f);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
}
html[data-theme="light"].fp-js .site-head .site-drop-list {
  background: var(--fp-bg, #ffffff);
  border-color: rgba(0, 0, 0, 0.1);
}
html.fp-js .site-head .site-dropdown.open .site-drop-list { display: block; }

.site-head .site-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  /* Never overflow: hidden here. It converts "does not fit" into "silently
     disappears": measured at 768px the nav wanted 244px, got 79px, and lost
     two links entirely with no scrollbar to hint at it. header.js decides
     fit now. Wrapping is the visible, debuggable fallback. */
  flex-wrap: wrap;
}
.site-head .site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: inherit;
  text-decoration: none;
  font-size: 14px;
  padding: 8px 10px;
  border-radius: 8px;
  white-space: nowrap;
}
.site-head .site-nav a:hover { background: rgba(255, 255, 255, 0.08); }
html[data-theme="light"] .site-head .site-nav a:hover { background: rgba(0, 0, 0, 0.06); }

.site-head .site-right {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  flex: none;
}

.site-head .site-menu-btn {
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: inherit;
  background: none;
  border: 0;
  padding: 8px;
  border-radius: 8px;
  cursor: pointer;
  margin-left: auto;
}
.site-head .site-menu-btn svg { width: 22px; height: 22px; display: block; }

/* No-JS fallback (all widths): without the fp-js class the dropdown lists
   stay in normal flow as plain visible link lists, so the bar can no longer
   hold a fixed height. It grows instead, and the nav wraps to its own full
   width row below the brand, which itself stacks when it runs out of width.
   The hamburger never appears without JS, so nothing here may be gated on
   the collapse class: only header.js sets it. This path is not the rare
   one it sounds like. ocr-web and pdf-extension both load header.js with
   defer, against the documented contract, so it is what paints on every
   page load there until the script runs. */
html:not(.fp-js) .site-head {
  height: auto;
  min-height: var(--fp-header-h);
}
html:not(.fp-js) .site-head .site-head-inner {
  flex-wrap: wrap;
  height: auto;
  padding: 8px 16px;
}
html:not(.fp-js) .site-head .site-nav-wrap {
  flex-basis: 100%;
  /* The panel has to stack here, not under html.fp-nav-collapsed. Only
     header.js ever sets that class, so with no script the wrap stayed a
     single unwrapped row: measured at 375px with fp-js absent, the document
     was 527px wide against a 375px viewport, and the wrap itself 511px
     inside a 343px box. That is the reflow failure (WCAG 1.4.10, measured
     at 320px) the 719px media block used to cover, because it applied
     whether or not fp-js was present.

     Wrapping rather than an unconditional column, and rather than a second
     breakpoint: nothing without JS can measure fit, and the fit point is
     property-owned (nav copy, page-nav slot). Wrap answers it from the
     content at every width. The groups sit side by side while they fit
     (at 1280px the no-JS bar is still the same single row it was) and
     stack when they do not, which is what the removed block did below
     719px. */
  flex-wrap: wrap;
  /* Bounded like the JS panel: without this the stacked groups make a
     header taller than the phone showing it. */
  max-height: calc(100vh - var(--fp-header-h));
  overflow: auto;
}
html:not(.fp-js) .site-head .site-menu-btn {
  display: none;
}

/* Collapsed: one hamburger; dropdown groups and page nav stack in a panel.
   Height stays fixed and the panel overlays below the bar (no CLS).

   Driven by a class rather than a width because the fit point is not a
   constant. It moves with the nav copy, the CTA label, and anything a
   property puts in .site-right, including the plan pill that only appears
   after sign-in. header.js sets this class from a real measurement. */
html.fp-nav-collapsed .site-head .site-menu-btn { display: inline-flex; }
html.fp-nav-collapsed .site-head .site-nav-wrap {
  display: none;
  position: absolute;
  top: var(--fp-header-h);
  left: 0;
  right: 0;
  flex-direction: column;
  align-items: stretch;
  background: var(--fp-bg, #0b1f17);
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  padding: 8px 16px 16px;
  max-height: calc(100vh - var(--fp-header-h));
  overflow: auto;
}
html[data-theme="light"].fp-nav-collapsed .site-head .site-nav-wrap { background: var(--fp-bg, #f4faf7); }
html.fp-nav-collapsed .site-head.menu-open .site-nav-wrap { display: flex; }
html.fp-js.fp-nav-collapsed .site-head .site-drop-list,
html.fp-js.fp-nav-collapsed .site-head .site-dropdown.open .site-drop-list {
  position: static;
  display: block;
  min-width: 0;
  border: 0;
  box-shadow: none;
  background: none;
}
html.fp-nav-collapsed .site-head .site-drop-btn { pointer-events: none; }
html.fp-nav-collapsed .site-head .site-drop-btn .caret { display: none; }
html.fp-nav-collapsed .site-head .site-nav { flex-direction: column; align-items: stretch; }
/* There is deliberately no html:not(.fp-js).fp-nav-collapsed rule here.
   header.js adds fp-js at execute time and fp-nav-collapsed only after
   that, so the combination cannot occur and any rule written for it is
   dead code that reads like the no-JS fallback while doing nothing. The
   no-JS layout lives in one place, the html:not(.fp-js) block above. */

/* The hamburger belongs with the other controls, not adrift mid bar.
   .site-menu-btn and .site-right both carry margin-left: auto, and flexbox
   splits the free space between two auto margins: measured at 768px the
   brand ended at x=171.9, the hamburger sat at x=284.6 and the right
   cluster started at x=441.2, leaving 92.6px of dead space on each side.
   Dropping the right cluster's auto margin while collapsed hands all the
   free space to the hamburger's own, so the bar reads the way it does
   expanded: brand left, controls right. Scoped to the collapsed state
   because .site-right's auto margin is what right-aligns the cluster when
   the nav is a normal flex item.

   The coupling this creates: while collapsed, .site-right is right-aligned
   only because the hamburger's auto margin is still in the row absorbing
   the free space. Take the button out of the markup, or have a property
   force it display: none while collapsed, and nothing pushes: the cluster
   slides left from x=441.2 to x=191.9 and sits mid bar. No property in the
   fleet does either today, and the frame ships the button in header.html,
   so this is a note for whoever changes that, not a live bug. */
html.fp-nav-collapsed .site-head .site-right { margin-left: 0; }

/* Hallmark · component: header right-side controls · genre: modern-minimal
 * theme: FormsPal fleet tokens (--fp-*)
 * states: default · hover · focus-visible · active (loading/error/success N/A for nav)
 * Right-side controls: shared base styles. Properties may override, but the
 * bar ships finished. */

.site-head .site-drop-btn .caret {
  transition: transform var(--fp-dur) var(--fp-ease);
}
.site-head .site-drop-btn[aria-expanded="true"] .caret {
  transform: rotate(180deg);
}

.site-head .site-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  color: inherit;
  cursor: pointer;
  transition: background-color var(--fp-dur) var(--fp-ease);
}
.site-head .site-theme-toggle svg {
  width: 18px;
  height: 18px;
  display: block;
  stroke: currentColor;
}
.site-head .site-theme-toggle .moon { display: none; }
html[data-theme="light"] .site-head .site-theme-toggle .sun { display: none; }
html[data-theme="light"] .site-head .site-theme-toggle .moon { display: block; }
.site-head .site-theme-toggle:hover { background: rgba(255, 255, 255, 0.08); }
html[data-theme="light"] .site-head .site-theme-toggle:hover { background: rgba(0, 0, 0, 0.06); }
.site-head .site-theme-toggle:active { transform: translateY(1px); }

.site-head .site-cta {
  display: inline-flex;
  align-items: center;
  /* The frame owns this button's box, so it owns the containing block for
     anything a property decorates it with. Two properties add a ::after gleam
     that sweeps on hover, sized in percentages. Without position: relative
     those percentages resolved against .site-head, which is sticky and
     therefore the nearest positioned ancestor: the gleam came out 630px wide
     and 64px tall on a 150x44 button, and swept the full width of the bar.
     overflow: hidden then keeps it inside the rounded rect. Harmless for
     properties that add no decoration. */
  position: relative;
  overflow: hidden;
  min-height: 44px;
  padding: 8px 14px;
  border-radius: 10px;
  background: var(--fp-orange, #ef8b2d);
  color: var(--fp-orange-ink, #1c1206);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--fp-dur) var(--fp-ease), transform var(--fp-dur) var(--fp-ease);
}
.site-head .site-cta:hover { background: var(--fp-orange-hover, #f79c47); }
.site-head .site-cta:active { transform: translateY(1px); }

.site-head .site-theme-toggle:focus-visible,
.site-head .site-cta:focus-visible,
.site-head .site-drop-btn:focus-visible,
.site-head .site-menu-btn:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .site-head .site-drop-btn .caret,
  .site-head .site-theme-toggle,
  .site-head .site-cta {
    transition-duration: 0.01ms;
  }
}

/* Design elevation: glass bar, live tier badge, dropdown entrance.
   All motion is transform/opacity only and collapses under reduced motion. */

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  html.fp-js .site-head {
    background: color-mix(in oklab, var(--fp-bg, #0b1f17) 86%, transparent);
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    backdrop-filter: blur(12px) saturate(1.4);
  }
  html[data-theme="light"].fp-js .site-head {
    background: color-mix(in oklab, var(--fp-bg, #f4faf7) 86%, transparent);
  }
}

.site-head .site-brand svg {
  transition: transform var(--fp-dur) var(--fp-ease);
}
.site-head .site-brand:hover svg {
  transform: rotate(-4deg) scale(1.06);
}

.site-head .tier-badge[hidden] { display: none; }
.site-head .tier-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: inherit;
  white-space: nowrap;
  border: 1px solid color-mix(in oklab, var(--fp-green, #0e8a5f) 45%, transparent);
  background: color-mix(in oklab, var(--fp-green, #0e8a5f) 14%, transparent);
}
.site-head .tier-dot {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--fp-green-soft, #34d399);
}
.site-head .tier-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: inherit;
  animation: fp-live 2.4s var(--fp-ease) infinite;
}
@keyframes fp-live {
  0% { transform: scale(1); opacity: 0.7; }
  70%, 100% { transform: scale(2.6); opacity: 0; }
}

html.fp-js .site-head .site-dropdown.open .site-drop-list {
  animation: fp-drop 160ms var(--fp-ease);
}
@keyframes fp-drop {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .site-head .tier-dot::after,
  html.fp-js .site-head .site-dropdown.open .site-drop-list {
    animation: none;
  }
  .site-head .site-brand svg {
    transition-duration: 0.01ms;
  }
}

/* Narrow screens: the bar sheds furniture in priority order (logo, hamburger,
   CTA, toggle, plan pill) instead of overflowing. Without this the right
   cluster keeps its full width and forces horizontal page scroll. */
@media (max-width: 560px) {
  .site-head .site-head-inner { gap: 12px; padding: 0 14px; }
  .site-head .site-brand b { display: none; }
  .site-head .site-cta { padding: 8px 12px; font-size: 13.5px; }
  .site-head .site-right { gap: 8px; min-width: 0; }
}
/* The 44px hit regions are 30px wider than what they replaced, and until
   this block paid for them the collapsed bar simply overflowed. Against
   v0.7.1 at a 320px viewport: brand 28 to 44, hamburger 38 to 44, theme
   toggle 36 to 44. The row ran to x=343.5 where v0.7.1 ended it at 313.5,
   and the document read 320/343 (23px of horizontal scroll) where v0.7.1
   read 320/320. That is a WCAG 1.4.10 reflow failure at the reference
   width, and it only appears with the plan pill shown, which is the state
   this release exists for: ocr-web ships the badge hidden and reveals it
   after sign-in, so it was signed-in phone users who got the scrollbar.

   The 30px comes back out of spacing and pill chrome, never out of a hit
   region. Each number continues a ladder the wider blocks already walk:
   inner gap 20/12/8, inner padding 16/14/10, .site-right gap 10/8/6.
   Collapsed, the row is brand + hamburger + cluster, so the inner gap is
   spent twice and only the LEFT inner padding moves the far edge that
   decides scrollWidth. Budget at 320px, pill shown: 10 + 44 + 8 + 44 + 8 +
   (9 + 6 + 44 + 6 + 134.5) = 313.5, back to where v0.7.1 had it, with
   every control still 44px. */
@media (max-width: 430px) {
  .site-head .site-head-inner { gap: 8px; padding: 0 10px; }
  .site-head .site-brand .app { display: none; }
  /* Only here is the brand small enough to need the floor: wordmark and app
     name are both gone and the 28px mark alone would be the target. Above
     this width the nowrap content is already wider than 44px, so declaring
     the floor there only broke the automatic minimum size. */
  .site-head .site-brand { min-width: 44px; justify-content: center; }
  .site-head .site-right { gap: 6px; }
  /* The pill is already only a dot here: .tier-label goes to display: none
     just below, so the border, background and 7px of side padding are a
     ring around a 7px dot and 14px of the row. Shed the ring, keep the
     indicator. The dot and its live pulse both survive, so a signed-in user
     still sees plan status, and the badge keeps its title attribute. The
     pill is last in the priority order at the head of this narrow-screen
     section, and the ring is chrome rather than content, which is why it
     goes before any 44px control is touched. */
  .site-head .tier-badge {
    padding: 0;
    gap: 0;
    border-color: transparent;
    background: none;
  }
  .site-head .tier-label { display: none; }
  .site-head .site-cta { padding: 7px 10px; font-size: 13px; }
}

/* Stacked rows get the floor only where the frame is actually thumbed. Above
   900px the dropdown keeps its denser pointer rhythm: rows are 33px tall
   and 230px+ wide, clearing WCAG 2.5.8 AA on size alone, no exception
   needed. */
@media (max-width: 900px) {
  .site-head .site-drop-list a,
  .site-head .site-drop-list span[aria-current] {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
}

/* FormsPal shared footer. Scope everything under .site-foot (plus html for
   theme variants). Dark-first; properties override the --fp-* variables.
   No JS: the footer is fully static. */

.site-foot {
  background: var(--fp-bg, #0b1f17);
  color: var(--fp-ink, #eaf5ef);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  /* Dimmed text uses mixed colors, never opacity. Opacity dims toward
     whatever is behind: that keeps contrast on a dark backdrop and destroys
     it on a light one, which is how the light theme fell under 4.5:1. */
  --fp-foot-soft: color-mix(in oklab, var(--fp-ink, #eaf5ef) 85%, var(--fp-bg, #0b1f17));
  --fp-foot-label: color-mix(in oklab, var(--fp-ink, #eaf5ef) 78%, var(--fp-bg, #0b1f17));
  --fp-foot-muted: color-mix(in oklab, var(--fp-ink, #eaf5ef) 70%, var(--fp-bg, #0b1f17));
  --fp-foot-link: color-mix(in oklab, var(--fp-green, #0e8a5f) 45%, #fff);
}
html[data-theme="light"] .site-foot {
  /* Fallbacks must flip with the theme too: a property that does not define
     --fp-ink/--fp-bg would otherwise dim light-theme text using the dark
     default ink and land at ~1.5:1. */
  --fp-foot-soft: color-mix(in oklab, var(--fp-ink, #10231a) 85%, var(--fp-bg, #f4faf7));
  --fp-foot-label: color-mix(in oklab, var(--fp-ink, #10231a) 78%, var(--fp-bg, #f4faf7));
  --fp-foot-muted: color-mix(in oklab, var(--fp-ink, #10231a) 70%, var(--fp-bg, #f4faf7));
  --fp-foot-link: color-mix(in oklab, var(--fp-green, #0e8a5f) 72%, #000);
}
html[data-theme="light"] .site-foot {
  background: var(--fp-bg, #f4faf7);
  color: var(--fp-ink, #10231a);
  border-top-color: rgba(0, 0, 0, 0.08);
}

/* Same reasoning as .site-head-inner in header.css: own the box model rather
   than inheriting whatever reset the host page happens to have. */
.site-foot .foot-cols,
.site-foot .foot-bottom-inner,
.site-foot .foot-ghost {
  box-sizing: border-box;
}

.site-foot .foot-cols {
  max-width: 1120px;
  margin: 0 auto;
  padding: 40px 16px 28px;
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr;
  gap: 28px;
}

.site-foot .foot-brand svg { width: 34px; height: 34px; }
.site-foot .foot-brand b {
  display: inline-block;
  margin-left: 8px;
  font-size: 17px;
  vertical-align: super;
}
.site-foot .foot-brand p {
  font-size: 14px;
  line-height: 1.5;
  color: var(--fp-foot-soft);
  margin: 10px 0;
}
.site-foot .foot-brand a {
  color: var(--fp-foot-link);
  text-decoration: none;
  font-size: 14px;
}
.site-foot .foot-addr {
  font-style: normal;
  font-size: 13px;
  color: var(--fp-foot-label);
  margin-top: 12px;
  line-height: 1.5;
}
.site-foot .foot-addr strong { display: block; }

.site-foot .foot-col .foot-col-title {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fp-foot-label);
  margin: 4px 0 12px;
  font-weight: 600;
}
.site-foot .foot-col ul { list-style: none; margin: 0; padding: 0; }
.site-foot .foot-col li { margin: 0 0 9px; }
.site-foot .foot-col a {
  color: var(--fp-foot-soft);
  text-decoration: none;
  font-size: 14px;
}
.site-foot .foot-col a:hover { color: var(--fp-foot-link); }
.site-foot .foot-col span[aria-current] { font-size: 14px; color: var(--fp-foot-muted); }

.site-foot .foot-bottom { border-top: 1px solid rgba(255, 255, 255, 0.08); }
html[data-theme="light"] .site-foot .foot-bottom { border-top-color: rgba(0, 0, 0, 0.08); }
.site-foot .foot-bottom-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 14px 16px 18px;
  font-size: 13px;
  color: var(--fp-foot-soft);
}
.site-foot .foot-disclaimer { margin: 0 0 10px; line-height: 1.55; }
.site-foot .foot-legal { display: block; }
.site-foot .foot-legal a {
  color: inherit;
  text-decoration: none;
  margin-right: 14px;
}
.site-foot .foot-legal a:hover { color: var(--fp-foot-link); }

/* The frame owns focus for its own components: a property that ships no
   global focus style (or resets outlines) must not lose the focus ring. */
.site-foot a:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  border-radius: 4px;
}

@media (max-width: 900px) {
  .site-foot .foot-cols { grid-template-columns: 1fr 1fr; }
  .site-foot .foot-brand { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
  .site-foot .foot-cols { grid-template-columns: 1fr; }
}

/* Match the header's gutter scale. The bar narrows to 14px then 10px so it can
   shed furniture instead of overflowing, but the footer stayed at a flat 16px,
   so footer content sat 2px then 6px inboard of the brand directly above it.
   Two gutters on one page is visible as a broken alignment line on any phone. */
@media (max-width: 560px) {
  .site-foot .foot-cols,
  .site-foot .foot-bottom-inner,
  .site-foot .foot-ghost { padding-inline: 14px; }
}
@media (max-width: 430px) {
  .site-foot .foot-cols,
  .site-foot .foot-bottom-inner,
  .site-foot .foot-ghost { padding-inline: 10px; }
}

/* Design elevation: signature top rule, heading accent ticks, link
   micro-shift, ghost wordmark half-cropped behind the bottom bar. */

.site-foot {
  border-top: 2px solid var(--fp-green, #0e8a5f);
}
.site-foot .foot-col .foot-col-title::before {
  content: "";
  display: block;
  width: 18px;
  height: 2px;
  margin-bottom: 8px;
  background: var(--fp-green, #0e8a5f);
}
.site-foot .foot-col a {
  display: inline-block;
  transition: color var(--fp-dur, 150ms) var(--fp-ease, ease-out), transform var(--fp-dur, 150ms) var(--fp-ease, ease-out);
}
.site-foot .foot-col a:hover {
  transform: translateX(2px);
}
.site-foot .foot-ghost {
  max-width: 1120px;
  margin: 8px auto -0.4em;
  padding: 0 16px;
  font-weight: 800;
  font-size: clamp(40px, 13vw, 190px);
  white-space: nowrap;
  line-height: 1;
  letter-spacing: -0.045em;
  opacity: 0.05;
  user-select: none;
  pointer-events: none;
  overflow-wrap: anywhere;
}
.site-foot .foot-bottom {
  position: relative;
  background: var(--fp-bg, #0b1f17);
}
html[data-theme="light"] .site-foot .foot-bottom {
  background: var(--fp-bg, #f4faf7);
}
@media (prefers-reduced-motion: reduce) {
  .site-foot .foot-col a { transition-duration: 0.01ms; }
}

/* Footer rows are 14px type on a 9px rhythm: a 16.5px box at 25.5px pitch.
   That clears WCAG 2.5.8 AA on the spacing exception but sits well under the
   44px Apple asks for. Raised only where the footer is thumbed; above 900px
   the columns keep their denser desktop rhythm. */
/* A second @media (max-width: 900px) block on purpose: keep it separate
   from the one above. The "design elevation" section earlier in this file
   sets .site-foot .foot-col a { display: inline-block } at equal
   specificity. Merging these rules up there would put them before that one
   in source order, so inline-block would win the cascade and silently
   shrink the 44px row back down to a text-width link. */
@media (max-width: 900px) {
  .site-foot .foot-col li { margin: 0; }
  .site-foot .foot-col a,
  .site-foot .foot-col span[aria-current] {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
  /* Width needs the floor too: these are short words, and a hit region is
     44x44, not 44 tall. Measured at 880px before this rule: Privacy 44.19,
     Cookies 48.64, Terms 37.21, CCPA 34.76, DMCA 38.32. They are inline-flex
     boxes on a line box, so widening them pushes their neighbours along the
     row instead of changing any layout around it. */
  .site-foot .foot-legal a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    margin-right: 18px;
  }
}
/* fp-shared-frame:end */

/* Two columns, not one, once the rows are 44px tall.

   Raising every footer link to a 44px hit region added roughly 370px to the
   page on its own, and the frame drops the columns to a single stack at 560px.
   Two columns halve that back without giving any of it up: at 375px each
   column is about 160px, which is comfortable for link text this short, and
   the 44px rows are untouched. Beats the vendored single-column rule on both
   specificity and source order. */
@media (max-width: 560px) {
  .site-foot .foot-cols { grid-template-columns: 1fr 1fr; gap: 20px 16px; }
}
