/* =============================================================================
   TravelPdfPro — THE WHOLE MARKETING SITE, ONE STYLESHEET
   =============================================================================
   Five pages share this file: the umbrella landing at `/`, the Visa PDF
   Compressor's landing at `/visa-pdf-compressor/`, and `/privacy`, `/terms`,
   `/contact`. It was named "the landing page" when there was one of them; T2b
   (D11) made the site a suite, and the header said so a build too late — the
   brand-name check in build-site.js caught this comment, which is the smallest
   possible demonstration of why that check exists.

   Lifted from docs/visapdfpro-landing-mockup.html, which is the locked pixel
   reference (Blueprint §3) — the filename keeps the old name because it is an
   internal identifier, and those deliberately did not move in the rename.
   Everything here that is not in that file is marked ADDED and says why.

   WHY THIS DOES NOT IMPORT src/styles/tokens.css
   It is the same palette, deliberately duplicated, and that is the point of the
   Phase 7 structure: the marketing site is a static artefact with no build step
   and no dependency on the app, and the app never serves marketing content. Two
   worlds, one deploy. A shared stylesheet would put the landing page's rendering
   behind webpack and make `/` depend on the thing `/` exists to compensate for.

   The values below and tokens.css both come from the same locked mockups, so
   they cannot disagree about what navy is — but if one ever moves, BOTH change.
   ============================================================================= */

/* =============================================================================
   FONTS — SELF-HOSTED                                       (ADDED, Phase 7 T2)
   =============================================================================
   These used to come from fonts.googleapis.com. On a page whose headline is
   "Your documents never leave your device", a third-party font request is a
   contradiction the visitor cannot see: it hands their IP address and user-agent
   to Google before a word of the privacy copy has been read, and it would have
   had to be disclosed in the very policy this task writes. Self-hosting deletes
   the disclosure and the request together — the marketing site now makes NO
   third-party network call of any kind.

   ⚠ THE APP AT /app STILL LOADS THESE FROM GOOGLE. `public/index.html` has its
   own <link> to fonts.googleapis.com, it is out of this task's scope (site/ and
   scripts/ only), and so /privacy discloses it — narrowed to the app, which is
   where it is still true. Fixing that is a two-line change plus a copy of this
   folder into public/; until then the disclosure is the honest half of this.

   WHERE THE FILES CAME FROM — reproduce with:
     curl -A "<a modern browser UA>" \
       "https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=IBM+Plex+Mono:wght@500;600&display=swap"
   and fetch the woff2 URLs it names. The UA matters: Google serves woff2 only to
   browsers that say they can read it, and ancient formats to anything else.

   INTER IS THE VARIABLE FONT — one file covers weights 100–900, which is why six
   static weights (400/500/600/700/800/900) became one 48 KB request. IBM Plex
   Mono has no variable build on Google Fonts, so its two weights are two files.
   Both are SIL OFL 1.1; the licence text ships beside the files in this folder,
   which is what that licence asks for.

   latin AND latin-ext are both here, and only the ones a page actually needs are
   ever downloaded — that is what `unicode-range` is for. An English page pulls
   inter-var-latin + the two ibm-plex-mono-*-latin files, ~78 KB, and never asks
   for the -ext files at all. They cost repository bytes, not page weight, and
   T3's articles are the reason to keep them.

   `font-display: swap` is Google's own default for these and is kept: text
   renders immediately in the fallback and re-renders when the font lands. The
   alternative, `block`, hides the hero headline for up to 3 seconds.

   NOT PRELOADED, deliberately. A <link rel="preload"> would shave a round trip
   off the first paint and would put these file paths in all four HTML files,
   where a typo is a silent no-op that only shows up in a console warning. One
   copy of the path, in the stylesheet that uses it.
   ============================================================================= */

