/* The one place the Safeleaf palette is written down.
 *
 * It used to live in five: index.html, variant-b.html, build.mjs's privacy template,
 * server.mjs's page() helper, and make-store-graphics.py as RGB tuples. Five hand-kept
 * copies of one palette is five chances for the store listing and the website to stop
 * being the same product, and the Python one is what the Play icon is drawn from.
 *
 * So: every page links this file, and scripts/make-store-graphics.py PARSES the :root
 * block below for GREEN/CREAM. Changing a hex here changes the site, the error pages
 * and the store graphics together. The app's own colours are in
 * android/app/src/main/res/values/colors.xml — make-store-graphics.py asserts that
 * ic_launcher_background still equals --accent and fails the build if it does not.
 *
 * Serving this as a file costs `style-src 'self'` in server.mjs's CSP. That is not a
 * loosening of the thing the CSP is actually for: there is still no script-src at all
 * and default-src stays 'none'. Styles already allowed 'unsafe-inline'.
 */

:root {
  --bg: #fbfaf7;
  --panel: #ffffff;
  --ink: #17201a;
  --muted: #5c6b60;
  --line: #e2e6e0;
  /* The edge of a CONTROL, as opposed to the hairline between two bits of content.
   * --line is deliberately faint, which is right for a divider and wrong for the only
   * thing marking where a form field is: at 1.26:1 against the field it failed WCAG
   * 1.4.11, which asks 3:1 for exactly that and exempts the decorative case. So the
   * token is split rather than darkened, and no hairline changes. 3.25:1 on --panel.
   * Same value as @color/control_line in the app, like the rest of this palette. */
  --control-line: #889189;
  --danger: #a33c32;   /* 6.19:1 on --bg. Same red as the app's `blocked`. */
  --accent: #2f6b45;
  --accent-ink: #ffffff;
  --accent-soft: #edf3ee;
  --warn-bg: #fdf6e8;
  --warn-line: #e8d4a8;

  --radius: 0.85rem;
  --radius-sm: 0.6rem;
  --measure: 44rem;
  --prose: 34rem;
}

/* Three states, and the default one stamps no attribute — so the media query has to
 * carry it, guarded so an explicit light choice still wins. Do not collapse these. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #10130f;
    --panel: #191d18;
    --ink: #eef2ec;
    --muted: #a3b0a6;
    --line: #2b312a;
    --control-line: #636e65;   /* 3.21:1 on --panel */
    --danger: #e8917f;
    --accent: #7fc79b;
    --accent-ink: #0d1410;
    --accent-soft: #1a231c;
    --warn-bg: #241f14;
    --warn-line: #4a3f26;
  }
}

:root[data-theme="dark"] {
  --bg: #10130f;
  --panel: #191d18;
  --ink: #eef2ec;
  --muted: #a3b0a6;
  --line: #2b312a;
  --control-line: #636e65;
  --danger: #e8917f;
  --accent: #7fc79b;
  --accent-ink: #0d1410;
  --accent-soft: #1a231c;
  --warn-bg: #241f14;
  --warn-line: #4a3f26;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 17px/1.65 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--accent); color: var(--accent-ink); }

a { color: var(--accent); text-underline-offset: 0.15em; }
a:hover { text-decoration-thickness: 2px; }

/* One visible focus ring for everything, because the form is the only thing on this
 * site that does anything and it has to be reachable from a keyboard. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

.wrap { max-width: var(--measure); margin: 0 auto; padding: 0 1.25rem 3rem; }

/* ---- the lockup ------------------------------------------------------------- */

/* /leaf.svg is the same curve the store icon and the launcher are drawn from — see
 * scripts/make-store-graphics.py. One file does both jobs, but not the same way:
 *
 *   as the favicon it is loaded standalone and inherits nothing, so it carries its
 *   own prefers-color-scheme rule and colours itself;
 *
 *   here it is a MASK, not an image, so only its alpha is used and the colour comes
 *   from currentColor — the page's own --accent. An <img> could not do that: its
 *   internal media query follows the OS, and would ignore a [data-theme] override
 *   set on the page, leaving a dark-mode leaf on a light-mode header.
 *
 * The background paint lives inside @supports so a browser without masks shows no
 * mark rather than a solid green rectangle. */
.lockup {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--accent);
  text-decoration: none;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-size: 1.1rem;
}
.leafmark { width: 1.45em; height: 1.45em; flex: none; display: block; }

@supports ((-webkit-mask-image: url("/leaf.svg")) or (mask-image: url("/leaf.svg"))) {
  .leafmark {
    background: currentColor;
    -webkit-mask: url("/leaf.svg") center / contain no-repeat;
    mask: url("/leaf.svg") center / contain no-repeat;
  }
}

