/* Nocturne, ported to the web so the site and the app are visibly the same
   product. Tokens mirror src/theme/tokens.ts exactly. */

:root {
  --bg: #161826;
  --surface: #232532;
  --text: #e9e9ed;
  --accent: #9184d9;
  --accent-300: #d2cefd;
  --neutral-300: #cfd3e5;
  --neutral-500: #9397ab;
  --neutral-600: #75798c;
  --neutral-800: #3f424d;
  --divider: rgba(233, 233, 237, 0.16);
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

.wrap {
  max-width: 46rem;
  margin: 0 auto;
  padding: 4rem 1.5rem 6rem;
}

.mark { display: inline-block; margin-bottom: 1.5rem; }

h1 {
  font-size: 2.6rem;
  font-weight: 500;
  letter-spacing: -0.03em;
  margin: 0 0 0.25rem;
}

h2 {
  font-size: 1.3rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  margin: 2.5rem 0 0.75rem;
}

h3 {
  font-size: 1.05rem;
  font-weight: 500;
  margin: 1.75rem 0 0.5rem;
}

.sub {
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--neutral-600);
  margin: 0 0 2rem;
}

.lede { font-size: 1.15rem; color: var(--neutral-300); margin: 0 0 0.75rem; }
.muted { color: var(--neutral-500); margin: 0 0 1rem; }
p { margin: 0 0 1rem; }
strong { font-weight: 500; color: var(--text); }

/* Rules fade to transparent at both ends — a Nocturne signature. */
.rule {
  height: 1px;
  border: 0;
  margin: 2.5rem 0;
  background: linear-gradient(to right,
    transparent, var(--divider) 48px,
    var(--divider) calc(100% - 48px), transparent);
}

a { color: var(--accent); text-underline-offset: 3px; }
a:hover { color: var(--accent-300); }
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

.links { display: flex; flex-wrap: wrap; gap: 1.5rem; font-size: 0.95rem; }

.back {
  display: inline-block;
  font-size: 0.9rem;
  margin-bottom: 2rem;
  text-decoration: none;
}
.back:hover { text-decoration: underline; }

.kicker {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.75rem;
}

.panel {
  background: var(--surface);
  border: 1px solid var(--neutral-800);
  border-radius: 14px;
  padding: 1.5rem;
  margin: 1.5rem 0;
}

.panel-accent {
  background: rgba(145, 132, 217, 0.07);
  border: 1px solid rgba(145, 132, 217, 0.32);
  border-radius: 10px;
  padding: 1.25rem 1.5rem;
  margin: 1.5rem 0;
}

ul { padding-left: 1.25rem; margin: 0 0 1rem; }
li { margin-bottom: 0.4rem; color: var(--neutral-300); }

table { width: 100%; border-collapse: collapse; font-size: 0.95rem; margin: 1rem 0 1.5rem; }
th {
  text-align: left;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--neutral-600);
  padding: 0.5rem 0.75rem 0.5rem 0;
  border-bottom: 1px solid var(--divider);
}
td {
  padding: 0.65rem 0.75rem 0.65rem 0;
  border-bottom: 1px solid rgba(233, 233, 237, 0.08);
  color: var(--neutral-300);
  vertical-align: top;
}

.updated { font-size: 0.85rem; color: var(--neutral-600); }

label { display: block; font-size: 0.85rem; color: var(--neutral-500); margin-bottom: 0.35rem; }

input[type="email"] {
  width: 100%;
  min-height: 48px;
  padding: 0.6rem 0.9rem;
  font: inherit;
  font-size: 1rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: 8px;
  margin-bottom: 1rem;
}
input[type="email"]:focus-visible { border-color: var(--accent); outline: none; }

