/* ─────────────────────────────────────────────────────────────
   Every plans page: the landing page and the documents alike.

   The top half is the shared surface - the two faces, the night
   garden tokens, the fixed ground layers, the reveal and the
   hovers. It is the single copy; index.html links this file
   rather than restating any of it.

   The bottom half is the document pages only: one comfortable
   column built to be read.
   ───────────────────────────────────────────────────────────── */

/* The app's own faces. Fraunces is variable: the display cuts below set
   SOFT and WONK exactly as Typography.swift does, so headings carry the
   same softened, slightly wonky drawing as the plan-name screen. */
/* `block`, not `swap`. Under swap the browser paints the fallback first
   and reflows when the real face lands - and the metrics are nowhere near
   each other: "Plans." sets 423px wide in Georgia against 344px in
   Fraunces, so the headline visibly snapped 79px on load. Block paints
   nothing until the face is ready, and since these are same-origin and
   preloaded, "not yet" lasts a few milliseconds.
   The italic cut is gone: nothing on this page is set in italic any more
   (the lede, the sign-off and the whisper were all uprighted), so it was
   415KB fetched to be used by nothing. */
@font-face {
  font-family: "Fraunces";
  src: url("fonts/Fraunces-Variable.ttf") format("truetype-variations");
  font-weight: 100 900; font-style: normal; font-display: block;
}
@font-face {
  font-family: "Geist";
  src: url("fonts/Geist-Variable.ttf") format("truetype-variations");
  font-weight: 100 900; font-style: normal; font-display: block;
}

/* Dark-mode tokens from Colors.swift. This page commits to the app's
   night garden - there is no light variant by design. */
