/* ⚠️ **Dark, unconditionally** (owner, 2026-08-10) — not "dark unless the
   visitor prefers light". Every screenshot on this site is the app's dark
   theme, and on a pale page twelve dark rectangles read as holes punched in the
   layout; on a dark ground they are lit objects. The light palette is deleted
   rather than left behind a media query, because a half-used second theme is
   how contrast bugs survive.
   ⭐ To follow the visitor's system again: restore the light values here and
   wrap these dark ones in a prefers-color-scheme media query.
   ⚠️ No backticks anywhere in this stylesheet — it is a template literal. */
:root {
  color-scheme: dark;
  --bg: #14162A; --card: #1E2035; --text: #ECEDF5; --muted: #9AA0B8;
  --border: #333650; --accent: #9184D9; --accent-text: #CFC8F7;
  --shadow: none;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 400 17px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
  padding: 0 20px;
}
/* ⚠️ **One page width everywhere** (owner, 2026-08-10). Help, Privacy and Terms
   used to sit in a 680px column while the landing used 1080, so the logo and
   the nav jumped sideways every time you changed page — the chrome moving is
   what reads as broken, not the column itself.
   ⭐ The prose still gets a readable measure: .doc caps the DOCUMENT body at
   ~72 characters. A legal clause set across 1080px is about 140 characters a
   line, which is roughly twice what anyone can track back to the next line. So
   the frame is shared and only the text is narrow. */
.wrap { max-width: 1080px; margin: 0 auto; padding: 56px 0 80px; }
.doc { max-width: 720px; }
a { color: var(--accent-text); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }
h1 { font-size: 34px; line-height: 1.2; letter-spacing: -.02em; margin: 0 0 12px; font-weight: 600; }
h2 { font-size: 21px; line-height: 1.35; margin: 40px 0 10px; font-weight: 600; }
h3 { font-size: 17px; margin: 0; font-weight: 600; }
p  { margin: 0 0 16px; }
.lede { font-size: 19px; color: var(--muted); margin-bottom: 28px; }
.meta { font-size: 14px; color: var(--muted); }

/* Dividers fade at both ends — a plain hairline is not this design language. */
.rule {
  height: 1px; border: 0; margin: 40px 0;
  background: linear-gradient(90deg, transparent, var(--border) 18%, var(--border) 82%, transparent);
}
nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; font-size: 15px; margin-bottom: 44px;
}
nav a { color: var(--muted); text-decoration: none; }
nav a:hover, nav a[aria-current="page"] { color: var(--accent-text); }
.nav-links { display: flex; gap: 22px; flex-wrap: wrap; }

/* The lockup: mark plus wordmark, and the only nav item carrying brand colour.
   The mark takes the accent; the word takes the text colour, so the pairing
   reads as one object rather than two coloured things. */
.brand { display: inline-flex; align-items: center; gap: 13px; }
.brand b { font-size: 32px; font-weight: 650; letter-spacing: -.025em; color: var(--text); }
.brand .mark { color: var(--accent); flex: none; }
.brand:hover b { color: var(--accent-text); }
@media (max-width: 640px) {
  .brand b { font-size: 24px; }
  .brand .mark { width: 36px; height: 36px; }
}
.foot-brand {
  display: flex; align-items: center; gap: 8px;
  font-size: 16px; font-weight: 600; color: var(--text); margin-bottom: 10px;
}
.foot-brand .mark { color: var(--accent); }

.card {
  background: var(--card); border: 1px solid var(--border); border-radius: 14px;
  padding: 18px 20px; margin: 0 0 12px; box-shadow: var(--shadow);
}
.card p:last-child { margin-bottom: 0; }
.card h3 { margin-bottom: 8px; }

/* Outlined, never filled — emphasis is a border and a colour, not a slab. */
.btn {
  display: inline-block; border: 1px solid var(--accent); color: var(--accent-text);
  border-radius: 999px; padding: 11px 22px; text-decoration: none; font-weight: 500;
  background: transparent;
}
.btn:hover { border-color: var(--accent-text); }

ul, ol { padding-left: 22px; margin: 0 0 16px; }
li { margin-bottom: 8px; }

/* Belt and braces for the join page, which toggles two cards with [hidden].
   A later rule setting display on .card would otherwise silently show both. */