/* Primary actions are an accent outline on transparent, never a fill. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 0 1.25rem;
  font: inherit;
  font-size: 1rem;
  color: var(--accent);
  background: transparent;
  border: 1px solid var(--accent);
  border-radius: 12px;
  cursor: pointer;
}
.btn:hover { background: rgba(145, 132, 217, 0.12); }
.btn:active { background: rgba(145, 132, 217, 0.22); }


/* ═══ Site chrome ═══════════════════════════════════════════════════════════
   Added 2026-08-28, when the site grew past one page. Every page now carries
   the same header and the same footer, and the footer is the only place the
   parent company is named. Tokens above are unchanged — nothing here invents a
   color or a radius that the app does not already use.                       */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin-bottom: 3rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--text);
}
.brand svg { flex: none; }
.brand-word {
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.35rem;
  font-size: 0.9rem;
}
.site-nav a {
  color: var(--neutral-500);
  text-decoration: none;
  padding: 0.25rem 0;
}
.site-nav a:hover { color: var(--accent-300); }
.site-nav a[aria-current="page"] { color: var(--text); }

/* ── Hero ─────────────────────────────────────────────────────────────── */

.hero { margin-bottom: 3rem; }
.hero h1 { font-size: 3rem; margin-bottom: 0.15rem; }

.status-pill {
  display: inline-block;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid rgba(145, 132, 217, 0.4);
  border-radius: 999px;
  padding: 0.3rem 0.75rem;
  margin-bottom: 1.5rem;
}

/* ── Numbers ──────────────────────────────────────────────────────────── */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  gap: 1rem 1.5rem;
  margin: 2rem 0;
  padding: 1.5rem 0;
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
}
.stat-n {
  display: block;
  font-size: 1.9rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
.stat-l {
  display: block;
  font-size: 0.72rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--neutral-600);
  margin-top: 0.2rem;
}

/* ── Feature grid ─────────────────────────────────────────────────────── */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 1.5rem 0 2rem;
}
.card {
  background: var(--surface);
  border: 1px solid var(--neutral-800);
  border-radius: 14px;
  padding: 1.35rem;
}
.card h3 { margin: 0 0 0.4rem; font-size: 1rem; }
.card p { margin: 0; color: var(--neutral-500); font-size: 0.94rem; }

/* ── Embeds ───────────────────────────────────────────────────────────────
   The board is a third-party frame, so it needs its own CSP allowance in
   netlify.toml. The wrapper exists so a long board scrolls inside itself
   rather than pushing the page sideways on a phone.                        */

.embed-frame {
  border: 1px solid var(--neutral-800);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface);
  margin: 1.5rem 0;
}
.embed-frame iframe {
  display: block;
  width: 100%;
  height: 700px;
  border: 0;
  background: transparent;
}
@media (max-width: 40rem) {
  .embed-frame iframe { height: 560px; }
}

/* ── Footer ───────────────────────────────────────────────────────────── */

.site-footer {
  margin-top: 4rem;
  padding-top: 2rem;
  border-top: 1px solid var(--divider);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.parent {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: 0.95rem;
  color: var(--neutral-500);
  text-decoration: none;
  align-self: flex-start;
}
.parent strong {
  font-weight: 500;
  color: var(--neutral-300);
  letter-spacing: 0.01em;
}
.parent:hover strong { color: var(--accent-300); }

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  font-size: 0.9rem;
}
.footer-nav a { color: var(--neutral-500); text-decoration: none; }
.footer-nav a:hover { color: var(--accent-300); }

.copyright {
  font-size: 0.82rem;
  color: var(--neutral-600);
  margin: 0;
}

/* Long email addresses must not push a phone sideways. */
.wrap a[href^="mailto:"] { word-break: break-word; }


/* ═══ The lesson demo ═══════════════════════════════════════════════════════
   A real lesson from the live library, rendered in the app's own tokens rather
   than screenshotted. Three reasons it is built this way:

   1. Screenshots go stale. The eight in `assets/` are from version code 5-9
      against a current 32, and one of them shows a verse card labelled NRSVue
      from before the BSB migration — a translation this project has no licence
      to display. A rendered deck cannot drift out of date in that direction.
   2. It stays legible. A 1344x2992 PNG shrunk into a page is unreadable text;
      this is real type at a real size, and it reflows on a phone.
   3. No JavaScript. The deck is a scroll-snap container, so it swipes with a
      finger and scrolls with a trackpad, and `script-src 'none'` holds.       */

