/* ============================================================
   mindspace. — stylesheet
   ============================================================

   Plain CSS, no build step, no framework. Double-click any page to
   see exactly what ships.

   ------------------------------------------------------------
   ON THE PALETTE

   The brief asked for muted earth tones and soft sages. That was
   not taken literally, and the reason is worth recording: the app
   is #99BBFF blue with a #FFB861 amber accent, and a sage website
   in front of a blue app makes the download feel like arriving
   somewhere else. Brand continuity between the page and the
   product is worth more than any one palette.

   What the brief was actually reaching for — calm, breathable,
   low cognitive load — came from the *other* levers instead:

     - a warm off-white page (#FAF9F6) rather than cool grey, so
       the whole thing reads softer without changing hue
     - the blue desaturated for large areas and kept saturated
       only for small accents
     - roughly double the vertical rhythm
     - one idea per screen

   ------------------------------------------------------------
   THE ONE HARD RULE

   Never white text on --blue or --amber. They measure 1.93:1 and
   1.71:1 against white — both far under WCAG AA. Text on those
   surfaces uses --on-blue / --on-amber, which are the same hues
   mixed toward black and clear 4.5:1.
   ============================================================ */

/* ============================================================
   FONTS — self-hosted, and that is the point

   These are the exact Fredoka .ttf files the app ships, converted
   to woff2 (48KB → 21KB each). Four weights, 84KB total.

   Self-hosted rather than loaded from Google Fonts, for two
   reasons and the second one matters:

     1. The app is Fredoka. Google's copy is the same typeface,
        but pulling the real files out of the project guarantees
        the site and the product can never drift apart.

     2. A Google Fonts <link> sends every visitor's IP address to
        Google before the page has even rendered. On a site whose
        central claim is "nothing leaves your device", that is a
        contradiction sitting in the <head>. This site now makes
        ZERO third-party requests — no fonts, no analytics, no
        CDN, nothing. The privacy page is true of the website as
        well as the app.

   Body text falls back to the system UI stack rather than a
   downloaded font: it is already on the reader's machine, costs
   no request, and is designed for long-form reading in a way a
   rounded display face is not.
   ============================================================ */

