/* The landing page (PLAN.md Stage 15). It loads after `pages.css` and the
   theme tokens, and only the landing page loads it.

   One screen holds the text, on the left, and it stays in place. On the
   right, a narrow, tall deck of cards moves with the scroll. The pins of the
   deck hang in the right margin, so the layout keeps a margin of `--pinw` on
   both sides. A window too narrow for that, or a page with no script, gets
   the text and then the deck, in the normal flow, and no pins. */

:root {
  --pinw: 13rem; --wide: 72rem;
  /* The dark parts of the deck and the pins. On a dark page they are a step
     lighter, and their edges stronger, so they stand apart from the ground. */
  --deck-bg: #15130f; --deck-bar: #201d18; --deck-edge: rgb(255 255 255 / 0.1);
  --tag-bg: #1b1814; --tag-edge: rgb(255 255 255 / 0.12); --gutter-ink: rgb(255 255 255 / 0.32);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --deck-bg: #1d1a16; --deck-bar: #2a2621; --deck-edge: rgb(255 255 255 / 0.2);
    --tag-bg: #2d2924; --tag-edge: rgb(255 255 255 / 0.24); --gutter-ink: rgb(255 255 255 / 0.45);
  }
}
:root[data-theme="dark"] {
  --deck-bg: #1d1a16; --deck-bar: #2a2621; --deck-edge: rgb(255 255 255 / 0.2);
  --tag-bg: #2d2924; --tag-edge: rgb(255 255 255 / 0.24); --gutter-ink: rgb(255 255 255 / 0.45);
}
main.landing { max-width: none; padding: 0; }
.nobr { white-space: nowrap; }

.land { --aw: 31rem; display: grid; gap: 2.5rem; width: 100%; max-width: 68rem; margin: 0 auto; padding: 1.5rem 1.5rem 0; }
.art { width: 100%; max-width: var(--aw); justify-self: center; }
.steps { display: none; }
/* One column: the parts of the left column take their places around the
   deck, so the deck comes after the chapters and before the end. */
.left { display: contents; }
.hero { order: 1; } .zone { order: 2; } .art { order: 3; } .closing { order: 4; } .legal { order: 5; }
/* The landing page writes its own foot, in the left column. */
body > .foot { display: none; }
@media (min-width: 80rem) {
  .wide .top { max-width: calc(min(100vw - 2 * var(--pinw), var(--wide)) + 3rem); }
  .land {
    --aw: clamp(26rem, 27.5vw, 31rem); --pad-top: clamp(1.5rem, 5svh, 3.5rem);
    /* The deck fits the first screen whole: the window, less the header,
       the space above the deck and a margin below it. */
    --deck-h: calc(100svh - 4.6rem - var(--pad-top) - 1.5rem);
    max-width: calc(min(100vw - 2 * var(--pinw), var(--wide)) + 3rem);
    grid-template-columns: minmax(0, 1fr) var(--aw); column-gap: clamp(3rem, 4vw, 5rem);
    align-items: start; padding-top: var(--pad-top);
  }
  .left { display: block; }
  /* The deck runs the whole height of the page, and stays in place. */
  .art { max-width: none; align-self: stretch; }
  /* The story: the chapters stay in place while the markers beside them
     scroll by, and the markers give the scroll its length. */
  .live .zone { position: relative; height: calc(7 * 62svh + 40svh); margin-top: clamp(1.4rem, 4svh, 2.4rem); }
  .live .chapters { position: sticky; top: 1.5rem; margin-top: 0; }
  .live .steps { display: block; position: absolute; inset: 0; pointer-events: none; }
  /* A link to a marker lands a little past the focus line, inside its
     step, so the deck has switched to its card. */
  .live .stop { height: 62svh; scroll-margin-top: 24svh; }
}