/* A block, not a flex row, and that is the whole of the mobile width bug.
   ------------------------------------------------------------------------
   Each `.lesson` was a flex item, so it was sized shrink-to-fit by its own
   longest line -- and `.phone { width: 100% }` on a narrow screen resolved
   against *that*. Measured at 375px: 292px under one lesson, 200px under
   the next, 263px under the third, in a 327px stage. The frame changed size
   as you switched lessons.

   As blocks the lessons are all stage-width, so `width: 100%` means the
   same thing in each, and the phone centres on its own margins. */
.demo-stage {
  display: block;
  margin: 2rem 0 1rem;
}

.phone {
  width: 320px;
  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
  border: 9px solid #2b2e3d;
  border-radius: 36px;
  background: var(--bg);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(233, 233, 237, 0.06);
  overflow: hidden;
  position: relative;
}

/* The speaker pill. Purely decorative, and small enough not to eat a line. */
.phone::before {
  content: "";
  position: absolute;
  top: 9px; left: 50%;
  transform: translateX(-50%);
  width: 74px; height: 5px;
  border-radius: 3px;
  background: #3a3d4d;
  z-index: 3;
}

/* The chrome sits inside each card now rather than beside the deck, so it
   has to pin itself: the card is the scroll container, and a header in its
   normal flow would slide away with the prose. The negative side margins
   undo `.deck-card`s own padding so the segments still span the frame.

   `flex: none` because the card is a column flex box and would otherwise
   let a long card squeeze the header. */
.phone-top {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 22px 16px 12px;
  position: sticky;
  top: 0;
  z-index: 2;
  flex: none;
  margin: 0 -18px;
  background: var(--bg);
}
.phone-x { color: var(--neutral-600); font-size: 15px; line-height: 1; }
.segs { display: flex; gap: 4px; flex: 1; }
.seg { height: 3px; flex: 1; border-radius: 2px; background: var(--neutral-800); }
.seg.on { background: var(--accent); }
.phone-count { font-size: 11px; color: var(--neutral-600); font-variant-numeric: tabular-nums; }

/* The deck itself. */
/* One card at a time, switched by `:target`.
   -------------------------------------------------------------------------
   This was a horizontal scroll-snap deck until 2026-08-28, on the theory that
   anchor links would scroll it the way a swipe does. They do not, reliably:
   measured in the browser, clicking `href="#c2"` set the hash and scrolled the
   *page* by 438px while the deck stayed on card 1 at `scrollLeft: 0`. An anchor
   scrolls ancestors only as far as it takes to bring the target into view, and
   once the page had moved the browser considered the job done. The same card
   reached by `scrollIntoView` moved the deck correctly, so the deck was never
   the problem — the anchor was.

   `:target` does not depend on any of that. The targeted card is shown and the
   rest are not, so a button either works or is visibly broken, with no
   scroll-position guesswork in between.

   The cost is the swipe, which is a real loss on a page demonstrating a
   swipe-based app. Buttons were the requirement; swiping was the flourish. */

/* Fixed height, sized to the tallest card so none of them scrolls.
   -------------------------------------------------------------------------
   Two attempts. With an auto height the frame grew and shrank on every Next.
   Setting it to 470px stopped that but was still wrong: measured, the seven
   cards run from 352px to 531px of content, so c1 and c6 overflowed and grew an
   internal scrollbar — a bar appearing and vanishing reads as the frame moving
   even though the box is fixed.

   560px clears the tallest with room to spare, so nothing scrolls and nothing
   resizes. Short cards pad out, and because `.card-nav` has `margin-top: auto`
   the controls sit on the floor of the frame at every card — which is also what
   the real deck does, where Continue is pinned to the bottom with whatever
   space the card leaves above it.

   If a card is ever added with more prose than c6, this number is the thing to
   raise. The measurement is one line in the console:
     [...document.querySelectorAll('.deck-card')].map(c => c.scrollHeight)  */
.deck {
  display: block;
  position: relative;
  height: 560px;
}
.deck:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Every card occupies the same box, stacked rather than laid out in sequence.
   -------------------------------------------------------------------------
   This is what stops the page jumping. Clicking `#c2` makes the browser scroll
   the target into view, and it scrolls as far as it takes — so with the cards
   in normal flow, the seventh one sat far enough down the document that
   advancing threw the reader at the foot of the page.

   Absolutely positioned, all seven share one rectangle. The target is already
   where the previous card was, so there is nothing to scroll to and the page
   stays put. `overflow-anchor: none` stops the browser trying to preserve a
   scroll position against content that just changed underneath it. */