/* Inter — variable, 100–900 */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/inter-var-latin.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;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/inter-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* IBM Plex Mono — 500 and 600, the only two weights this site uses */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-500-latin.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;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-600-latin.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;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --navy: #0f2557;
  --navy-deep: #0a1a3f;
  --ink: #1b2437;
  --slate: #5a6478;
  --line: #e3e7ef;
  --bg: #f6f8fb;
  --card: #ffffff;
  --green: #0fa36b;
  --green-soft: #e6f6ef;
  --red: #d64545;
  --red-soft: #fbeaea;
  --amber: #b97a0f;
  --radius: 14px;
  --mono: 'IBM Plex Mono', ui-monospace, Consolas, monospace;

  /* ADDED — from src/styles/tokens.css, which has it and the mockup's :root
     does not. Used only by the "arriving later" footer items, which have to sit
     visibly below --slate or they read as ordinary links. */
  --muted: #9aa3b5;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
}
body {
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  background: #fff;
  color: var(--ink);
}

/* ADDED — the mockup animates nothing, but it does ask the page to scroll
   smoothly, and that is a motion preference somebody may have turned off. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

/* ADDED — the mockup has no focus styles at all. Every CTA on this page is a
   link, so without this the entire page is unusable from a keyboard. */
a:focus-visible,
summary:focus-visible {
  outline: 3px solid rgba(15, 37, 87, 0.35);
  outline-offset: 2px;
  border-radius: 6px;
}

.wrap {
  max-width: 1040px;
  margin: 0 auto;
  padding: 0 24px;
}

/* nav */
header {
  position: sticky;
  top: 0;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
  z-index: 20;
}
.nav {
  height: 66px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.logo {
  display: flex;
  align-items: center;
  font-weight: 800;
  font-size: 19px;
  letter-spacing: -0.02em;
  color: var(--navy);
}

/* THE WORDMARK — "Travel" navy, "PDF" green, "Pro" reversed out of a green
   badge. There is no tile: the lockup on every marketing surface is the word
   alone. The mark is not retired — it is the favicon set, assets/mark.svg, and
   the app's admin sidebar, which draws its own 30px tile because it collapses
   to an icon rail with no wordmark beside it. This is the CSS twin of the
   lockup drawn in scripts/generate-brand-assets.js; the app draws it a THIRD
   time in src/components/Logo.css, because the two worlds share no stylesheet
   by design (D10). If one moves, move all three. Every ratio below has a named
   constant over there.

   `.word` IS STILL LOAD-BEARING — for a different reason than the one it was
   written for, so do not read it as a leftover and delete it.

   It was written for the GAP. `.logo` carried `gap: 10px` to space the tile,
   and flex wraps each contiguous run of child text in an anonymous item — so
   the bare "TravelPdf" text node and `.pro` were two flex items and the header
   SHIPPED reading "TravelPdf Pro", live, on every page, through two owner
   passes. Splitting the word into three coloured parts would have made it two
   such holes.

   That gap is now DELETED rather than zeroed or left standing with nothing to
   space: a dormant `gap` on this container is the same trap re-armed for
   whoever adds the next element to the lockup, and it would spring the same
   way — silently, looking like letter-spacing somebody chose.

   What keeps `.word` here is `align-items: center` on this rule. The badge is a
   flex item of the WORD, so it is centred on the wordmark's own box — the cap
   band — rather than on whatever else the lockup row comes to contain. */
.logo .word {
  display: flex;
  align-items: center;
}
.logo .pdf {
  color: var(--green);
}

/* The badge fills the wordmark's CAP BAND: top on the cap line, bottom on the
   baseline. `align-items: center` on `.word` is what puts it there — for Inter
   the em box's centre and the cap band's centre are 0.0005em apart, so centring
   the box centres the caps and no vertical nudge is needed at any size.

   ⚠ `em` in this rule resolves against THIS rule's font-size — 0.68 of the
   wordmark's — so each length is the wordmark figure ÷ 0.68. The comments give
   the wordmark figure, which is the one that matches the generator. */
.logo .pro {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.68em; /* "slightly smaller" than the wordmark */
  height: 1.069em; /* 0.727 wordmark-em — Inter's cap height */
  padding: 0 0.34em;
  margin-left: 0.206em; /* 0.14 wordmark-em */
  border-radius: 0.3em; /* 0.28 of the badge's own height */
  background: var(--green);
  color: #fff;
}
.nav-links {
  display: flex;
  gap: 26px;
  align-items: center;
}
.nav-links a {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--slate);
  text-decoration: none;
}
.nav-links a:hover {
  color: var(--navy);
}
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: 10px;
  font-family: inherit;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.15s;
  text-decoration: none;
}
.btn-sm {
  font-size: 13.5px;
  padding: 9px 18px;
}
.btn-lg {
  font-size: 15.5px;
  padding: 15px 30px;
}
.btn-navy {
  background: var(--navy);
  color: #fff;
}
.btn-navy:hover {
  background: var(--navy-deep);
}
.nav-links a.btn-navy {
  color: #fff;
}
.btn-outline {
  background: #fff;
  border: 1.5px solid var(--line);
  color: var(--navy);
}
.btn-outline:hover {
  border-color: var(--navy);
}

