/* ─── tokens — lifted straight from tokens/colors.ts ─────────────── */
/* One ground for the whole site. The front door is the member palette at
   full voice; every page behind it starts on that same ground, a shade
   deeper, and darkens the further down you read (see body below). There is
   no light theme any more, and so no toggle: these are the only values.

   Ink is cream at three strengths rather than three warm greys, because the
   same text has to read on terracotta at the top of a page and on near-black
   at the bottom of it. Warm greys went muddy on the colour; cream holds on
   both. */
:root {
  --bg:          #140d09;
  --surface:     #1a140e;
  --paper:       #1a140e;
  --paper-warm:  #2a1f17;
  --ink:         #FFF6E8;
  --ink2:        rgba(255,246,232,0.80);
  --ink-soft:    rgba(255,246,232,0.80);
  --ink-muted:   rgba(255,246,232,0.70);
  --rule:        rgba(255,246,232,0.16);
  --rule-strong: rgba(255,246,232,0.26);
  /* the accent is cream, not a colour: colour belongs to the members and
     the logo (see tokens/colors.ts accentDark). Every page is dark, so
     there is only the one value. */
  --brand:       #FFF6E8;
  --brand-deep:  #E8DCC6;
  --cream:       #FFFAF0;
  /* member palette — one color per person per table */
  --clay:   #c4643a;
  --blue:   #4a7a95;
  --green:  #7a9550;
  --gold:   #c49560;
  --purple: #a07ec4;
  --coral:  #d4776b;
  --ash:    #8a7a6b;
  /* card surfaces that stay physical (paper is paper on any ground) */
  --card-paper: #f4ebd8;
  --card-ink:   #2a1f15;
  --card-ink-soft: rgba(42,31,21,0.62);

  --serif: 'Source Serif 4', Georgia, serif;
  --sans: 'Inter', -apple-system, sans-serif;
  --hand: 'Caveat', cursive;
  /* the stuck nav's bar: the ground with a little of the page showing through */
  --bg-veil: rgba(20, 13, 9, 0.82);

  /* keeps form controls, scrollbars and the like dark */
  color-scheme: dark;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
::selection { background: var(--brand); color: var(--bg); }

html { scroll-behavior: smooth; }
/* The door's ground at the top of every page, a shade deeper, turning to
   near-black the further down you read. The heading sits on the colour
   and so does the first thing you see; the long reading below sits on the
   dark. Every layer is one 110vh tile pinned to the top of the document
   and scrolling with it, so the fade is measured in screens, not in page
   length: a forty-screen terms page and a one-screen invite darken at the
   same rate, and below 110vh there is only the dark background-color, which
   the top layer has already reached, so there's no seam.
   Layers, top to bottom: the dusk coming down; the door's five member-
   colour washes; the door's terracotta base. */
body {
  background-color: var(--bg);
  background-image:
    linear-gradient(to bottom,
      rgba(20,13,9,0.08) 0%,
      rgba(20,13,9,0.50) 34%,
      rgba(20,13,9,0.88) 66%,
      rgb(20,13,9)       100%),
    radial-gradient(110vw 85vh at 10% -10%, rgba(212,119,107,0.95), rgba(212,119,107,0) 62%),
    radial-gradient(90vw 72vh at 94% 2%,    rgba(196,149,96,0.88),  rgba(196,149,96,0) 60%),
    radial-gradient(85vw 78vh at 104% 60%,  rgba(160,126,196,0.62), rgba(160,126,196,0) 62%),
    radial-gradient(92vw 76vh at -6% 80%,   rgba(74,122,149,0.60),  rgba(74,122,149,0) 62%),
    linear-gradient(#b4552f, #b4552f);
  background-size: 100% 110vh;
  background-position: top left;
  background-repeat: no-repeat;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Fine grain over the ground. Without it a gradient this size reads
   plastic; with it the surface reads printed. z-index -1 puts it above the
   body's background (which paints on the canvas) and under every page's
   content, so no wrapper needs its own stacking context. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.085;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

.wrap { max-width: 680px; margin: 0 auto; padding: 0 22px; }

/* ─── type voices ─────────────────────────────────────────────────
   wordmark = /brand/*.svg              (outlines, not a font. see assets/brand)
   display  = Source Serif 4 ExtraBold  (headlines)
   en       = Source Serif 4 Italic     (en only. jealously.)
   sans     = Inter                     (ui, body, labels)
   hand     = Caveat                    (humans only)              */
.meta {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.en-voice { font-family: var(--serif); font-style: italic; }
.hand { font-family: var(--hand); }

a { color: inherit; }

/* ─── nav ───────────────────────────────────────────────────────────
   Sticks to the top of the viewport. Once it leaves its resting place
   (site.js sets .is-stuck off a sentinel) it grows a translucent bar and
   a hairline, and tightens its padding a little. */
nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 26px 0 22px;
  transition: padding 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* The bar bleeds past the 680px column to the window edges. It's a
   pseudo-element rather than a background on the nav so the nav's own
   contents stay inside the column. */
nav::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  z-index: -1;
  background: var(--bg-veil);
  border-bottom: 1px solid var(--rule);
  opacity: 0;
  transition: opacity 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
@supports (backdrop-filter: blur(1px)) {
  nav::before { backdrop-filter: blur(8px); }
}
nav.is-stuck { padding: 14px 0; }
nav.is-stuck::before { opacity: 1; }

/* The strip under the status bar. iOS 26 Safari fills it with one flat
   colour and ignores theme-color. It takes the background-color of a sticky
   or fixed element on the top edge, and with none (or a transparent one)
   the body's, which here is the near-black under the tile: a dark band over
   the coloured top of every page. So the nav's own background-color is the
   strip's colour: the tile's top edge at rest, the ground once stuck. It is
   clipped to the nav's text, which paints over it, so it never shows; Safari
   reads the property all the same. It has to be the nav's own: a change on
   ::before/::after is not picked up. Safari only re-reads it while the page
   scrolls, so site.js unsticks the nav a little before the top, leaving
   the last few scroll frames to pick the resting colour back up. */
nav {
  background-color: #b76c4d;
  -webkit-background-clip: text;
  background-clip: text;
}
nav.is-stuck { background-color: var(--bg); }
/* ...and the resting nav fades that colour into the tile, so the strip and
   the page meet without an edge. */
nav::after {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: 100vw;
  height: 44px;
  margin-left: -50vw;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(#b76c4d, rgba(183,108,77,0));
}
nav.is-stuck::after { display: none; }

/* the 100vw bar overhangs by the scrollbar width; clip rather than hide,
   because overflow:hidden here would make the nav's sticky stop working. */
body { overflow-x: clip; }
html { scroll-padding-top: 84px; }
/* The wordmark is outlines (assets/brand/README.md), the small cut: the
   plate's rim only shows at hero sizes. */
.wordmark {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  line-height: 0;
}
.wordmark img { display: block; height: 26px; width: auto; }
.nav-link {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.1px;
  color: var(--ink);
  text-decoration: none;
  transition: opacity 140ms ease;
}
.nav-link:hover { opacity: 0.74; }
.nav-link:hover .arrow { transform: translateX(3px); }
.nav-link.back:hover .arrow { transform: translateX(-3px); }
.arrow { display: inline-block; transition: transform 160ms cubic-bezier(0.22,1,0.36,1); }

/* ─── buttons — flat matte cream, radius = 38% height ────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 64px;
  padding: 0 44px;
  border-radius: 24px;
  background: var(--brand);
  color: var(--bg);
  font-family: var(--sans);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.16px;
  text-transform: lowercase;
  text-decoration: none;
  border: none;
  cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}
.btn:hover { background: var(--brand-deep); }
.btn:active { background: var(--brand-deep); transform: translateY(1px); }

/* ─── app store badge ─────────────────────────────────────────────
   Apple's own artwork (marketingtools.apple.com), unmodified. Their
   identity guidelines want the white badge on dark surfaces, and every
   page is dark now, so the white one always shows. Pages still ship both
   images; the black one is kept out of the way rather than deleted from
   five pages' markup. The link carries the accessible name — both images
   are decorative.
   Guidelines also ask for clear space of at least 1/4 the badge
   height on every side; at 56px that is 14px, which is the gap the
   CTA stacks already use. Don't tighten it. */
.app-store {
  display: inline-block;
  line-height: 0;
  border-radius: 9px;
  transition: opacity 120ms ease, transform 120ms ease;
}
.app-store:hover  { opacity: 0.86; }
.app-store:active { transform: translateY(1px); }
.app-store img { display: block; height: 56px; width: auto; }

.app-store .on-light { display: none; }
.app-store .on-dark  { display: block; }

/* ─── the squiggle under the door's turn ──────────────────────────── */
.squiggle { margin: 14px auto 0; display: block; }
.squiggle path {
  stroke-dasharray: 190;
  stroke-dashoffset: 190;
  animation: draw 900ms cubic-bezier(0.22,1,0.36,1) 500ms forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }

/* ─── footer ──────────────────────────────────────────────────────── */
footer {
  border-top: 1px solid var(--rule);
  padding: 22px 0 36px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
footer .links { display: flex; gap: 18px; }
footer a { font-size: 12px; color: var(--ink-muted); text-decoration: none; }
footer a:hover { color: var(--ink-soft); }
footer .word { display: block; height: 20px; width: auto; opacity: 0.7; }

/* ─── scroll reveal — same settle bezier the app uses ─────────────── */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity 420ms cubic-bezier(0.22,1,0.36,1), transform 420ms cubic-bezier(0.22,1,0.36,1); }
.reveal.in { opacity: 1; transform: none; }

/* ─── support page ────────────────────────────────────────────────── */
.support-rows { margin-top: 34px; border-top: 1px solid var(--rule); }
.support-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 20px 0;
  border-bottom: 1px solid var(--rule);
}
.support-row b { font-family: var(--serif); font-weight: 700; font-size: 18px; letter-spacing: -0.01em; }
.support-row p { font-size: 13px; color: var(--ink-soft); margin-top: 3px; max-width: 42ch; }
.support-row a { color: var(--ink); text-decoration: none; font-size: 14px; font-weight: 500; white-space: nowrap; }
.support-row a:hover { text-decoration: underline; }

@media (max-width: 560px) {
  .support-row { flex-direction: column; gap: 8px; }
  .support-row a { white-space: normal; }
  /* the wordmark and the link row crowd each other below ~400px. this used to
     live in catch.html only, so every other page kept the cramped row. */
  footer { flex-direction: column; align-items: flex-start; gap: 14px; }
  footer .links { flex-wrap: wrap; gap: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .squiggle path { animation: none; stroke-dashoffset: 0; }
  .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}