.deck-card {
  display: none;
  position: absolute;
  inset: 0;
  padding: 0 18px 20px;
  overflow-y: auto;
  overflow-anchor: none;
  box-sizing: border-box;
}

/* ── What `:target` is actually on ───────────────────────────────────────
   An empty `<span class="ca" id="g2">` before each card, never the card.

   Aaron, 2026-09-11: "when you select a lesson or click next it jumps down
   the page instead of leaving it in place." The first click moved the page
   404px and left the selector 39px above the top of the screen.

   `scroll-margin-top` cannot fix that, and the note it replaced here was
   wrong about why: fragment navigation scrolls the target into view with
   `block: start` **unconditionally**, in view already or not, so the margin
   only chooses where the jump lands. What fixes it is a target with no box.
   The browser has nothing to scroll to and leaves the page alone, while
   `:target` reads the URL rather than the layout and still matches.
   Measured before building it: a visible probe moved the page 466px, the
   same probe at `display: none` moved it 0 and still matched.

   `first-of-type` below, not `first-child`: the deck's first child is now
   one of these spans. */
.ca { display: none; }
.ca:target + .deck-card { display: flex; }

/* Nothing targeted yet — show the first card. `:has()` is what makes this a
   default rather than a permanent override: the moment any card is targeted,
   this stops applying and `:target` alone decides. */
.deck:not(:has(.ca:target)) .deck-card:first-of-type { display: flex; }

.c-kicker {
  font-size: 0.62rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.6rem;
}
.c-title {
  font-size: 1.22rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.28;
  margin: 0 0 0.7rem;
  color: var(--text);
  text-wrap: balance;
}
.c-body {
  font-size: 0.87rem;
  line-height: 1.62;
  color: var(--neutral-300);
  margin: 0 0 0.7rem;
}
.c-body.dim { color: var(--neutral-500); }

/* Scripture: the accent rail is the app's own treatment. */
.c-verse {
  border-left: 2px solid var(--accent);
  padding-left: 0.85rem;
  margin: 0.2rem 0 0.8rem;
}
.c-verse p { font-size: 0.93rem; line-height: 1.66; color: var(--text); margin: 0 0 0.5rem; }
.c-vn {
  font-size: 0.6rem;
  color: var(--accent);
  vertical-align: super;
  margin-right: 3px;
  font-variant-numeric: tabular-nums;
}
.c-ref { font-size: 0.72rem; color: var(--neutral-600); }

/* Word spotlight. */
.c-word {
  background: rgba(145, 132, 217, 0.07);
  border: 1px solid rgba(145, 132, 217, 0.3);
  border-radius: 10px;
  padding: 0.85rem 1rem;
  margin-bottom: 0.8rem;
  text-align: center;
}
.c-greek { font-size: 1.4rem; color: var(--text); line-height: 1.35; }
.c-translit { font-size: 0.78rem; color: var(--accent-300); font-style: italic; }
.c-gloss { font-size: 0.78rem; color: var(--neutral-500); margin-top: 0.3rem; }

/* Two-ages diagram, drawn with boxes rather than an image. */
.c-diagram { margin: 0.4rem 0 0.8rem; }
.c-drow { margin-bottom: 0.7rem; }
.c-dlabel {
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--neutral-600);
  margin-bottom: 0.3rem;
}
.c-bars { display: flex; gap: 3px; }
.c-bar {
  flex: 1;
  min-height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 0.6rem;
  line-height: 1.25;
  padding: 0.3rem;
  border-radius: 5px;
  border: 1px solid var(--neutral-800);
  color: var(--neutral-500);
}
.c-bar.now { border-color: var(--accent); background: rgba(145,132,217,0.16); color: var(--accent-300); }
.c-bar.age { border-color: rgba(145,132,217,0.42); color: var(--neutral-300); }