/* hero */
.hero {
  padding: 76px 0 60px;
  text-align: center;
  background: linear-gradient(180deg, #fff 0%, var(--bg) 100%);
}
.hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--green);
  background: var(--green-soft);
  border-radius: 999px;
  padding: 7px 16px;
  margin-bottom: 22px;
}
h1 {
  font-size: clamp(30px, 5vw, 52px);
  font-weight: 900;
  letter-spacing: -0.035em;
  color: var(--navy);
  line-height: 1.08;
  max-width: 820px;
  margin: 0 auto 18px;
}
h1 .hl {
  color: var(--green);
}
.hero-sub {
  font-size: clamp(15px, 2vw, 18px);
  color: var(--slate);
  max-width: 640px;
  margin: 0 auto 30px;
  line-height: 1.6;
}
.hero-ctas {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.hero-note {
  font-size: 12.5px;
  color: var(--slate);
}

/* hero demo visual */
.demo-card {
  max-width: 640px;
  margin: 44px auto 0;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: 0 20px 50px -12px rgba(15, 37, 87, 0.18);
  padding: 22px;
  text-align: left;
}
.demo-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  margin-bottom: 9px;
}
.demo-row:last-child {
  margin-bottom: 0;
}
.demo-check {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--green);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  flex-shrink: 0;
}
.demo-name {
  flex: 1;
  font-size: 13px;
  font-weight: 600;
  font-family: var(--mono);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--navy);
}
.demo-size {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.demo-size .old {
  color: var(--slate);
  /* DEVIATION — the mockup uses `text-decoration: line-through`. The strike is
     drawn by the ::after rule below instead, because a text-decoration cannot
     be made to sweep across the figure and that sweep is the beat that reads as
     "this file just got compressed". At rest the two look the same: a 1px rule
     in the text's own colour across the middle of the box. inline-block is what
     makes both the absolute positioning and the transform apply — neither does
     anything to a plain inline element. */
  position: relative;
  display: inline-block;
}
.demo-size .old::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% - 0.5px);
  height: 1px;
  background: currentColor;
  transform-origin: left center;
}
.demo-size .arrow,
.demo-size .new {
  display: inline-block;
}
.demo-size .new {
  color: var(--green);
}
.demo-gauge {
  height: 5px;
  background: var(--line);
  border-radius: 3px;
  position: relative;
  margin-top: 14px;
}
.demo-gauge-fill {
  position: absolute;
  height: 100%;
  width: 34%;
  background: var(--green);
  border-radius: 3px;
}
.demo-gauge-limit {
  position: absolute;
  top: -4px;
  bottom: -4px;
  left: 42%;
  width: 2px;
  background: var(--navy);
}
.demo-caption {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--slate);
  margin-top: 8px;
  font-family: var(--mono);
}

