/* sesh.bike public site — static, no build step.
   Tokens mirror the app's dark palette (frontend/src/index.css) so the
   marketing site reads as the same product. Inlined here as literals so the
   page has zero external CSS dependencies.

   That claim used to be half true: the --font-* tokens below were copied from
   index.css byte for byte, but nothing here DELIVERED the faces they name, so
   every visitor got system-ui and the marketing site looked like a different
   product from the app it advertises. The @font-face block does the other
   half. */

/* The brand faces, self-hosted from this directory.

   No Google Fonts <link> and no CDN: that hands every visitor's IP to a third
   party on a site whose privacy page is still under-disclosing subprocessors,
   and README.md's rule for this directory is that everything the pages need
   lives in it.

   Copied byte for byte from frontend/public/fonts/ (asserted in
   backend/tests/test_landing_site.py — same bytes or the two surfaces are not
   the same product). Only the two faces this stylesheet can reach are here, not
   all five the app ships: --font-display is used by h1/h2/h3 and .wordmark and
   nothing else, all at weight 700, and Hanken Grotesk is one variable file
   spanning 400-700. Give a heading a lighter weight and you must copy that
   .woff2 in beside these, or it will silently render at 700.

   Relative URLs on purpose. These pages are served both from this directory's
   root (Caddy, the standalone service) and under /welcome/ (the backend mount),
   and a leading slash resolves wrong on the second. font-display: swap so the
   fallback chain in the tokens paints immediately and the face swaps in. */