/* Check card options. */
.c-opts { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.7rem; }
.c-opt {
  font-size: 0.79rem;
  line-height: 1.45;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--neutral-800);
  border-radius: 9px;
  color: var(--neutral-500);
}
.c-opt.right {
  border-color: var(--accent);
  background: rgba(145, 132, 217, 0.13);
  color: var(--text);
}

/* Reflection input, shown as an empty field rather than a live one. */
.c-input {
  min-height: 76px;
  border: 1px solid var(--divider);
  border-radius: 9px;
  background: var(--surface);
  margin-bottom: 0.7rem;
}

.c-cta {
  display: block;
  text-align: center;
  font-size: 0.83rem;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 10px;
  padding: 0.6rem;
  margin-top: 0.2rem;
}

.deck-hint {
  text-align: center;
  font-size: 0.8rem;
  color: var(--neutral-600);
  margin: 0.25rem 0 0;
}

/* ── Marketing layout ─────────────────────────────────────────────────── */

.wrap.wide { max-width: 64rem; }

.split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 3rem;
  align-items: center;
  margin-bottom: 1rem;
}
@media (max-width: 52rem) {
  .split { grid-template-columns: 1fr; gap: 2rem; }
}

.section { margin: 4rem 0; }
.section-lead { max-width: 42rem; }

.quote {
  font-size: 1.22rem;
  line-height: 1.6;
  color: var(--neutral-300);
  border-left: 2px solid var(--accent);
  padding-left: 1.25rem;
  margin: 1.5rem 0;
}
.quote cite { display: block; font-size: 0.82rem; color: var(--neutral-600); font-style: normal; margin-top: 0.6rem; }

.cta-row { display: flex; flex-wrap: wrap; gap: 0.9rem; align-items: center; margin-top: 1.5rem; }

/* The plan selector on /buy/: one row of pills, the chosen one in the accent.
   A row rather than a column so the page is one card, not four. Named
   `plans`, not `seg`: `.seg` is the lesson demo's 3px progress segment, and
   the first cut of this collided with it and rendered 3px tall. */
.plans { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1.25rem 0 1.5rem; }
.plans button {
  font: inherit;
  font-size: 0.94rem;
  min-height: 44px;
  padding: 0 1rem;
  border-radius: 999px;
  border: 1px solid var(--neutral-800);
  background: transparent;
  color: var(--neutral-300);
  cursor: pointer;
}
.plans button:hover { background: rgba(233, 233, 237, 0.06); }
.plans button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.plans button[aria-selected="true"] {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(145, 132, 217, 0.12);
}
.plans-gap { margin-top: 1rem; }
/* The `hidden` attribute has to win over any display rule below, or a label
   the script hides stays on screen — which is exactly what happened to the
   seat count's label on the Gather tab. */
[hidden] { display: none !important; }
.seats { max-width: 7.5rem; min-height: 50px; padding: 0 0.9rem; font: inherit; color: var(--text); margin-bottom: 0; }
.seats-label { margin: 0; }
.btn-quiet { color: var(--neutral-300); border-color: var(--neutral-800); }
.btn-quiet:hover { background: rgba(233,233,237,0.06); }

.a-list { list-style: none; padding: 0; margin: 1rem 0; }
.a-list li {
  padding-left: 1.4rem;
  position: relative;
  margin-bottom: 0.7rem;
  color: var(--neutral-300);
}
.a-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 7px; height: 7px;
  border-radius: 50%;
  border: 1px solid var(--accent);
}
.a-list.no li::before { border-color: var(--neutral-600); background: transparent; }


/* ═══ Spacing utilities ═════════════════════════════════════════════════════
   These exist because of the Content-Security-Policy, not because of a
   preference for utility classes.

   `style-src 'self'` blocks **inline style attributes**, not only inline
   <style> blocks — and it always did. The privacy and delete-account pages
   carried `style="margin-top:0"` and `style="font-size:2rem"` from the day they
   were written, and every one of them was being dropped in production while
   rendering perfectly on a local static server, because a plain file server
   sends no CSP header. Nothing looked broken; the headings were simply the
   wrong size for anyone who visited the real site.

   Found 2026-08-28 by loading the pages with the production policy in a meta
   tag and reading the console: eight `Applying inline style violates...` errors
   on the home page alone.

   The fix is classes rather than `'unsafe-inline'`. Allowing inline styles to
   rescue nine declarations would have unpicked the directive that makes style
   injection hard, in exchange for margins.

   Declared last so they beat the element selectors they override — `h1` and
   `h2` both set margins above, and a class outranks an element anyway.        */