@font-face {
  font-family: "Fredoka";
  src: url("fonts/Fredoka-Regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fredoka";
  src: url("fonts/Fredoka-Medium.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fredoka";
  src: url("fonts/Fredoka-SemiBold.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fredoka";
  src: url("fonts/Fredoka-Bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

:root {
  --font-brand: "Fredoka", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, system-ui, sans-serif;

  /* brand */
  --blue: #99bbff;
  --blue-mist: #e8f0ff;
  --blue-ink: #4a6bb0;      /* link/label weight — 4.9:1 on the page */
  --amber: #ffb861;
  --amber-mist: #fff3e2;

  --on-blue: #3a4761;
  --on-amber: #614625;

  /* page */
  --paper: #faf9f6;         /* warm off-white, not cool grey */
  --paper-2: #f3f1ec;
  --card: #ffffff;

  --ink: #23262e;
  --ink-2: rgba(35, 38, 46, 0.70);
  --ink-3: rgba(35, 38, 46, 0.48);
  --line: rgba(35, 38, 46, 0.09);

  --radius: 24px;
  --radius-sm: 16px;
  --shadow: 0 1px 2px rgba(35,38,46,.04), 0 12px 32px rgba(35,38,46,.06);
  --shadow-lift: 0 2px 6px rgba(35,38,46,.05), 0 24px 56px rgba(35,38,46,.10);

  --wrap: 1120px;
  --wrap-text: 680px;

  /* vertical rhythm — the main lever for "breathable" */
  --section: clamp(88px, 13vw, 168px);
}

/* ---------- reset ---------- */

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  /* Nothing on this page is meant to sit outside the viewport. The
     hero's colour washes are already clipped by their own
     overflow:hidden, so if a scrollbar ever appears here it is a bug —
     this keeps a bug from shifting the entire layout while it is
     found. */
  overflow-x: hidden;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: var(--blue-ink); text-decoration: none; }
a:hover { text-decoration: underline; }

a:focus-visible, button:focus-visible {
  outline: 2px solid var(--blue-ink);
  outline-offset: 4px;
  border-radius: 8px;
}

/* ---------- layout ---------- */

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 28px; }
.wrap-text { max-width: var(--wrap-text); }
section { padding: var(--section) 0; }
.center { text-align: center; }
.center .lede, .center p { margin-left: auto; margin-right: auto; }

/* ---------- type ---------- */

/* Headings are the app's own typeface, at its lightest usable weight.
   Fredoka is a rounded display face — at 400 and large sizes it reads
   warm and open; at heavier weights it gets shouty, which is the
   opposite of what this page is for. */
h1, h2, h3 {
  font-family: var(--font-brand);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: -0.022em;
  margin: 0 0 0.45em;
  color: var(--ink);
  /* A long word at 4.4rem is wider than a narrow column, and an
     element that cannot shrink past its longest word pushes the whole
     document sideways — which is what made the header look cropped and
     shifted. These two let a heading break rather than overflow. */
  overflow-wrap: anywhere;
  word-break: normal;
}

h1 { font-size: clamp(2.7rem, 6.2vw, 4.4rem); }
h2 { font-size: clamp(2rem, 4vw, 2.9rem); }
h3 { font-size: 1.16rem; font-weight: 500; letter-spacing: -0.01em; }

p { margin: 0 0 1.2em; color: var(--ink-2); }

.lede {
  font-size: clamp(1.08rem, 1.7vw, 1.26rem);
  line-height: 1.66;
  color: var(--ink-2);
  max-width: 33em;
}

.eyebrow {
  font-family: var(--font-brand);
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--blue-ink);
  margin-bottom: 18px;
}

/* ---------- wordmark ---------- */

/* The trailing period belongs to the mark, so it is drawn with CSS
   rather than typed — that keeps it out of the accessible name, where
   a screen reader would announce a full stop mid-sentence.

   BLUE, BUT NOT AppPrimary. The app's #99BBFF measures 1.83:1 on this
   background — it is a fill colour, designed to sit behind dark text,
   and as text itself it is barely visible. #4a6bb0 is the same hue
   taken down until it works as ink: still unmistakably the brand blue,
   and 4.96:1. It is also exactly the blue the nav links and eyebrow
   labels already use, so the header reads as one family.

   The period stays amber — the one warm mark on the page. */
.wordmark {
  font-family: var(--font-brand);
  font-weight: 500;
  font-size: 1.3rem;
  letter-spacing: -0.02em;
  color: var(--blue-ink);
  white-space: nowrap;
}
.wordmark::after { content: "."; color: var(--amber); }
.wordmark:hover { text-decoration: none; }

/* ---------- nav ---------- */

.nav {
  position: sticky; top: 0; z-index: 60;
  background: rgba(250, 249, 246, 0.78);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .3s ease, background .3s ease;
}
.nav.scrolled { border-bottom-color: var(--line); }

.nav-inner { display: flex; align-items: center; gap: 24px; height: 74px; }

/* Pills rather than plain links, and identical on all five pages.
   The header used to differ page to page — and on the home page
   "Privacy" was an in-page anchor while everywhere else it opened a
   file — so moving between them felt like leaving one site and
   arriving at another. One header, one set of destinations, and the
   current one marked: now it reads as a single place with tabs. */
.nav-links {
  margin-left: auto;
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-brand);
  font-size: .92rem; font-weight: 400;
}

.nav-links a {
  color: var(--ink-2);
  padding: 9px 16px;
  border-radius: 999px;
  white-space: nowrap;
  transition: background .2s ease, color .2s ease;
}
.nav-links a:hover {
  color: var(--ink);
  background: rgba(35, 38, 46, .05);
  text-decoration: none;
}

/* The page you are on. Marked with background and weight rather than
   colour alone — colour by itself is invisible to a good number of
   readers, and `aria-current` carries it to screen readers. */
.nav-links a[aria-current="page"] {
  color: var(--on-blue);
  background: var(--blue-mist);
  font-weight: 500;
}

@media (max-width: 860px) {
  .nav-inner { height: auto; padding: 12px 0; flex-wrap: wrap; gap: 8px 16px; }

  /* The mark is the one thing in the header that must never be
     shortened or clipped, so it is excused from shrinking. */
  .wordmark { flex: 0 0 auto; }

  .nav-links {
    margin-left: 0; width: 100%; gap: 6px 4px;
    font-size: .86rem;
    /* Wrap rather than scroll. This row used to be a horizontal
       scroller, which on a phone is narrower than the five pills need:
       the last one was sliced in half against the edge of the content
       box, and a half-word reads as a broken page rather than as
       "there is more this way". These five destinations are the entire
       site, so none of them should need discovering by swipe.
       Wrapping costs a row of height on the narrowest screens and
       nothing at all above them — wherever the pills fit on one line
       they still sit on one line. */
    flex-wrap: wrap;
  }
  .nav-links a { padding: 8px 13px; }
}

/* Narrow phones. Slightly tighter pills so the five fit on two
   comfortable rows instead of three cramped ones, and so the row
   always ends short of the gutter rather than against it. */
@media (max-width: 420px) {
  .nav-links { font-size: .84rem; gap: 6px 3px; }
  .nav-links a { padding: 8px 11px; }
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 54px; padding: 16px 32px;
  border-radius: 999px; border: 0; cursor: pointer;
  font-family: var(--font-brand); font-size: 1rem; font-weight: 500;
  transition: transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s ease;
}
.btn:hover { text-decoration: none; transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn-primary {
  background: var(--blue); color: var(--on-blue);
  box-shadow: 0 4px 16px rgba(153,187,255,.45);
}
.btn-primary:hover { box-shadow: 0 10px 28px rgba(153,187,255,.6); }

.btn-ghost {
  background: transparent; color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line);
}
.btn-ghost:hover { box-shadow: inset 0 0 0 1px rgba(35,38,46,.22); }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; }
.center .btn-row { justify-content: center; }