/* -----------------------------------------------------------------------------
   .demo-card — THE ONE ANIMATION ON THIS PAGE            (ADDED, owner-requested)
   -----------------------------------------------------------------------------
   The card illustrates a finished run. Animated, it illustrates the run itself:
   each row arrives, its old size is struck out, the new green figure lands, the
   tick confirms it, and the gauge finally sweeps up to just under the portal
   limit. Plays ONCE on load, then holds. Nothing loops — the card sits directly
   beside the primary CTA and a permanently moving element competes with it.
   (To loop instead: add `infinite` to each shorthand and pad the last keyframe
   with a hold. Deliberately not done.)

   THIS IS CSS ONLY, AND THAT IS NOT A STYLE PREFERENCE — see the header of
   site/index.html. The page must render complete with JavaScript disabled,
   which is the entire reason it exists as a separate artefact, and
   scripts/build-site.js fails the build on a <script> tag in it.

   TWO RULES THIS IS BUILT ON, both of which are ways it could silently break:

   1. THE RESTING STATE IS THE FINISHED STATE. Every element below is already
      complete and visible in ordinary CSS; the *starting* state exists only
      inside the @keyframes, applied during the delay by `backwards` fill. Write
      it the other way round — `opacity: 0` in the rule, `1` in the keyframe —
      and the moment animations are off (reduced motion, an old engine, a print
      stylesheet) the hero's centrepiece is a blank card. That failure has no
      symptom for anybody whose machine plays the animation.
   2. ONLY `opacity` AND `transform` MOVE. Nothing here changes width, height or
      layout, so nothing reflows and the card cannot shift the page while it
      plays. The hidden elements keep their boxes the whole time.

   The stagger is one custom property per row; everything inside a row derives
   its delay from it, so the whole sequence retimes from three numbers.

        row 1  --step 0s      row 2  --step 0.42s     row 3  --step 0.84s
        +0.10  row slides in
        +0.42  strike sweeps across the old size
        +0.64  arrow fades in
        +0.72  green figure lands
        +0.94  tick pops
        2.05   gauge fills to 34% (the limit tick at 42% never moves)
        2.60   "ALL FILES UNDER LIMIT" fades in — the conclusion, so it is last
   -------------------------------------------------------------------------- */
.demo-row:nth-child(1) {
  --step: 0s;
}
.demo-row:nth-child(2) {
  --step: 0.42s;
}
.demo-row:nth-child(3) {
  --step: 0.84s;
}

.demo-row {
  animation: demo-row-in 0.45s cubic-bezier(0.2, 0.7, 0.3, 1) backwards;
  animation-delay: calc(var(--step) + 0.1s);
}
.demo-row .demo-check {
  animation: demo-tick-in 0.42s cubic-bezier(0.2, 1.3, 0.4, 1) backwards;
  animation-delay: calc(var(--step) + 0.94s);
}
.demo-row .old::after {
  animation: demo-strike 0.3s ease-out backwards;
  animation-delay: calc(var(--step) + 0.42s);
}
.demo-row .arrow {
  animation: demo-fade-in 0.24s ease-out backwards;
  animation-delay: calc(var(--step) + 0.64s);
}
.demo-row .new {
  animation: demo-land 0.34s cubic-bezier(0.2, 0.9, 0.3, 1) backwards;
  animation-delay: calc(var(--step) + 0.72s);
}
.demo-gauge-fill {
  transform-origin: left center;
  animation: demo-sweep 0.85s cubic-bezier(0.3, 0.8, 0.3, 1) 2.05s backwards;
}
/* The left half of the caption only. The right half labels the limit tick,
   which is drawn from the start, so its label is too. */
.demo-caption span:first-child {
  animation: demo-fade-in 0.5s ease-out 2.6s backwards;
}

@keyframes demo-row-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}
@keyframes demo-fade-in {
  from {
    opacity: 0;
  }
}
@keyframes demo-strike {
  from {
    transform: scaleX(0);
  }
}
@keyframes demo-land {
  from {
    opacity: 0;
    transform: translateY(-4px) scale(0.94);
  }
}
@keyframes demo-sweep {
  from {
    transform: scaleX(0);
  }
}
@keyframes demo-tick-in {
  from {
    opacity: 0;
    transform: scale(0.3);
  }
}

/* ADDED — the opt-out, kept next to the animation rather than in the global
   reduced-motion block at the top of this file, so that anyone editing the
   sequence above sees what they also have to switch off. Because of rule 1
   above, `animation: none` does not hide anything: it leaves the card in the
   finished state it is written in. */
@media (prefers-reduced-motion: reduce) {
  .demo-row,
  .demo-row .demo-check,
  .demo-row .old::after,
  .demo-row .arrow,
  .demo-row .new,
  .demo-gauge-fill,
  .demo-caption span:first-child {
    animation: none;
  }
}