.flush      { margin: 0; }
.flush-top  { margin-top: 0; }
.flush-bot  { margin-bottom: 0; }
.gap-sm     { margin: 0 0 0.75rem; }
.gap-md     { margin: 0 0 1rem; }
.push-sm    { margin-top: 0.7rem; }

/* Sub-pages run a smaller h1 than the home page's 2.6rem. */
.page-title { font-size: 2rem; }

/* A kicker that labels rather than accents. Must follow `.kicker`, which sets
   the accent colour at the same specificity. */
.dim-label  { color: var(--neutral-600); }


/* ═══ Multi-page ════════════════════════════════════════════════════════════
   The site was one long scrolling page until 2026-08-28. It is now a small set
   of pages that link to each other, because that is how somebody evaluating an
   app actually reads: they pick the thing they want to know and go to it,
   rather than scrolling past four sections to reach the one that answers them.

   Two consequences run through everything below. The header no longer carries
   the mark — it is a plain text nav, and the mark appears once, large, on the
   landing page where it introduces the product. And every page that is not the
   landing page carries a Home control, because a page you can only leave with
   the back button is a page that feels like a dead end.                       */

/* ── Header, without the mark ─────────────────────────────────────────── */

.top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  flex-wrap: wrap;
  padding-bottom: 1.25rem;
  margin-bottom: 2.5rem;
  border-bottom: 1px solid var(--divider);
}

.home-link {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--neutral-300);
  text-decoration: none;
  padding: 0.4rem 0.85rem 0.4rem 0.7rem;
  margin-left: -0.7rem;
  border-radius: 9px;
}
.home-link:hover { color: var(--accent-300); background: rgba(145,132,217,0.10); }
.home-link .arr { font-size: 1.05em; line-height: 1; }

/* ── Landing hero ─────────────────────────────────────────────────────── */

.hero-lead {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  margin-bottom: 1.25rem;
}
.hero-mark { flex: none; }

.hero-title {
  font-size: clamp(2.6rem, 7vw, 4.4rem);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.02;
  margin: 0;
  text-wrap: balance;
}
.hero-title .sm {
  display: block;
  font-size: 0.42em;
  letter-spacing: -0.01em;
  color: var(--neutral-500);
  margin-top: 0.35rem;
}

@media (max-width: 34rem) {
  .hero-lead { gap: 1rem; }
  .hero-mark svg { width: 64px; height: 70px; }
}

/* ── The mockup ───────────────────────────────────────────────────────── */

.shot {
  display: block;
  width: 100%;
  max-width: 414px;
  height: auto;
  margin: 0 auto;
}
.shot-stage { display: flex; justify-content: center; }

/* ── Page cards, the way in to everything else ────────────────────────── */

.ways {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.9rem;
  margin: 2rem 0;
}
.way {
  display: block;
  background: var(--surface);
  border: 1px solid var(--neutral-800);
  border-radius: 14px;
  padding: 1.35rem;
  text-decoration: none;
}
.way:hover { border-color: rgba(145,132,217,0.45); background: rgba(145,132,217,0.06); }
.way:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.way h3 {
  margin: 0 0 0.35rem;
  font-size: 1.02rem;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.way h3 .go { color: var(--accent); font-weight: 400; }
.way p { margin: 0; font-size: 0.93rem; color: var(--neutral-500); }

/* ── Deck navigation, no JavaScript ───────────────────────────────────────
   The buttons live *inside* each card and point at the sibling ids. Clicking
   one is a plain anchor jump, which the browser resolves by scrolling the
   nearest scrollable ancestor — the deck — so the cards move and the page does
   not. That is why there is no script here and no `:target` rule: the
   behaviour is the anchor, not a stylesheet trick.

   `scroll-margin` keeps a jumped-to card aligned in the scroller instead of
   flush against its left edge.                                              */

.card-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 1rem;
}