.btn[aria-disabled="true"] { cursor: default; }

/* ---------- hero ---------- */

.hero { padding: clamp(64px, 9vw, 112px) 0 var(--section); position: relative; overflow: hidden; }

/* Two very soft washes. Large, low opacity, heavily blurred — they
   should register as light rather than as shapes. */
.hero::before, .hero::after {
  content: ""; position: absolute; border-radius: 50%;
  filter: blur(110px); pointer-events: none; z-index: 0;
}
.hero::before { width: 680px; height: 680px; background: var(--blue); opacity: .30; top: -340px; left: -200px; }
.hero::after  { width: 520px; height: 520px; background: var(--amber); opacity: .20; top: -180px; right: -190px; }
.hero > .wrap { position: relative; z-index: 1; }

/* ---------- screenshots ---------- */

/* The captures include the device bezel, so nothing here draws a phone
   frame — a CSS frame over a captured one gives two nested bezels,
   which is the giveaway of a mockup made in a hurry.

   The blue backdrop has been flood-filled out, so each file is the
   phone alone on transparency. That is why the shadow is drop-shadow
   and not box-shadow: drop-shadow follows the real alpha silhouette
   and traces the rounded corners, where box-shadow would draw a
   rectangle behind a rounded object.

   Capped at 300px because the sources are ~388px wide. Larger than
   that and they soften on a Retina screen. */
.shot {
  height: clamp(430px, 54vw, 580px);
  width: auto; max-width: 300px; object-fit: contain;
  filter: drop-shadow(0 26px 50px rgba(35,38,46,.18));
}

/* A slow, tiny vertical drift. 9s and 10px — below the threshold where
   it reads as animation, above the threshold where it reads as still.
   Disabled wholesale under prefers-reduced-motion at the bottom. */
@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}
.shot-float { animation: float 9s ease-in-out infinite; }

/* ---------- showcase rows ---------- */

.showcase {
  display: grid;
  grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: clamp(36px, 7vw, 88px);
  align-items: center;
}
.showcase-media { display: flex; justify-content: center; }
.showcase-body { max-width: 30em; }

@media (min-width: 881px) {
  .showcase-flip .showcase-media { order: 2; }
}
@media (max-width: 880px) {
  .showcase { grid-template-columns: 1fr; gap: 44px; }
  .showcase-body { max-width: none; text-align: center; margin: 0 auto; }
  .showcase-body .btn-row { justify-content: center; }
  .showcase-body .lede { margin-left: auto; margin-right: auto; }
}