/* sections */
section {
  padding: 72px 0;
}
.sec-eyebrow {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--green);
  text-align: center;
  margin-bottom: 10px;
}
h2 {
  font-size: clamp(24px, 3.4vw, 34px);
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--navy);
  text-align: center;
  margin-bottom: 14px;
}
.sec-sub {
  font-size: 15px;
  color: var(--slate);
  text-align: center;
  max-width: 560px;
  margin: 0 auto 44px;
  line-height: 1.6;
}

/* benefits grid */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
}
.feat {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
}
.feat-icon {
  width: 44px;
  height: 44px;
  border-radius: 11px;
  background: var(--navy);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 19px;
  margin-bottom: 16px;
}
.feat-icon.g {
  background: var(--green);
}
.feat h3 {
  font-size: 16px;
  font-weight: 800;
  color: var(--navy);
  margin-bottom: 8px;
  letter-spacing: -0.01em;
}
.feat p {
  font-size: 13.5px;
  color: var(--slate);
  line-height: 1.6;
}

/* privacy band */
.privacy {
  background: var(--navy);
  color: #fff;
  text-align: center;
}
.privacy .sec-eyebrow {
  color: #4ade9c;
}
.privacy h2 {
  color: #fff;
}
.privacy p {
  color: rgba(255, 255, 255, 0.75);
  font-size: 15px;
  max-width: 620px;
  margin: 0 auto;
  line-height: 1.7;
}
.privacy-points {
  display: flex;
  justify-content: center;
  gap: 34px;
  margin-top: 34px;
  flex-wrap: wrap;
}
.privacy-point {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 13.5px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.9);
}
.privacy-point .dot {
  color: #4ade9c;
}

/* steps */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  counter-reset: step;
}
.step {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  position: relative;
}
.step::before {
  counter-increment: step;
  content: counter(step);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--green-soft);
  color: var(--green);
  font-family: var(--mono);
  font-weight: 600;
  font-size: 15px;
  margin-bottom: 14px;
}
.step h3 {
  font-size: 15.5px;
  font-weight: 800;
  color: var(--navy);
  margin-bottom: 7px;
}
.step p {
  font-size: 13.5px;
  color: var(--slate);
  line-height: 1.6;
}

/* faq */
.faq {
  max-width: 680px;
  margin: 0 auto;
}
details {
  border: 1px solid var(--line);
  border-radius: 12px;
  margin-bottom: 10px;
  background: var(--card);
}
summary {
  padding: 16px 20px;
  font-size: 14.5px;
  font-weight: 700;
  color: var(--navy);
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
}
/* Safari still needs the vendor pseudo-element to drop the disclosure triangle. */
summary::-webkit-details-marker {
  display: none;
}
summary::after {
  content: '+';
  font-size: 18px;
  color: var(--slate);
  font-weight: 400;
}
details[open] summary::after {
  content: '–';
}
details p {
  padding: 0 20px 16px;
  font-size: 13.5px;
  color: var(--slate);
  line-height: 1.65;
}

/* final cta */
.final {
  background: var(--bg);
  text-align: center;
}

footer {
  border-top: 1px solid var(--line);
  padding: 28px 0;
  background: #fff;
}
.foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.foot-links {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  align-items: center;
}
.foot a {
  font-size: 12.5px;
  color: var(--slate);
  text-decoration: none;
}
.foot a:hover {
  color: var(--navy);
}
.foot-copy {
  font-size: 12.5px;
  color: var(--slate);
}

/* ADDED — Blog is written and not yet built.
   The mockup renders it as <a href="#">, which is a live-looking control for
   something that goes nowhere (rule #54, the same call the Google button made
   in Phase 1). This is not a link at all: no href, visibly quieter than the
   real ones, and it carries the word "soon" so the page says out loud what it
   is doing. It becomes a real anchor in Phase 7 T3.

   PRIVACY / TERMS / CONTACT USED TO BE THREE MORE OF THESE. They are real pages
   as of T2 and therefore real anchors; `build-site.js` now fails the build if
   any of the three goes back to wearing this class, on any of the four pages. */