.step {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.8rem;
  color: var(--accent);
  text-decoration: none;
  border: 1px solid var(--accent);
  border-radius: 9px;
  padding: 0.45rem 0.8rem;
  min-height: 38px;
  box-sizing: border-box;
}
.step:hover { background: rgba(145,132,217,0.14); }
.step:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The disabled ends. An anchor with nowhere to go is rendered as a span, so it
   is not focusable and not clickable — a greyed-out link that still takes a tab
   stop is worse than no control. */
.step-off {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.8rem;
  color: var(--neutral-800);
  border: 1px solid var(--neutral-800);
  border-radius: 9px;
  padding: 0.45rem 0.8rem;
  min-height: 38px;
  box-sizing: border-box;
}

.card-count {
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: var(--neutral-600);
  font-variant-numeric: tabular-nums;
}

/* A column, so `margin-top: auto` pins the nav to the bottom and every card's
   controls line up regardless of how much prose it carries.

   **`display` is deliberately not set here.** It was, and it silently undid the
   `:target` switching further up — same selector, same specificity, later in the
   file, so `display: flex` won and all seven cards rendered at once. Whether a
   card is shown is decided by `:target`; this rule only decides how it is laid
   out once it is. */
.deck-card { flex-direction: column; }


/* ── The progress bar tracks the card, and the card carries it ────────
   Twenty-eight lines of `:has(#c4:target)` lived here, lighting segments and
   setting the count with `content: "4/7"`. They named one deck of seven
   cards with ids `c1`–`c7`, and their own comment said to extend the block if
   a lesson of a different length was ever demoed.

   Three lessons arrived instead, generated with per-deck id prefixes, and
   every selector here stopped matching at once. It did not fail blank: the
   default arm still lit one segment and still said **1/7**, so card four of
   Jonah showed "1/7" an inch above its own nav reading "4 of 7".

   So the state is markup now — `scripts/build-lesson-demo.mjs` writes
   `<span class="seg on">` and the literal count from the same `i` and `n`
   that number the nav. `.seg.on`, up with the rest of the frame, is the whole
   of what CSS decides, and a fourth lesson of any length needs nothing here. */

/* ── The study link, as the app draws it ───────────────────────────────── */

.c-study {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.82rem;
  color: var(--accent);
  margin-top: 0.5rem;
}

/* ── Free / paid marker on the capability cards ───────────────────────── */

.tagline {
  display: inline-block;
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  margin-bottom: 0.6rem;
}
.t-free { color: var(--neutral-300); border: 1px solid var(--neutral-800); }
.t-paid { color: var(--accent); border: 1px solid rgba(145,132,217,0.45); background: rgba(145,132,217,0.08); }

/* ── Course kinds ─────────────────────────────────────────────────────── */

.kinds { display: grid; gap: 0.9rem; margin: 1.5rem 0 2rem; }
.kind {
  background: var(--surface);
  border: 1px solid var(--neutral-800);
  border-radius: 14px;
  padding: 1.25rem 1.4rem;
}
.kind h3 { margin: 0 0 0.15rem; font-size: 1rem; }
.kind .eg { font-size: 0.82rem; color: var(--neutral-600); margin: 0 0 0.55rem; }
.kind p { margin: 0; font-size: 0.94rem; color: var(--neutral-500); }

/* ── The leader-note spotlight ────────────────────────────────────────── */

.ln {
  border: 1px solid rgba(145,132,217,0.32);
  background: rgba(145, 132, 217, 0.05);
  border-radius: 14px;
  padding: 1.5rem;
  margin: 1.5rem 0;
}
.ln-field {
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 1.4rem 0 0.4rem;
}
.ln-field:first-of-type { margin-top: 0; }
.ln p { font-size: 0.95rem; color: var(--neutral-300); margin: 0 0 0.5rem; }
.ln .q { color: var(--text); }
.ln .w { color: var(--neutral-500); font-size: 0.9rem; padding-left: 0.9rem; border-left: 1px solid var(--neutral-800); }

/* ── /set-password/ ───────────────────────────────────────────────────────
   The only form on this site. These live here rather than inline because
   script-src's sibling, style-src 'self', blocks a style attribute exactly as
   it blocks a script tag — the inputs rendered full-bleed and the console said
   so, six times. */