/* The text. */
.landing h1 {
  font-family: var(--serif); font-weight: 400; font-size: calc(0.85 * clamp(2.6rem, min(1.4rem + 2.2vw, 7.5svh), 4rem));
  line-height: 1.05; letter-spacing: -0.015em; margin: 0 0 1rem; text-wrap: balance;
}
.landing .lead { font-size: calc(0.85 * clamp(1.15rem, 0.95rem + 0.35vw, 1.4rem)); line-height: 1.5; color: var(--fg-muted); margin: 0 0 1.4rem; max-width: 32em; text-wrap: pretty; }
.ctas { display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: center; }
.chapters {
  list-style: none; margin: clamp(1.4rem, 4svh, 2.4rem) 0 0; padding: clamp(1.2rem, 3svh, 1.8rem) 0 0;
  display: grid; gap: clamp(0.9rem, 2.4svh, 1.5rem); border-top: 1px solid var(--border);
}
.ch { display: grid; grid-template-columns: 1.6rem minmax(0, 1fr); column-gap: 0.85rem; align-items: start; }
.ch-icon {
  width: 1.4rem; height: 1.4rem; margin-top: 0.2rem; fill: none; stroke: var(--fg);
  stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
}
/* A whole chapter is a link to its place in the story: the link of its
   title stretches over it. The link inside its text stays on top. */
.ch { position: relative; }
.ch-head { color: inherit; text-decoration: none; }
@media (min-width: 80rem) {
  .live .ch-head::after { content: ""; position: absolute; inset: -0.4rem -0.6rem; border-radius: 0.5rem; }
  .live .ch { cursor: pointer; }
  .live .ch:hover h2 { text-decoration: underline; text-underline-offset: 0.18em; text-decoration-thickness: 1px; }
  .ch .more { position: relative; z-index: 1; }
}
.ch h2 { font-family: var(--serif); font-weight: 400; font-size: 1.35rem; line-height: 1.2; margin: 0 0 0.3rem; }
.ch p { margin: 0; color: var(--fg-muted); font-size: 0.98rem; line-height: 1.5; max-width: 36em; text-wrap: pretty; }
.ch .more { color: var(--fg); font-weight: 600; white-space: nowrap; }
/* The chapter of the card on top is in full ink, and the others are faint. */
@media (min-width: 80rem) {
  .live .ch { opacity: calc(0.3 + 0.7 * var(--a)); }
  .live .ch-learn { --a: clamp(0, 3 - var(--s), 1); }
  .live .ch-write { --a: clamp(0, min(var(--s) - 2, 5 - var(--s)), 1); }
  .live .ch-share { --a: clamp(0, min(var(--s) - 4, 6 - var(--s)), 1); }
  .live .ch-more { --a: clamp(0, var(--s) - 5, 1); }
}

/* The end of the left column: the last call, then the links of the foot. */
.closing { padding-block: 4rem; }
/* Beside the deck, the last call fills the window above the foot. It
   follows the chapters with no gap, and pushes them out. */
@media (min-width: 80rem) {
  .closing {
    box-sizing: border-box; min-height: calc(100svh - 5rem); padding-block: 0;
    display: flex; flex-direction: column; justify-content: center;
  }
}
.closing h2 { font-family: var(--serif); font-weight: 400; font-size: clamp(2rem, 1.4rem + 1.4vw, 3rem); line-height: 1.1; margin: 0 0 0.8rem; }
.closing p { margin: 0 0 1.6rem; color: var(--fg-muted); font-size: 1.15rem; max-width: 30em; }
.legal {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; padding: 1.5rem 0 2rem;
  border-top: 1px solid var(--border); color: var(--fg-muted); font-size: 0.9rem;
}
.legal a { color: inherit; text-decoration: none; }
.legal a:hover { color: var(--fg); }

/* The scroll hint: a mouse at the foot of the first screen. It fades as soon
   as the page moves. */
.hint { display: none; }
@media (min-width: 80rem) and (prefers-reduced-motion: no-preference) {
  .live .hint {
    display: block; position: fixed; left: 50%; bottom: 1.6rem; z-index: 4; pointer-events: none;
    transform: translateX(-50%); opacity: clamp(0, 1 - var(--sy, 0) * 6, 1);
  }
  .mouse { display: block; width: 1.4rem; height: 2.2rem; border: 1.5px solid var(--fg-muted); border-radius: 0.7rem; position: relative; }
  .mouse::before {
    content: ""; position: absolute; left: 50%; top: 0.4rem; width: 3px; height: 0.45rem; margin-left: -1.5px;
    border-radius: 2px; background: var(--fg-muted); animation: wheel 1.6s ease-in-out infinite;
  }
  @keyframes wheel { 0% { transform: translateY(0); opacity: 1; } 70% { transform: translateY(0.6rem); opacity: 0; } 100% { transform: translateY(0); opacity: 0; } }
}