.foot-soon {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--muted);
  cursor: default;
}
.foot-soon .soon {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--slate);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px 7px;
}

@media (max-width: 640px) {
  .nav-links a:not(.btn) {
    display: none;
  }
  section {
    padding: 52px 0;
  }
}

/* =============================================================================
   DOCUMENT PAGES — /privacy, /terms, /contact               (ADDED, Phase 7 T2)
   =============================================================================
   The same shell as the landing page and deliberately the same stylesheet: same
   header, same footer, same tokens, one file (D10 — the marketing site is one
   static artefact). What changes is the body. The landing page is a sales
   sequence of centred, full-width sections; these are documents, so they are a
   single column of left-aligned prose at a readable measure.

   THAT IS WHY EVERY HEADING RULE BELOW IS AN OVERRIDE. `h1`, `h2` and `section`
   are styled as bare elements at the top of this file, because the landing page
   has exactly one of each per band and they are all centred. A document page has
   to say otherwise explicitly — and `.wrap.legal` is two classes on purpose, so
   it beats `.wrap`'s own max-width rather than relying on source order.
   ============================================================================= */
.legal-page {
  padding: 54px 0 76px;
  background: linear-gradient(180deg, var(--bg) 0%, #fff 220px);
}
.wrap.legal {
  max-width: 760px;
}
.legal h1 {
  font-size: clamp(28px, 4vw, 40px);
  text-align: left;
  max-width: none;
  margin: 0 0 10px;
}
.legal-updated {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--slate);
  margin-bottom: 26px;
}
.legal-lead {
  font-size: 16px;
  line-height: 1.7;
  color: var(--ink);
  margin-bottom: 28px;
}
.legal section {
  padding: 0;
  margin-bottom: 30px;
}
.legal section:last-child {
  margin-bottom: 0;
}
.legal h2 {
  font-size: clamp(18px, 2.4vw, 22px);
  text-align: left;
  margin: 0 0 12px;
}
.legal h3 {
  font-size: 15px;
  font-weight: 800;
  color: var(--navy);
  margin: 20px 0 7px;
}
.legal p {
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--slate);
  margin-bottom: 12px;
}
.legal p:last-child {
  margin-bottom: 0;
}
.legal strong {
  color: var(--navy);
  font-weight: 700;
}
.legal a {
  color: var(--navy);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.legal a:hover {
  color: var(--green);
}
.legal ul {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
}
.legal li {
  position: relative;
  padding-left: 20px;
  margin-bottom: 9px;
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--slate);
}
.legal li:last-child {
  margin-bottom: 0;
}
.legal li::before {
  content: '';
  position: absolute;
  left: 3px;
  top: 10px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--green);
}

/* The one thing on /privacy that a visitor should read even if they read
   nothing else. Green rather than navy because it is the good news. */
.legal-callout {
  background: var(--green-soft);
  border: 1px solid rgba(15, 163, 107, 0.25);
  border-radius: var(--radius);
  padding: 20px 22px;
  margin-bottom: 30px;
}
.legal-callout-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--green);
  margin-bottom: 10px;
}
.legal-callout p {
  color: var(--ink);
}

/* A neutral box for the same job on /terms, where the news is a warning rather
   than a reassurance — navy, not red: it is important, not an error. */
.legal-note {
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--navy);
  border-radius: var(--radius);
  padding: 20px 22px;
  margin-bottom: 30px;
}
.legal-note .legal-callout-title {
  color: var(--navy);
}
.legal-note p {
  color: var(--ink);
}

/* The header logo is a link back to / on every page except / itself, where it
   would be a self-link. `.logo` is a flex container carrying its own colour, so
   as an <a> it needs only the underline removed. */
a.logo {
  text-decoration: none;
}
/* The badge is the hover affordance now that "Pro" is a fill rather than a
   coloured word — the fill goes navy and the white text stays white, so the
   feedback is the same gesture the old rule made and the label never drops out. */
a.logo:hover .pro {
  background: var(--navy);
}