.pw-field {
  width: 100%;
  max-width: 22rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--neutral-600);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 1rem;
}
.pw-field:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ── /lesson/: three lessons, one phone, and no script ────────────────────
   Aaron, 2026-09-11: a lesson selector above a bigger phone, loading each
   lesson into it.

   There is no click handler because there is no script on this page. Each
   button links to the first card of its lesson, and the wrapper showing that
   lesson is the one containing the `:target`. Choosing a lesson and landing on
   its first card are therefore the same action, and the back button moves
   between lessons for free.

   This is the same mechanism the deck already used for cards, extended one
   level out. Card ids are prefixed per lesson (g1, j1, e1) so a target can
   only ever match one deck. */

.picks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.7rem;
  margin: 1.6rem 0 0.4rem;
}

.pick {
  display: block;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--neutral-800);
  border-radius: 12px;
  background: transparent;
  text-decoration: none;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.pick:hover { border-color: var(--neutral-600); background: rgba(233, 233, 237, 0.03); }
.pick:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pick-title {
  display: block;
  color: var(--text);
  font-size: 0.95rem;
  line-height: 1.3;
  margin-bottom: 0.25rem;
}
.pick-why { display: block; color: var(--neutral-600); font-size: 0.78rem; }

/* The selected one. `:has()` is already load-bearing on this page for the
   deck's own default, so this adds no new assumption. It hangs off <main>
   rather than a sibling combinator: .picks comes *before* .demo-stage in the
   document, so '~' can never reach back to it. */
main:has(.l-g .ca:target) .pick-g,
main:has(.l-j .ca:target) .pick-j,
main:has(.l-e .ca:target) .pick-e {
  border-color: var(--accent);
  background: rgba(145, 132, 217, 0.07);
}
main:has(.l-g .ca:target) .pick-g .pick-title,
main:has(.l-j .ca:target) .pick-j .pick-title,
main:has(.l-e .ca:target) .pick-e .pick-title { color: var(--accent); }

/* Nothing targeted yet: the first lesson is the one showing, and its button
   is the one lit. The moment any card is targeted this stops applying. */
main:not(:has(.ca:target)) .pick-g {
  border-color: var(--accent);
  background: rgba(145, 132, 217, 0.07);
}
main:not(:has(.ca:target)) .pick-g .pick-title { color: var(--accent); }

.lesson { display: none; }
.lesson:has(.ca:target) { display: block; }
.demo-stage:not(:has(.ca:target)) .lesson:first-child { display: block; }

.lesson-meta {
  text-align: center;
  color: var(--neutral-600);
  font-size: 0.8rem;
  margin: 0 0 0.9rem;
}

/* ── The phone, bigger ────────────────────────────────────────────────────
   320x560 until 2026-09-11. Aaron asked for bigger and it also buys back
   scrolling: the note on `.deck-card` records that the content is taller than
   its box, so the extra 100px of height is read rather than swiped. */
.phone { width: 380px; }
.deck { height: 660px; }

@media (max-width: 26rem) {
  .phone { width: 100%; }
  .deck { height: 78vh; }
}

/* ── The contrast diagram ─────────────────────────────────────────────────
   The app draws this with react-native-svg. Two arrows pointing opposite ways
   is a border and a triangle here, which needs no image and so nothing from
   `img-src`. */
.c-contrast { margin: 0.4rem 0 1rem; }
.c-dlabel {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--neutral-600);
  margin: 0.9rem 0 0.35rem;
}
.c-dlabel.accent { color: var(--accent); }
.c-arrow { display: flex; align-items: center; height: 14px; }
.c-arrow-line { flex: 1; height: 2px; background: var(--neutral-800); }
.c-arrow-line.accent { background: var(--accent); }
.c-arrow-head {
  width: 0; height: 0;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
}
.c-arrow-head.left { border-right: 12px solid var(--neutral-600); order: -1; }
.c-arrow-head.right { border-left: 12px solid var(--accent); }
.c-dnote { font-size: 0.78rem; color: var(--neutral-500); margin: 0.35rem 0 0; }
.c-dnote.accent { color: var(--accent-300, var(--accent)); }