/* The artwork: three panels, then the app. Its type scales with its width. */
.stage { font-size: calc(min(var(--aw), 100vw - 3rem) / 24); }
.deck { display: grid; gap: 1.2em; }
/* With no story, the screen shows the top of its content. */
.view { height: 30em; }
.panel {
  --tb: var(--deck-bg); --tbar: var(--deck-bar); --tf: #ece6da; --td: #8f877a; --tok: #9fd18b; --terr: #f08a7a;
  background: var(--tb); color: var(--tf); border: 1px solid var(--deck-edge); border-radius: 0.6em;
  overflow: hidden; font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
}
.strip {
  color: inherit; text-decoration: none;
  display: flex; align-items: center; gap: 0.6em; height: calc(2.5em / 0.85); padding: 0 0.9em; background: var(--tbar);
  border-bottom: 1px solid rgb(255 255 255 / 0.08); font-family: var(--sans); font-size: 0.85em; font-weight: 600; letter-spacing: 0.02em;
}
.strip .no { display: grid; place-items: center; width: 1.5em; height: 1.5em; border-radius: 50%; background: var(--tok); color: var(--tb); font-size: 0.8em; }
.strip .where { margin-left: auto; font-family: ui-monospace, Menlo, Consolas, monospace; font-weight: 400; font-size: 0.85em; color: var(--td); }
.body { padding: 0.9em 1em 1em; }
.lines { display: grid; gap: 0.15em; }
.tree { margin: 0 0 0.8em; font: inherit; font-size: 0.78em; line-height: 1.55; white-space: pre; }
.file { border-top: 1px solid rgb(255 255 255 / 0.1); padding-top: 0.6em; }
.fname { display: inline-block; font-size: 0.72em; color: var(--td); margin-bottom: 0.4em; }
.file .lines { gap: 0; }
/* A line of a file: its number, then its text. A long line wraps under its
   own text, and the number is not repeated. */