@font-face {
  font-family: "Clash Display";
  src: url("assets/fonts/clash-display-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("assets/fonts/hanken-grotesk.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #0a0b10;
  --surface: #13151c;
  --raised: #1b1e27;
  --border: #262a35;

  --text: #eceef3;
  --muted: #9aa1b0;
  --faint: #737b8e;

  --accent: #7c5cff;
  --accent-2: #9d86ff;
  --accent-soft: rgba(124, 92, 255, 0.14);
  --on-accent: #0a0b10;

  --green: #3ddc84;
  --blue: #4aa8ff;
  --amber: #ffb43d;

  --radius-sm: 0.5rem;
  --radius-md: 0.75rem;
  --radius-lg: 1rem;
  --radius-xl: 1.375rem;

  --font-display: "Clash Display", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-sans: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* There was a `body { overflow-x: hidden }` here. It did not stop the page
   overflowing on a phone, it stopped anyone SEEING that it did: measured with
   headless Chromium, `document.scrollWidth` was 419 against a 390 viewport on
   all six pages, and the page looked intact because the scrollbar was
   suppressed. The overflow is fixed below (the narrow lane at the end of this
   file, plus the gutter fix on the section rules), so the crutch is gone — a
   future regression should be visible, not hidden. Re-measured after the fix
   with overflow-x forced back to `visible`: scrollWidth == clientWidth at both
   320px and 390px, on all six pages. */

a { color: var(--accent-2); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { font-family: var(--font-display); line-height: 1.15; letter-spacing: -0.01em; margin: 0 0 0.5em; }

/* The page gutter. Several section rules below are applied to the SAME element
   as .wrap (`<section class="hero wrap">`, `<main class="wrap legal">`), at equal
   specificity and later in the file — so any of them that sets `padding` as a
   SHORTHAND silently resets this 20px to zero and runs the section edge-to-edge.
   Four of them did. Set padding-top / padding-bottom in section rules, never the
   shorthand, and never `padding-inline` here either: some sections are nested
   INSIDE a .wrap instead of being one, and would get a doubled 40px gutter. */
.wrap { width: 100%; max-width: 1080px; margin: 0 auto; padding: 0 20px; }

/* ---------- Nav ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(10, 11, 16, 0.82);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
}
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.25rem;
  letter-spacing: -0.02em;
  color: var(--text);
}
.wordmark .nav-logo { width: 28px; height: 28px; display: block; border-radius: 7px; }
.wordmark .dot { color: var(--accent); }
.nav-links { display: flex; gap: 18px; align-items: center; }
.nav-links a { color: var(--muted); font-size: 0.9rem; }
.nav-links a:hover { color: var(--text); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-block;
  /* A button label is one thing to press, so it is one line. Without this the
     nav CTA wrapped to "Join / the / waitlis" on a phone: the flex row squeezed
     the button below its content width, the label broke between words, and the
     resulting 91px-tall box was cut off by the 60px bar. Every .btn on the site
     says "Join the waitlist", which measures 141.9px here and so fits inside
     the 280px content box a 320px viewport leaves. */
  white-space: nowrap;
  padding: 12px 20px;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
  font-family: var(--font-sans);
  border: none;
  cursor: pointer;
  transition: transform 120ms ease, background 120ms ease;
}
.btn:hover { background: var(--accent-2); text-decoration: none; transform: translateY(-1px); }
.btn.ghost { background: transparent; color: var(--text); border: 1px solid var(--border); }
.btn.ghost:hover { background: var(--raised); }

/* ---------- Hero ---------- */
/* padding-top/-bottom, not the shorthand — see .wrap. `.hero` IS the .wrap on
   index.html, the only page that still has one, so the shorthand here would
   reset that same element's own 20px gutter to zero. (the separate media gallery, which nested
   a .hero INSIDE a .wrap, is gone — its whole image set was already on this
   page, better captioned.) */
.hero { padding-top: 72px; padding-bottom: 40px; }
.hero h1 {
  font-size: clamp(2rem, 6vw, 3.25rem);
  line-height: 1.05;
  max-width: 20ch;
}
.hero h1 .accent { color: var(--accent-2); }
.hero .sub {
  color: var(--muted);
  font-size: clamp(1rem, 2.4vw, 1.2rem);
  max-width: 52ch;
  margin: 0 0 28px;
}
.hero-cta { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.hero-cta .more { color: var(--muted); font-size: 0.95rem; }
.hero-note { color: var(--faint); font-size: 0.9rem; margin: 14px 0 0; }

/* ---------- Trust band ---------- */
.trust {
  margin: 8px 0 56px;
  padding: 14px 18px;
  border: 1px solid var(--border);
  background: var(--accent-soft);
  border-radius: var(--radius-md);
  color: var(--text);
  font-weight: 500;
  font-size: 0.95rem;
}

/* ---------- Features ---------- */
.features { padding-top: 16px; padding-bottom: 64px; }
.section-title {
  font-size: clamp(1.5rem, 4vw, 2.25rem);
  margin-bottom: 8px;
}
.section-lede { color: var(--muted); max-width: 60ch; margin: 0 0 36px; }
.feature {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  margin-bottom: 56px;
  align-items: center;
}
.feature img {
  width: 100%;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface);
  display: block;
}
.feature h3 { font-size: 1.4rem; margin-bottom: 6px; }
.feature p { color: var(--muted); margin: 0; max-width: 48ch; }
@media (min-width: 760px) {
  .feature { grid-template-columns: 1fr 1fr; gap: 40px; }
  .feature.flip .f-text { order: 2; }
  /* Two blocks on index.html carry no screenshot, because no honest one
     exists for them yet. Without this they would keep the two-column grid
     and leave half the row blank. */
  .feature.textonly { grid-template-columns: 1fr; }
  /* #1205 section 3: the named-trail block is the one claim no surveyed
     competitor makes, so it keeps the full width on desktop while the
     table-stakes blocks share a two-column row — the most room on the page,
     by layout rather than by saying so. */
  .feature.wide { grid-template-columns: 1fr; }
  .feature.wide .f-text p { font-size: 1.1rem; max-width: 62ch; }
}

/* ---------- The atlas section (index.html, #1205 section 4) ----------
   A text-only card: the numbers it names are the park page's own live ones,
   so the destination link — not a screenshot — is the evidence. A baked
   capture of the atlas cannot be corrected when the catalogue moves, and
   nobody notices it went stale. */
.atlas-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 28px;
  margin-bottom: 56px;
  max-width: 720px;
}
.atlas-card h3 { font-size: 1.4rem; margin-bottom: 6px; }
.atlas-card p { color: var(--muted); margin: 0 0 18px; max-width: 58ch; }

/* ---------- Waitlist form ---------- */
.waitlist {
  border-top: 1px solid var(--border);
  padding-top: 56px;
  padding-bottom: 72px;
}
.waitlist-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 32px;
  max-width: 560px;
}
.waitlist h2 { font-size: clamp(1.5rem, 4vw, 2rem); }
.waitlist p.help { color: var(--muted); margin: 0 0 18px; }
/* #1205 final CTA: the invite door sits between the two help lines, so it
   takes the same rhythm rather than the form's tighter one. */
.waitlist p.invite-door { margin: 0 0 18px; }
.form-row { display: flex; flex-direction: column; gap: 12px; }
input[type="email"], textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--raised);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 1rem;
}
input[type="email"]:focus, textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}
textarea { resize: vertical; min-height: 70px; }
label { font-size: 0.85rem; color: var(--muted); }
.form-msg {
  margin-top: 14px;
  font-size: 0.92rem;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  display: none;
}
.form-msg.show { display: block; }
.form-msg.ok   { background: rgba(61, 220, 132, 0.12); color: var(--green); border: 1px solid rgba(61,220,132,0.3); }
.form-msg.warn { background: rgba(255, 180, 61, 0.12); color: var(--amber); border: 1px solid rgba(255,180,61,0.3); }
.form-msg.err  { background: rgba(255, 84, 104, 0.12); color: #ff8a96; border: 1px solid rgba(255,84,104,0.3); }

/* ---------- Invite ---------- */
.invite-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 36px;
  max-width: 620px;
  margin: 48px 0;
}
.invite-card .note {
  margin-top: 18px;
  padding: 12px 16px;
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  color: var(--text);
  font-weight: 500;
}