:root {
  --canvas-top:  #171c0a;
  --canvas-glow: #222b10;
  --canvas-deep: #0b0e05;
  --ink:         #eaede2;
  --ink-soft:    #c3cea4;
  --brand:       #a3b85c;
  --brand-solid: #6a7c30;
  --stone:       #7e8a72;
  --line:        #2a3316;

  --display: "Fraunces", Georgia, serif;
  --body: "Geist", -apple-system, BlinkMacSystemFont, sans-serif;
  /* The display cut used for the h1 alone; everything else in Fraunces
     sits at SOFT 0, the drawing the About frame in Figma specifies. */
  /* Two cuts, and SOFT 100 on both. The soft axis is the app's own
     drawing - it was reaching the h1 and nothing else, so every other
     line of Fraunces on the site was set in a different face to the
     headline above it. `--soft` (wght 400) is retired: nothing used it. */
  --soft-head:  "wght" 600, "SOFT" 100, "WONK" 1;
  --soft-quiet: "wght" 300, "SOFT" 100, "WONK" 1;

  /* The builder's cubic-bezier(.34,1.56,.64,1); FlowerNativeView
     approximates the same curve as easeOutBack. */
  --unfurl: cubic-bezier(.34, 1.56, .64, 1);
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { background: var(--canvas-deep); }

/* ScrollSmoother drives the scroll: it transforms #smooth-content and
   lets the page catch up on a lag. The ground, grain and vignette stay
   outside the wrapper - they are fixed, and must not ride the transform. */
#smooth-wrapper { position: relative; z-index: 1; }

body {
  background: var(--canvas-deep);
  color: var(--ink);
  font-family: var(--body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ── The ground ───────────────────────────────────────────────
   The app's drifting mesh, with one addition for this page: a
   third pool of light that follows the cursor like a lantern.
   Paper grain painted once, vignette so the corners fall away. */
.ground, .ground-gl, .grain, .vignette {
  position: fixed; inset: 0; pointer-events: none; z-index: 0;
}
/* The grain was a <canvas> with no CSS size. A replaced element with
   `inset: 0` and `width: auto` takes its INTRINSIC size, so the canvas
   displayed at its dpr-scaled backing store - 2560x1800 on a retina
   screen - while only the top-left viewport-sized rectangle of it was
   ever painted. The hard horizontal edge where that painted region
   ended was the "divider". It is a div with a tiled background now, so
   it has no intrinsic size to get wrong. */
.ground-gl { width: 100%; height: 100%; opacity: 0; transition: opacity 1.4s ease; }
.ground-gl.lit { opacity: 1; }
.ground {
  background:
    radial-gradient(ellipse 70% 55% at 30% 22%, var(--canvas-glow), transparent 66%),
    radial-gradient(ellipse 60% 50% at 76% 74%, #1b2210, transparent 70%),
    linear-gradient(168deg, var(--canvas-top) 0%, var(--canvas-deep) 72%);
  animation: drift 48s ease-in-out infinite;
}
@keyframes drift {
  0%, 100% { transform: scale(1.06) translate(0, 0); }
  50%      { transform: scale(1.12) translate(-2.2%, 1.6%); }
}
/* Film grain, not paper texture: a low-alpha noise tile blended as
   light, which is the only way grain reads on a near-black ground -
   `overlay` against #0b0e05 resolves to multiply and all but vanishes.
   Inset past the edges so the drift never exposes a corner. */
.grain {
  inset: -6%;
  opacity: .5;
  mix-blend-mode: screen;
  background-image: var(--grain-tile);
  background-repeat: repeat;
  background-size: var(--grain-size);
  will-change: transform;
}
.js .grain { animation: grainshift 1.1s steps(1) infinite; }
@keyframes grainshift {
  0%   { transform: translate3d(0, 0, 0); }
  20%  { transform: translate3d(-1.2%, 0.8%, 0); }
  40%  { transform: translate3d(0.9%, -1.4%, 0); }
  60%  { transform: translate3d(-0.7%, -0.6%, 0); }
  80%  { transform: translate3d(1.1%, 1.2%, 0); }
}
/* There were TWO vignettes: this one and the shader's. A CSS gradient
   gets no dithering, so its onset at 42% quantised into a visible ring
   over the near-black ground - the circle in the background. The shader
   owns the vignette wherever WebGL runs; this is only the fallback, and
   it is stepped through several stops so the ramp has no single edge
   to band on. */
.vignette {
  background: radial-gradient(ellipse at 50% 45%,
    transparent 0%,
    rgba(0,0,0,0.06) 38%,
    rgba(0,0,0,0.18) 58%,
    rgba(0,0,0,0.34) 78%,
    rgba(0,0,0,0.52) 100%);
}
.ground-gl.lit ~ .vignette { display: none; }

main { position: relative; z-index: 1; }

/* ── Reveal ─────────────────────────────────────────────────── */
.fi { opacity: 1; }
.js .fi {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .9s cubic-bezier(.22,.61,.36,1), transform .9s cubic-bezier(.22,.61,.36,1);
}
.fi.vis { opacity: 1; transform: none; }
.fi[data-d="1"] { transition-delay: .1s; }
.fi[data-d="2"] { transition-delay: .2s; }

/* ── The pill, and the quiet links ────────────────────────────
   Shared so the button on a policy page is the same object as the
   button on the landing page, down to the hover. */
.cta {
  display: inline-block;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--brand-solid);
  color: rgba(234,237,226,.8);
  text-decoration: none;
  font-size: 12px;
  background: rgba(106,124,48,.58);
  transition: background .3s ease;
}
.cta:hover { background: rgba(106,124,48,.78); }
.cta:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* GSAP owns these once it has loaded; leaving the transitions on
   would ease the same property twice. Qualified on `html` because
   the rules it has to outrank sit later in this sheet. */
html.gsap-ui .cta,
html.gsap-ui .legal a,
html.gsap-ui .back,
html.gsap-ui footer a,
html.gsap-ui .fi { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .ground, .grain { animation: none; }
  .fi { opacity: 1; transform: none; transition: none; }
}


/* ═══ Document pages ══════════════════════════════════════ */

/* Everything below is scoped to `.page`, the document column. It used to
   use bare element selectors - `footer`, `p`, `a`, `h1` - which is fine
   in a sheet only documents load, but this sheet is now shared with the
   landing page. `footer { border-top: 1px solid var(--line) }` was
   drawing a hairline across the bottom of index.html, and `p`'s measure
   and margins were leaking into the tier row. */

/* A document sets its own reading colour and measure; the shared body
   above is the landing page's, which is display-sized. */

.page {
  max-width: 660px;
  margin: 0 auto;
  padding: 68px 28px 120px;
  color: var(--ink-soft);
  font-size: 16px;
  line-height: 1.75;
}
/* ── Masthead ───────────────────────────────────────────────── */

.page .back {
  display: inline-block;
  font-size: 13px;
  color: var(--stone);
  text-decoration: none;
  margin-bottom: 52px;
  transition: color .2s ease;
}

.page .back:hover { color: var(--brand); }

.page h1 {
  font-family: var(--display);
  font-variation-settings: var(--soft-head);
  font-weight: 600;
  font-size: clamp(34px, 5.5vw, 50px);
  line-height: 1.06;
  letter-spacing: -0.04em;
  color: var(--ink);
  margin-bottom: 14px;
  text-wrap: balance;
}

.page .standfirst {
  font-family: var(--display);
  font-variation-settings: var(--soft-quiet);
  font-weight: 300;
  font-size: clamp(17px, 2.1vw, 20px);
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: var(--ink-soft);
  max-width: 40ch;
  text-wrap: balance;
}

.page .stamp {
  font-size: 13px;
  color: var(--stone);
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
/* ── Body ───────────────────────────────────────────────────── */

.page h2 {
  font-family: var(--display);
  font-variation-settings: var(--soft-head);
  font-weight: 600;
  font-size: clamp(23px, 3vw, 29px);
  line-height: 1.15;
  letter-spacing: -0.035em;
  color: var(--ink);
  margin: 58px 0 16px;
  text-wrap: balance;
}

.page h3 {
  font-family: var(--body);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin: 30px 0 8px;
}

.page p { margin-bottom: 17px; max-width: 68ch; text-wrap: pretty; }

.page a { color: var(--brand); text-decoration-thickness: 1px; text-underline-offset: 3px; }

.page a:hover { color: var(--ink); }

.page a:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 3px;
}

.page strong { color: var(--ink); font-weight: 500; }

.page ul { margin: 0 0 18px 0; padding-left: 20px; max-width: 68ch; }

.page li { margin-bottom: 9px; }

.page li::marker { color: var(--brand-solid); }
/* A quiet slab for the one thing on a page that matters most —
   the plain-language summary, or the contact address. */

.page .note {
  background: rgba(34, 43, 16, 0.5);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 22px 26px;
  margin: 26px 0;
}

.page .note p:last-child { margin-bottom: 0; }

.page .note .lead {
  font-family: var(--display);
  font-variation-settings: var(--soft-head);
  font-weight: 600;
  font-size: 19px;
  line-height: 1.4;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin-bottom: 10px;
}
/* ── Definition rows, for credits and contact ───────────────── */

.page .rows { border-top: 1px solid var(--line); margin: 22px 0 26px; }

.page .row {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 20px;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
}

.page .row dt {
  font-family: var(--display);
  font-variation-settings: var(--soft-head);
  font-weight: 600;
  font-size: 17px;
  letter-spacing: -0.03em;
  color: var(--ink-soft);
}

.page .row dd { font-size: 14.5px; color: var(--stone); line-height: 1.65; }

.page .row dd p { margin-bottom: 8px; }

.page .row dd p:last-child { margin-bottom: 0; }
/* ── Footer ─────────────────────────────────────────────────── */

.page footer {
  margin-top: 84px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  align-items: baseline;
  font-size: 13px;
  color: var(--stone);
}

.page footer a { color: var(--stone); text-decoration: none; }

.page footer a:hover { color: var(--brand); }

.page footer .sign-off {
  flex-basis: 100%;
  font-family: var(--display);
  font-variation-settings: var(--soft-quiet);
  font-weight: 300;
  font-size: 19px;
  line-height: 1.2;
  letter-spacing: -0.512px;
  color: var(--ink-soft);
  margin-top: 14px;
}

@media (max-width: 560px) {
  .row { grid-template-columns: 1fr; gap: 4px; }
  .page { padding: 52px 22px 90px; }
}
/* ── Suggestion box ─────────────────────────────────────────────
   A form rather than a published address: the email lives with the
   relay service, not in this page's source where it can be scraped.
   Submission is a plain fetch to the relay — no embedded widget, no
   third-party script, and so nothing that sets a cookie. */

.page .box { margin: 26px 0; }

.page .box .field { margin-bottom: 16px; }

.page .box label {
  display: block;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--stone);
  margin-bottom: 7px;
}

.page .box textarea,
.page .box input[type="email"] {
  width: 100%;
  background: rgba(11, 14, 5, 0.55);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 12px 14px;
  color: var(--ink);
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.6;
  transition: border-color 160ms ease;
}

.page .box textarea { min-height: 132px; resize: vertical; }

.page .box textarea::placeholder,
.page .box input[type="email"]::placeholder { color: #5d6a4f; }

.page .box textarea:focus,
.page .box input[type="email"]:focus {
  outline: none;
  border-color: var(--brand-solid);
}
/* Bots fill every field they find; people never see this one. */

.page .box .botcheck {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.page .box button {
  background: rgba(106, 124, 48, 0.58);
  border: 1px solid var(--brand-solid);
  border-radius: 999px;
  padding: 10px 22px;
  color: rgba(234,237,226,.8);
  font-family: var(--body);
  font-size: 13px;
  cursor: pointer;
  transition: background .3s ease;
}

.page .box button:hover { background: rgba(106, 124, 48, 0.78); }

.page .box button:disabled { opacity: 0.5; cursor: default; }

.page .box button:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

.page .box .status {
  margin-top: 14px;
  font-size: 14.5px;
  color: var(--stone);
  min-height: 1.6em;
}

.page .box .status.ok { color: var(--brand); }

.page .box .status.bad { color: #e8a0a0; }