[hidden] { display: none !important; }

/* An invite code exists to be transcribed into a phone, so it is monospace and
   loosely tracked: the eye has to hold twelve characters across a room. */
.code {
  font: 500 20px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .12em; margin: 0 0 8px; word-break: break-all;
}
footer { margin-top: 56px; font-size: 14px; color: var(--muted); }
footer a { color: var(--muted); }
@media (max-width: 520px) {
  body { padding: 0 16px; }
  .wrap { padding: 36px 0 56px; }
  h1 { font-size: 28px; }
}

/* ── The landing page ─────────────────────────────────────────────────────
   Only the landing uses this. Help, Privacy, Terms and Join stay in the 680px
   reading column, because they are documents and a document wants one column.  */
.wrap-wide { max-width: 1080px; }  /* kept: every page is this width now */

/* The court, behind the hero — the same drawing the app puts behind its
   sign-in screen, so the site and the product share one picture rather than
   two that merely match. Strokes only: this design language says imagery is a
   line, a ring or a glow, never a filled area or a photograph. */
.hero { position: relative; display: grid; grid-template-columns: 1fr auto; gap: 56px; align-items: center; }
.hero-art {
  position: absolute; inset: -60px -40px -40px -60px; z-index: 0;
  pointer-events: none; overflow: hidden;
}
.hero-art svg { width: 100%; height: 100%; }

/* The shuttle, with the screen's one glow — the same mark the app flies beside
   its wordmark. Positioned in the gap above the phone, which is the only part
   of the hero that never carries text at any width. Hidden once the hero stacks,
   because at that point there is no gap left for it to sit in. */
/* ⚠️ Anchored into the GAP between the copy and the phone, not the top-right
   corner — at right:3% it sat squarely behind the phone, which paints later in
   the DOM and hid it completely. */
.hero-shuttle { position: absolute; top: 8px; right: 27%; width: 124px; z-index: 1; pointer-events: none; }
.hero-shuttle svg { display: block; width: 100%; height: auto; }
@media (max-width: 900px) { .hero-shuttle { display: none; } }
/* ⚠️ :not(.hero-art) is load-bearing. Without it this rule out-specifies the
   absolute positioning above (class+type beats class), the backdrop rejoins the
   grid as a third column, and the phone is pushed onto its own row. */
.hero > div:not(.hero-art):not(.hero-shuttle), .hero > .phone { position: relative; z-index: 1; }
/* ⚠️ Tight tracking crowds a headline made of three sentences: at -.035em the
   full stops collided with the next word and it read as one long token. The
   tracking is eased and word-spacing opened, so each beat lands separately —
   which is the whole point of writing it as three sentences. */
.hero h1 {
  font-size: 52px; letter-spacing: -.018em; word-spacing: .14em;
  margin-bottom: 20px; line-height: 1.08;
}
.eyebrow {
  font-size: 13px; font-weight: 600; letter-spacing: .09em; text-transform: uppercase;
  color: var(--accent-text); margin: 0 0 14px;
}
/* Problem, then answer, in two weights: the muted paragraph is the reader's
   current Tuesday night, the solid one is what changes. */
.hero .problem { font-size: 19px; color: var(--muted); margin: 0 0 12px; max-width: 40ch; }
.hero .solve   { font-size: 19px; color: var(--text);  margin: 0 0 26px; max-width: 40ch; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 26px; padding: 0; list-style: none; }
.chips li {
  font-size: 13.5px; color: var(--muted); border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 13px; margin: 0;
  /* ⚠️ Opaque, not transparent. These are outlined pills sitting over the hero
     court, and with no ground the floor lines ran straight through "Free for
     use". Filling them with the page colour changes nothing visually and stops
     the backdrop showing through. Same reason the CTA below carries it. */
  background: var(--bg);
}
.hero .btn { background: var(--bg); }

/* A phone, drawn rather than photographed: a rounded frame and a hairline.
   No glossy device chrome — the screen is the subject.                      */