/* ---------- Legal ---------- */
.legal { padding-top: 48px; padding-bottom: 80px; max-width: 720px; }
.legal h1 { font-size: clamp(1.8rem, 5vw, 2.5rem); }
.legal .updated { color: var(--faint); font-size: 0.85rem; margin-bottom: 28px; }
.legal h2 { font-size: 1.25rem; margin-top: 28px; color: var(--text); }
.legal p, .legal li { color: var(--muted); }
.legal ul { padding-left: 1.2em; }
.legal p, .legal li { line-height: 1.65; }

/* ---------- Free promise (index.html, #78) ---------- */
/* Was `padding: 0 20px 64px` — the one section where someone had already
   re-stated the gutter by hand after the shorthand ate it. Now it inherits the
   20px from .wrap like the other four, so there is one way this is done. */
.free { padding-top: 0; padding-bottom: 64px; }
.free-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 32px;
}
.free-card h2 { font-size: clamp(1.5rem, 4vw, 2.25rem); margin-bottom: 6px; }
.free-lede { color: var(--muted); max-width: 60ch; margin: 0 0 20px; }
.free-list {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 10px;
}
.free-list li { position: relative; padding-left: 1.6em; }
.free-list li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--green);
  font-weight: 700;
}
.free-fineprint { color: var(--faint); font-size: 0.9rem; max-width: 60ch; margin: 0; }
@media (min-width: 760px) {
  .free-list { grid-template-columns: 1fr 1fr; }
}

/* ---------- Footer ---------- */
.footer {
  border-top: 1px solid var(--border);
  padding: 32px 0;
  color: var(--faint);
  font-size: 0.9rem;
}
.footer-inner { display: flex; flex-wrap: wrap; gap: 12px 24px; justify-content: space-between; align-items: center; }
.footer-links { display: flex; gap: 18px; flex-wrap: wrap; }
.footer-links a { color: var(--muted); }

/* ---------- Narrow viewports (#1202) ----------
   Everything above this point is desktop-first and, until this block existed,
   the phone simply got the desktop rules. The nav is why it mattered: wordmark
   + three text links + the CTA do not fit the 350px a 390px phone leaves inside
   the gutter, so the flex row squeezed the button until the only call to action
   on the page rendered as "Join / the / waitlis" — three line boxes in an
   86.3x91px box, inside a bar 60px tall. Measured, headless Chromium, 390x844.

   The nav collapses to wordmark + CTA here. The three links it drops (Media,
   Privacy, Terms) are in the footer of every page, so nothing becomes
   unreachable. A link that must survive the collapse gets `class="nav-keep"`
   — but measure before adding one: at 320px, even with the smaller wordmark
   below, the wordmark and the CTA together leave 24.2px. A fourth item does not
   fit there and belongs in the footer.

   Paired with the two `min-width: 760px` blocks above: 759/760 is the same
   boundary, so no viewport falls between them or matches both. */
@media (max-width: 759px) {
  .nav-links a:not(.btn):not(.nav-keep) { display: none; }
  .nav-links { gap: 12px; }

  /* The CTA keeps its full size — it is the thing this block exists for — so
     the slack at 320px comes out of the wordmark. At the desktop size the two
     leave 1.0px between them in a 280px content box, which is not a margin:
     these pages load no webfont ("Clash Display" is declared and never served),
     so the wordmark is whatever system-ui the visitor's phone has, and that is
     not the font measured here. */
  .wordmark { font-size: 1.05rem; gap: 7px; }
  .wordmark .nav-logo { width: 24px; height: 24px; }

  /* 32px of card padding costs a phone a fifth of its line. At 20px the
     waitlist card gives 310px of text at 390px and 240px at 320px. */
  .waitlist-card { padding: 20px; }
  .invite-card { padding: 20px; margin: 28px 0; }
  .free-card { padding: 20px; }
  .atlas-card { padding: 20px; }

  .hero { padding-top: 44px; padding-bottom: 28px; }
  .waitlist { padding-top: 40px; padding-bottom: 48px; }
  .legal { padding-top: 32px; padding-bottom: 56px; }
}