.row { display: grid; grid-template-columns: 2.6em minmax(0, 1fr); font-size: 0.78em; line-height: 1.55; }
.row .ln { width: auto; margin: 0; padding-right: 0.8em; }
.row .tx { white-space: pre-wrap; overflow-wrap: anywhere; }
.ln { display: inline-block; width: 2em; margin-right: 0.6em; text-align: right; color: var(--gutter-ink); user-select: none; }
.lines pre { margin: 0; font: inherit; font-size: 0.78em; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
.panel .d { color: var(--td); }
.panel .ok { color: var(--tok); }
.k2 .lines pre + pre, .k2 .lines pre + .diff, .k2 .diff + pre { margin-top: 0.4em; }
.diff .row { color: var(--td); }
.diff .row.add { color: var(--tok); }
.panel .err { color: var(--terr); }
.panel .code { color: var(--tf); background: rgb(255 255 255 / 0.08); border-radius: 0.2em; padding: 0 0.2em; }
.appbar .bar-ring { width: 1.1em; height: 1.1em; }
/* The repository line of the Write card. */
.repo-head { display: flex; align-items: center; gap: 0.5em; margin: 0 0 0.8em; padding-bottom: 0.7em; border-bottom: 1px solid rgb(255 255 255 / 0.1); font-family: var(--sans); font-size: 0.85em; }
.repo-head svg { width: 1.2em; height: 1.2em; fill: none; stroke: var(--tok); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.repo-head span { margin-left: auto; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 0.9em; color: var(--td); border: 1px solid rgb(255 255 255 / 0.2); border-radius: 1em; padding: 0.05em 0.6em; }
.facts { font-family: var(--sans); gap: 0.2em; }
.fact { display: grid; grid-template-columns: 1.6em minmax(0, 1fr); column-gap: 0.7em; padding: 0.75em 0; border-bottom: 1px solid rgb(255 255 255 / 0.1); }
.fact svg { width: 1.3em; height: 1.3em; fill: none; stroke: var(--tok); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; margin-top: 0.1em; }
.fact p { margin: 0; }
.fact b { display: block; font-size: 0.9em; }
.fact span { display: block; font-size: 0.8em; color: var(--td); line-height: 1.45; }
.k4 .repo { margin: 0; display: grid; font-size: 0.82em; padding: 0.45em 0; border-bottom: 1px solid rgb(255 255 255 / 0.1); }
.k4 .repo span { color: var(--td); font-size: 0.9em; }
.k4 .lines { font-family: var(--sans); gap: 0.35em; }
.k4 .label { margin: 0.4em 0 0; font-size: 0.72em; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--td); }
.k4 .field { margin: 0; padding: 0.5em 0.7em; border: 1px solid rgb(255 255 255 / 0.25); border-radius: 0.3em; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 0.8em; }
.k4 .typed { display: inline-block; white-space: nowrap; }
.k4 .added, .k4 .share { margin: 0; font-size: 0.85em; line-height: 1.5; color: var(--tf); }

/* The screen: the app's frame, drawn small and simplified. */
.app {
  background: var(--bg); border: 1px solid var(--border); border-radius: 0.8em;
  overflow: hidden; color: var(--fg);
}
.appbar {
  display: flex; align-items: center; gap: 0.9em; padding: 0 0.9em; height: 2.6em;
  border-bottom: 1px solid var(--rule); font-size: 1em; color: var(--fg-muted);
}
.appbar svg.i {
  width: 0.95em; height: 0.95em; display: block; fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.appbar .sp { margin-left: auto; }
.appbar .sep { width: 1px; height: 1.1em; background: var(--rule); }
.appbar .domain { display: inline-flex; align-items: center; gap: 0.35em; color: var(--fg); font-weight: 600; font-size: 0.8em; }
.appbar .domain small { font-weight: 400; color: var(--fg-muted); font-size: 0.9em; }
.ring { width: 1.05em; height: 1.05em; border-radius: 50%; border: 2px solid var(--border); }
.view { overflow: hidden; }
.track { will-change: transform; }
.part { padding: 0 1.4em 1.6em 2.3em; }

/* The item head, as the app sets it. */
.head { display: flex; align-items: center; gap: 0.6em; padding: 0.8em 0 0.7em; border-bottom: 1px solid var(--rule); margin-bottom: 1em; }
.head .t { font-family: var(--serif); line-height: 1.25; }
.head .t small { display: block; font-size: 0.72em; color: var(--fg-muted); }
.head .t b { display: block; font-size: 0.92em; }
.head .t span { display: block; font-family: var(--sans); font-size: 0.7em; color: var(--fg-muted); }
.head .act { margin-left: auto; font-size: 0.7em; border: 1px solid var(--rule); border-radius: 0.25em; padding: 0.2em 0.5em; }
.head .eye { margin-left: auto; width: 1em; height: 1em; fill: none; stroke: var(--fg); stroke-width: 1.6; }
.prog { width: 1.9em; height: 1.9em; flex: none; }
.prog circle { fill: none; stroke-width: 4; }
.prog .bg { stroke: var(--border); }
.prog .fg { stroke: var(--fg); }

/* The cards of a deck: numbered prose, with no boxes. */
.para { position: relative; font-family: var(--serif); font-size: 0.9em; line-height: 1.6; margin: 0 0 0.75em; }
.para::before { content: attr(data-n); position: absolute; left: -1.95em; top: 0.25em; font-family: var(--sans); font-size: 0.68em; color: var(--fg-muted); }
.para p { margin: 0; }
.para .sc { font-variant: small-caps; letter-spacing: 0.02em; }
.landing math { font-family: "NewCM Math", math; }
.para math[display="block"] { margin: 0.2em 0; }
.para .plot { width: 10.5em; display: block; margin: 0.3em auto 0; }
.plot .g { stroke: var(--border); }
.plot .ax { stroke: var(--fg); stroke-width: 1.2; }
.plot .t { font: 10px var(--sans); fill: var(--fg-muted); text-anchor: middle; }
.plot .lab { font: italic 11px var(--serif); fill: var(--fg-muted); }
.plot .curve { stroke: var(--graph-blue); stroke-width: 2.4; }
.plot .pt { fill: var(--graph-blue); }

/* The flashcard wall. */
.kind { font-family: var(--sans); font-size: 0.62em; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--fg-muted); }
.part > .kind + p { margin: 0.1em 0 0.7em; font-size: 0.7em; color: var(--fg-muted); }
.wall { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6em; }
.fcard {
  position: relative; height: 6.2em; background: var(--surface); border: 1px solid var(--rule); border-radius: 0.3em;
  padding: 0.7em 0.8em; font-family: var(--serif); font-size: 0.85em; line-height: 1.5; overflow: hidden;
}
.fcard p { margin: 0; }
.fcard.done > p { visibility: hidden; }
.fcard.done { background-image: repeating-linear-gradient(135deg, var(--border) 0 1px, transparent 1px 7px); }
.fcard.done::after {
  content: ""; position: absolute; inset: 0; margin: auto; width: 1.6em; height: 1.6em; border-radius: 50%;
  background: var(--grade-perfect); box-shadow: 0 0 0 0.35em var(--surface);
}
.fcard .tick {
  position: absolute; inset: 0; margin: auto; width: 1em; height: 1em; z-index: 1;
  fill: none; stroke: var(--bg); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
}

/* An exam: numbered questions, each answer under its rule. */
.q { margin-bottom: 0.55em; }
.ans { border-top: 1px solid var(--rule); padding-top: 0.45em; margin: 0 0 0.9em; font-family: var(--serif); font-size: 0.9em; line-height: 1.55; }
.ans .kind { display: block; font-weight: 400; margin-bottom: 0.1em; font-size: 0.68em; }
.ans p { margin: 0; }

/* The flashcard that turns over. The turn is flat: the card narrows to a
   line and opens on its back, so it never grows or leans. Then the grade
   covers it. */
.fcard.flip { padding: 0; background: none; border: none; overflow: visible; }
.flip .turn { position: relative; height: 100%; }
.flip .face {
  position: absolute; inset: 0; padding: 0.7em 0.8em;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 0.3em; display: flex; flex-direction: column;
}
.flip .back { visibility: hidden; }
.flip .grades { display: flex; gap: 0.3em; margin-top: auto; font-family: var(--sans); font-size: 0.7em; }
.flip .grades span { flex: 1; text-align: center; border: 1px solid var(--rule); border-radius: 0.3em; padding: 0.2em 0; }
.flip .grades .pick { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.flip .graded {
  position: absolute; inset: 0; display: grid; place-items: center; opacity: 0; border-radius: 0.3em;
  border: 1px solid var(--rule); background: var(--surface) repeating-linear-gradient(135deg, var(--border) 0 1px, transparent 1px 7px);
}
.flip .graded::before { content: ""; grid-area: 1 / 1; width: 1.6em; height: 1.6em; border-radius: 50%; background: var(--grade-perfect); box-shadow: 0 0 0 0.35em var(--surface); }
.flip .graded .tick { position: static; grid-area: 1 / 1; margin: 0; }
.knob { fill: var(--graph-blue); stroke: var(--bg); stroke-width: 2; }
.tilt { transform-box: view-box; transform-origin: 34px 222px; }

/* A pin: a dot on the artwork, a leg at 60 degrees, and a run to a dark note
   in the right margin. The corner between the leg and the run is 120 degrees.
   The island places the dot on its target (`--x`, `--y`) on each frame. */
.pin { display: none; }
@media (min-width: 80rem) {
  .live .pin {
    --r: 1.4em; --d: -1; --gapx: 1.2rem;
    display: block; position: absolute; inset: 0; pointer-events: none; opacity: 0; z-index: 3;
  }
  .live .pin i {
    position: absolute; left: var(--x); top: var(--y); width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px;
    border-radius: 50%; background: #f3ede2; box-shadow: 0 0 0 2px #1b1814;
  }
  /* A grey that reads on the dark panels and on the page. */
  .live .pin .leg, .live .pin .run { position: absolute; height: 1px; background: #8a8378; }
  .live .pin .leg {
    left: var(--x); top: var(--y); width: calc(var(--r) * 1.1547);
    transform-origin: 0 50%; transform: rotate(calc(var(--d) * 60deg));
  }
  .live .pin .run {
    left: calc(var(--x) + var(--r) * 0.5774); top: calc(var(--y) + var(--d) * var(--r));
    right: calc(-1 * var(--gapx));
  }
  .live .pin .tag {
    position: absolute; left: calc(100% + var(--gapx)); top: calc(var(--y) + var(--d) * var(--r));
    width: calc(var(--pinw) - var(--gapx) - 1rem); transform: translateY(-50%);
    padding: 0.55rem 0.8rem 0.6rem; background: var(--tag-bg); color: #f3ede2;
    font-size: 0.88rem; line-height: 1.4; border: 1px solid var(--tag-edge);
    clip-path: polygon(0 0, calc(100% - 0.75rem) 0, 100% 0.75rem, 100% 100%, 0 100%);
  }
}

/* The story. The island writes two numbers on `.story`. `--t` is the place
   of the scroll in the markers: 0 to 3 in the course, its flashcards and its
   exam, 3 to 4 in "Write", 4 to 5 in "Check", 5 to 6 in "Share", then 6 to 7
   in "And beyond". `--s` is the same place, held and switched: it stays on a
   step's number for most of the step, then runs to the next one. The cards
   and the chapters switch on `--s`; what moves inside a card follows `--t`.

   The deck does not change its size. Each card keeps its own size: it slides
   up from the foot (`--e`) and stops below the header of the card before it,
   so the headers stack at the top. A header links to its marker, and a link
   jumps there at once, with no animation. */
@media (min-width: 80rem) {
  .live .stage {
    --strip: 2.5em; --stage-h: var(--deck-h);
    position: sticky; top: 1.5rem; height: var(--stage-h); display: block;
  }
  /* The deck hides what is outside it: the cards that wait below it. Its
     shadow is drawn outside its edge, so nothing cuts it, and the pins are
     outside the deck, so they hang free in the margin. */
  .live .deck {
    position: absolute; inset: 0; overflow: hidden; border-radius: 0.8em;
    border: 1px solid var(--border);
    box-shadow: 0 0.15em 0.4em rgb(0 0 0 / 0.06), 0 0.6em 1.6em rgb(0 0 0 / 0.1);
  }
  .live .panel, .live .app {
    --m: calc(var(--e) * var(--e) * (3 - 2 * var(--e)));
    position: absolute; left: 0; right: 0; top: calc(var(--i) * var(--strip));
    height: calc(var(--stage-h) - var(--i) * var(--strip));
    transform: translateY(calc((1 - var(--m)) * (var(--stage-h) + 0.5em - var(--i) * var(--strip))));
    border-top-color: rgb(255 255 255 / 0.22);
  }
  /* One shadow, the deck's: the cards cast none. */
  /* The deck draws the outer edge: a border of the app's own would sit on
     the deck's clip, and lose its top. */
  .live .app { box-shadow: none; border: none; border-radius: 0; }
  /* A card that stacks over another has square top corners: a round corner
     would show the card under it. Only the top of the deck is round. */
  .live .panel { border-top-left-radius: 0; border-top-right-radius: 0; display: flex; flex-direction: column; }
  /* The body of a card takes the rest of its height, and hides what scrolls
     past its top, under the header. */
  .live .panel .body { flex: 1; min-height: 0; overflow: hidden; }
  @keyframes rise { from { transform: translateY(2.5em); opacity: 0; } }

  /* The app: the first card, with the hero. The scroll moves its content
     through the course, the flashcards and an exam. */
  .live .app {
    --i: 0; --e: 1; --k: clamp(0, var(--t) / 2.7, 1);
    --view-h: calc(var(--stage-h) - var(--strip));
    animation: rise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .live .appbar { height: var(--strip); }
  .live .view { height: var(--view-h); }
  .live .track { transform: translateY(calc(var(--k) * (var(--view-h) - 100%))); }
  .live .tilt { transform: rotate(calc((clamp(0, (var(--t) - 0.1) / 0.8, 1) - 0.5) * 34deg)); }
  .live .flip { --p: clamp(0, (var(--t) - 1.15) / 0.4, 1); }
  .live .flip .face { transform: scaleX(clamp(0, 1 - 2 * var(--p), 1)); }
  .live .flip .back { visibility: visible; transform: scaleX(clamp(0, 2 * var(--p) - 1, 1)); }
  .live .flip .graded { opacity: clamp(0, (var(--t) - 1.65) / 0.1, 1); }
  .live .ans { opacity: clamp(0, (var(--t) - 2.15) / 0.2, 1); }
  .live .eye { stroke: color-mix(in oklab, var(--fg-muted), var(--fg) calc(clamp(0, (var(--t) - 2.05) / 0.1, 1) * 100%)); }

  /* Write, Check, Share, then And beyond. Their lines come in as the scroll
     reaches them, and a card whose content is taller than it scrolls that
     content as its lines come in. A card keeps its size. */
  .live .k1 { --i: 1; --n: 18; --e: clamp(0, var(--s) - 2, 1); --f: clamp(0, (var(--t) - 3) / 0.65, 1); }
  .live .k2 { --i: 2; --n: 6; --e: clamp(0, var(--s) - 3, 1); --f: clamp(0, (var(--t) - 4) / 0.6, 1); }
  .live .k4 { --i: 3; --n: 6; --e: clamp(0, var(--s) - 4, 1); --f: clamp(0, (var(--t) - 5) / 0.6, 1); }
  .live .k5 { --i: 4; --n: 4; --e: clamp(0, var(--s) - 5, 1); --f: clamp(0, (var(--t) - 6) / 0.5, 1); }
  .live .panel .scroll {
    --body-h: calc(var(--stage-h) - (var(--i) + 1) * var(--strip) - 1.9em);
    /* The content holds still while its first lines come in, then scrolls
       so the last lines come into view. */
    --u: clamp(0, (var(--f) - 0.45) / 0.55, 1);
    transform: translateY(min(0px, calc(var(--u) * (var(--body-h) - 100%))));
  }
  .live .lines > * {
    --in: clamp(0, (var(--f) * var(--n) - var(--l)) * 2, 1);
    opacity: var(--in); transform: translateY(calc((1 - var(--in)) * 0.4em));
  }
  .live .lines > :nth-child(1) { --l: 0; } .live .lines > :nth-child(2) { --l: 1; } 
  .live .lines > :nth-child(3) { --l: 2; } .live .lines > :nth-child(4) { --l: 3; } 
  .live .lines > :nth-child(5) { --l: 4; } .live .lines > :nth-child(6) { --l: 5; } 
  .live .lines > :nth-child(7) { --l: 6; } .live .lines > :nth-child(8) { --l: 7; } 
  .live .lines > :nth-child(9) { --l: 8; } .live .lines > :nth-child(10) { --l: 9; } 
  .live .lines > :nth-child(11) { --l: 10; } .live .lines > :nth-child(12) { --l: 11; } 
  .live .lines > :nth-child(13) { --l: 12; } .live .lines > :nth-child(14) { --l: 13; } 
  .live .lines > :nth-child(15) { --l: 14; } .live .lines > :nth-child(16) { --l: 15; } 
  .live .lines > :nth-child(17) { --l: 16; } .live .lines > :nth-child(18) { --l: 17; } 
  
  .live .k4 .typed { clip-path: inset(0 calc((1 - clamp(0, (var(--f) * var(--n) - 1) / 1.5, 1)) * 100%) 0 0); }

  /* A pin shows in its window of `--t`, and only while its target is in view.
     The pins of a card come one after another. */
  .live .pin { opacity: min(var(--seen, 1), clamp(0, min((var(--t) - var(--from)) * 8, (var(--to) - var(--t)) * 8), 1)); }
  .pin-ring { --from: -1; --to: 0.45; --d: 1; }
  .pin-eq { --from: -1; --to: 0.45; }
  .pin-knob { --from: 0.35; --to: 0.95; --d: 1; }
  .pin-again { --from: 1.05; --to: 1.75; --d: 1; }
  .pin-due { --from: 1.3; --to: 1.75; }
  .pin-flip { --from: 1.1; --to: 1.75; }
  .pin-eye { --from: 2.05; --to: 2.75; --d: 1; }
  .pin-working { --from: 2.25; --to: 2.75; --d: 1; }
  .pin-git { --from: 3; --to: 3.4; --d: 1; }
  .pin-tree { --from: 3.35; --to: 3.75; }
  .pin-title { --from: 3.15; --to: 3.75; --d: 1; }
  .pin-card { --from: 3.3; --to: 3.75; }
  .pin-flashcard { --from: 3.45; --to: 3.75; --d: 1; }
  .pin-fault { --from: 4.05; --to: 4.75; }
  .pin-fix { --from: 4.3; --to: 4.75; --d: 1; }
  .pin-valid { --from: 4.45; --to: 4.75; --d: 1; }
  .pin-address { --from: 5.05; --to: 5.75; }
  .pin-added { --from: 5.2; --to: 5.75; --d: 1; }
  .pin-yours { --from: 5.45; --to: 5.75; --d: 1; }
  .pin-checker { --from: 6.1; --to: 9; --d: 1; }
}