header { padding: 3.5rem 0 1rem; }

h1 {
  font-size: clamp(2rem, 6vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.032em;
  margin: 1.75rem 0 0;
  font-weight: 700;
  text-wrap: balance;
}

.sub {
  font-size: 1.2rem;
  color: var(--muted);
  margin: 1.25rem 0 0;
  max-width: var(--prose);
  text-wrap: pretty;
}

/* ---- the form --------------------------------------------------------------- */

form { display: flex; gap: 0.6rem; flex-wrap: wrap; margin: 2.25rem 0 0.75rem; }

/* The label takes the whole first row; the field and the button share the next one. */
form label {
  flex: 1 0 100%;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: -0.15rem;
}

/* The error on a rejected submit, tied to the field by aria-describedby. Carries a
 * word as well as a colour, because colour alone is not a message. */
.formerror {
  flex: 1 0 100%;
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--danger);
}
input[type=email][aria-invalid="true"] { border-color: var(--danger); border-width: 2px; }

input[type=email] {
  flex: 1 1 16rem;
  min-width: 0;
  padding: 0.85rem 1rem;
  font: inherit;
  border: 1px solid var(--control-line);
  border-radius: var(--radius-sm);
  background: var(--panel);
  color: var(--ink);
}
input[type=email]::placeholder { color: var(--muted); opacity: 0.75; }
input[type=email]:hover { border-color: var(--accent); }

button {
  padding: 0.85rem 1.4rem;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-ink);
}
button:hover { filter: brightness(1.08); }
button:active { transform: translateY(1px); }

.formnote { font-size: 0.9rem; color: var(--muted); margin: 0; max-width: var(--prose); }

/* ---- the points ------------------------------------------------------------- */

section { padding: 3rem 0 0; }

h2 { font-size: 1.35rem; letter-spacing: -0.015em; margin: 0 0 0.6rem; font-weight: 700; }

.points { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }

/* A hairline between points rather than raw whitespace: five claims in a row need a
 * countable rhythm, or they read as one long paragraph. */
.points > li { padding: 1.6rem 0; border-top: 1px solid var(--line); }
.points > li:first-child { border-top: 0; padding-top: 0.4rem; }
.points h2 { color: var(--accent); }
.points p { margin: 0; color: var(--muted); max-width: var(--prose); text-wrap: pretty; }

/* ---- the callout ------------------------------------------------------------ */

.callout {
  background: var(--warn-bg);
  border: 1px solid var(--warn-line);
  border-radius: var(--radius);
  padding: 1.35rem 1.5rem;
  margin: 3rem 0 0;
}
.callout h2 { font-size: 1.1rem; }
.callout p { margin: 0.5rem 0 0; color: var(--ink); max-width: var(--prose); }

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

footer {
  margin: 4rem 0 0;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.9rem;
}
.ack { margin: 0.9rem 0 0; font-size: 0.85rem; line-height: 1.55; max-width: var(--prose); }

/* ---- the privacy page (body.doc) -------------------------------------------- */

.doc .wrap { padding-bottom: 5rem; }
.doc .lockup { margin: 2.5rem 0 0; }
.doc h1 { font-size: clamp(1.9rem, 5vw, 2.5rem); line-height: 1.15; margin: 1.5rem 0 0; }
.doc h2 { font-size: 1.3rem; letter-spacing: -0.01em; margin: 2.75rem 0 0; }
.doc p { margin: 1rem 0 0; }
.doc ul { margin: 1rem 0 0; padding-left: 1.25rem; }
.doc li { margin: 0.4rem 0; }
.doc hr { border: 0; border-top: 1px solid var(--line); margin: 2.5rem 0 0; }
.doc footer { font-size: 0.95rem; }
.doc .ack { font-size: 0.88rem; }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  background: var(--accent-soft);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.1em 0.35em;
}

blockquote {
  margin: 1.25rem 0 0;
  padding: 0.75rem 1rem;
  background: var(--panel);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--muted);
}

.tablewrap { overflow-x: auto; margin: 1.25rem 0 0; }
table { border-collapse: collapse; width: 100%; font-size: 0.95rem; }
th, td { text-align: left; vertical-align: top; padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--line); }
th { color: var(--muted); font-weight: 600; }

/* ---- the server's own reply pages (body.mid) -------------------------------- */

.mid {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.mid .box { max-width: 32rem; }
.mid h1 { font-size: 1.75rem; letter-spacing: -0.02em; margin: 0 0 1rem; }
.mid p { margin: 0 0 1rem; color: var(--muted); }