/* ---------- cards ---------- */

.card {
  background: var(--card); border-radius: var(--radius);
  padding: 32px; box-shadow: var(--shadow);
  transition: transform .3s cubic-bezier(.22,1,.36,1), box-shadow .3s ease;
}
.card h3 { margin-bottom: 10px; }
.card p { margin-bottom: 0; font-size: .97rem; }
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); }

.grid { display: grid; gap: 22px; grid-template-columns: repeat(auto-fit, minmax(270px,1fr)); }

.chip {
  width: 44px; height: 44px; border-radius: 13px;
  display: grid; place-items: center; margin-bottom: 18px;
  font-size: 1.2rem; background: var(--blue-mist);
}
.chip-amber { background: var(--amber-mist); }

/* ---------- quote ---------- */

.quote {
  border-radius: var(--radius);
  background: var(--paper-2);
  padding: clamp(44px, 7vw, 88px) clamp(28px, 5vw, 72px);
  text-align: center;
}
.quote blockquote {
  margin: 0; font-family: var(--font-brand); font-weight: 400;
  font-size: clamp(1.5rem, 3vw, 2.1rem); line-height: 1.34;
  letter-spacing: -0.015em; color: var(--ink);
}
/* --ink-3 measures 4.38:1 on --paper-2 — under AA, and small uppercase
   letterspaced text is the worst possible place to be under it.
   Solved rather than eyeballed: 0.64 alpha is still short at 4.45,
   0.68 clears it at 5.00. */
.quote cite {
  display: block; margin-top: 26px; font-style: normal;
  font-family: var(--font-brand); font-size: .82rem;
  letter-spacing: .14em; text-transform: uppercase;
  color: rgba(35, 38, 46, 0.68);
}

/* ---------- panel ---------- */

.panel {
  border-radius: var(--radius);
  padding: clamp(36px, 6vw, 72px);
  background: var(--card); box-shadow: var(--shadow);
}
.panel-mist { background: var(--blue-mist); box-shadow: none; }

/* ---------- document pages ---------- */

.doc { padding: 56px 0 var(--section); }
.doc h2 { margin-top: 2.4em; font-size: 1.45rem; }
.doc h2:first-of-type { margin-top: 1.3em; }
.doc h3 { font-size: 1.05rem; }
.doc ul { padding-left: 1.2em; margin: 0 0 1.2em; }
.doc li { margin-bottom: .5em; color: var(--ink-2); }
.doc strong { color: var(--ink); font-weight: 600; }

.updated {
  display: inline-block; font-size: .84rem; color: var(--ink-3);
  padding: 7px 16px; border-radius: 999px; background: var(--paper-2);
}

.note {
  border-left: 3px solid var(--amber);
  background: var(--amber-mist);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 20px 24px; margin: 28px 0;
}
.note p:last-child { margin-bottom: 0; }
.note strong { color: var(--ink); }

/* ---------- footer ---------- */

.footer { border-top: 1px solid var(--line); padding: 52px 0 64px; font-size: .92rem; }
.footer-inner { display: flex; flex-wrap: wrap; gap: 20px 36px; align-items: center; }
.footer a { color: var(--ink-2); }
.footer span { color: var(--ink-3); }
.footer-links { display: flex; flex-wrap: wrap; gap: 22px; margin-left: auto; }
@media (max-width: 720px) { .footer-links { margin-left: 0; } }

/* ---------- scroll reveal ---------- */

/* Starts *visible* and is hidden by JS only if IntersectionObserver is
   available. If the script fails, is blocked, or the browser is old,
   the page is simply readable rather than permanently blank — which is
   what happens when reveal styles are baked into the CSS. */
.js-reveal .reveal { opacity: 0; transform: translateY(18px); }
.js-reveal .reveal.in {
  opacity: 1; transform: none;
  transition: opacity .8s cubic-bezier(.22,1,.36,1), transform .8s cubic-bezier(.22,1,.36,1);
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .shot-float { animation: none; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
  .js-reveal .reveal { opacity: 1; transform: none; }
}