/* /contact — the address is the page, so it is the largest thing on it. */
.contact-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  margin-bottom: 18px;
}
.contact-label {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--green);
  margin-bottom: 10px;
}
a.contact-email {
  display: inline-block;
  font-family: var(--mono);
  font-size: clamp(17px, 3.4vw, 23px);
  font-weight: 600;
  color: var(--navy);
  text-decoration: none;
  letter-spacing: -0.01em;
  /* An address is one token to a reader and an unbreakable string to a layout
     engine. Without this it overflows the card on a narrow phone instead of
     wrapping — and this address is 21 characters of it. */
  word-break: break-word;
}
a.contact-email:hover {
  color: var(--green);
}
.contact-meta {
  font-size: 13px;
  color: var(--slate);
  margin-top: 12px;
  line-height: 1.6;
}

@media (max-width: 640px) {
  .legal-page {
    padding: 36px 0 56px;
  }
  .legal-callout,
  .legal-note,
  .contact-card {
    padding: 18px;
  }
}

/* =============================================================================
   THE UMBRELLA LANDING — `/`                                (ADDED, Phase 7 T2b)
   =============================================================================
   TravelPdfPro became a suite (D11), so `/` is now a tool directory and the visa
   compressor's sales page moved to /visa-pdf-compressor/. This block is what the
   directory needed and nothing more — the hero, the section rhythm, the privacy
   band and the whole footer are the SAME rules the other pages use, unchanged.

   `.tool` is deliberately a sibling of `.feat` rather than a variant of it. They
   look related because they share `.grid` and `.feat-icon`, but a benefit is a
   statement and a tool is a door: this one is an <a>, it has a hover state, and
   it grows a go-line. Building it as `.feat--linky` would have put those three
   behaviours behind a modifier on a class whose job is to be inert.
   ============================================================================= */

/* One tool today. `auto-fit` would stretch a single card to the full 1040px,
   which reads as an empty row rather than a deliberate one — so the tool grid
   caps its columns instead of filling them. A second tool sits beside it; a
   fourth wraps. Nothing here needs revisiting when that happens. */
.grid-tools {
  grid-template-columns: repeat(auto-fit, minmax(280px, 420px));
  justify-content: center;
}

.tool {
  display: block;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  text-decoration: none;
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.tool:hover {
  border-color: var(--green);
  box-shadow: 0 6px 22px rgba(15, 37, 87, 0.08);
  transform: translateY(-2px);
}
/* The card is one link, so the keyboard focus ring belongs to the whole card
   and not to the go-line inside it. */
.tool:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
}

.tool-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 14px;
}
/* .feat-icon carries a 16px bottom margin for the benefits grid, where it sits
   above its heading. Here it sits beside one. */
.tool-head .feat-icon {
  margin-bottom: 0;
  flex-shrink: 0;
}
.tool h3 {
  font-size: 17px;
  font-weight: 800;
  color: var(--navy);
  letter-spacing: -0.01em;
  margin-bottom: 3px;
}
.tool-tag {
  font-size: 12px;
  font-weight: 700;
  color: var(--green);
  letter-spacing: 0.01em;
}
.tool p {
  font-size: 13.5px;
  color: var(--slate);
  line-height: 1.6;
  margin-bottom: 16px;
}
.tool-go {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--navy);
}
.tool:hover .tool-go {
  color: var(--green);
}
/* The arrow nudges on hover. It is inside the transition budget the demo card
   already set, and it is the only motion on this page — `prefers-reduced-motion`
   is honoured below with everything else. */
.tool-go span {
  transition: transform 0.15s;
}
.tool:hover .tool-go span {
  transform: translateX(3px);
}

/* "More tools are coming" is a paragraph, not a grid — see the note in
   index.html's header for why there are no placeholder cards. It only needs its
   inline link to be visible as one. */
.more .sec-sub {
  margin-bottom: 0;
}
.more .sec-sub a {
  color: var(--green);
  font-weight: 700;
  text-decoration: none;
}
.more .sec-sub a:hover {
  text-decoration: underline;
}

@media (prefers-reduced-motion: reduce) {
  .tool,
  .tool-go span {
    transition: none;
  }
  .tool:hover {
    transform: none;
  }
  .tool:hover .tool-go span {
    transform: none;
  }
}