.phone {
  width: 310px; flex: none; border-radius: 42px; padding: 9px;
  background: var(--card); border: 1px solid var(--border);
  /* ⚠️ Unconditional, like the palette. This was behind a prefers-color-scheme
     query, which stopped making sense the moment the page became dark for
     everyone: a visitor whose SYSTEM is light would have got the pale shadow
     against our dark ground, and the phone would have floated with no weight. */
  box-shadow: 0 24px 60px rgba(0, 0, 0, .45);
}
/* ⚠️ height:auto is load-bearing. The hero image carries width/height
   attributes so the browser can reserve its box before the JPEG lands (no
   layout shift) — but an HTML height attribute beats CSS that only sets
   width, and the hero rendered 2796px tall until this was added.
   ⚠️ No backticks anywhere in this stylesheet: it is a template literal, and
   a stray one ends it mid-rule. That has now cost two builds. */
.phone img, .phone .stack { display: block; width: 100%; height: auto; border-radius: 34px; }
.phone .stack { position: relative; aspect-ratio: 1290 / 2796; overflow: hidden; }
.phone .stack img { position: absolute; inset: 0; height: 100%; object-fit: cover; }

.section-head { max-width: 60ch; }
.section-head h2 { font-size: 27px; margin-top: 0; }

/* ── The two workflow players ─────────────────────────────────────────────
   Pure CSS, no script. The /join page is the only one here allowed inline
   JavaScript and it had to argue for it; a marketing animation does not clear
   that bar, so the frames cross-fade on a shared keyframe and each one is
   offset by a negative animation-delay. The step list runs the same clock, so
   the caption and the screen can never drift apart.                          */
.flow { display: grid; grid-template-columns: auto 1fr; gap: 48px; align-items: center; }
.flow-steps { list-style: none; padding: 0; margin: 0; counter-reset: step; }
.flow-steps li {
  counter-increment: step; position: relative; padding: 14px 0 14px 52px;
  border-top: 1px solid var(--border); margin: 0; opacity: .45;
  animation: stepOn var(--dur) infinite;
}
.flow-steps li:first-child { border-top: 0; }
.flow-steps li::before {
  content: counter(step); position: absolute; left: 0; top: 12px;
  width: 32px; height: 32px; border-radius: 999px; border: 1px solid var(--accent);
  color: var(--accent-text); font-size: 14px; font-weight: 600;
  display: grid; place-items: center;
}
.flow-steps b { display: block; font-weight: 600; }
.flow-steps span { color: var(--muted); font-size: 15px; }
.flow .stack img { opacity: 0; animation: frameOn var(--dur) infinite; }

/* ⚠️ The visible window starts AT 0%, not after a fade-in. With a fade at the
   front, every frame sat at opacity 0 for the first instant of the cycle and
   the phone flashed empty on load. Wrapping the last 2% back to 1 means the
   outgoing frame is still fading as the next one takes over. */
@keyframes frameOn {
  0%, 18%  { opacity: 1; }
  20%, 98% { opacity: 0; }
  100%     { opacity: 1; }
}
@keyframes stepOn {
  0%, 18%  { opacity: 1; }
  20%, 98% { opacity: .4; }
  100%     { opacity: 1; }
}

/* Reduced motion gets the whole story at once, as a filmstrip — the frames are
   the content, so they must not simply vanish when the animation does.        */
@media (prefers-reduced-motion: reduce) {
  .flow { display: block; }
  .flow .phone { display: none; }
  .flow-steps li { opacity: 1; animation: none; }
  .filmstrip { display: grid !important; }
}
.filmstrip {
  display: none; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px; margin-top: 22px;
}
.filmstrip img { width: 100%; border-radius: 14px; border: 1px solid var(--border); }

/* Image-led feature cards: the picture carries the point, the words caption it. */
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px; }
.shot {
  background: var(--card); border: 1px solid var(--border); border-radius: 18px;
  padding: 18px; box-shadow: var(--shadow);
}
.shot img { width: 100%; border-radius: 12px; display: block; margin-bottom: 14px; }
.shot h3 { margin-bottom: 6px; }
.shot p { margin: 0; color: var(--muted); font-size: 15px; }

@media (max-width: 900px) {
  .hero, .flow { grid-template-columns: 1fr; gap: 32px; }
  .hero .phone, .flow .phone { justify-self: center; }
  .hero h1 { font-size: 34px; }
  .hero .lede { max-width: none; }
}
