/* The site's front door, web-link/index.html.
 *
 * It loads assets/site.css first, which is where everything the whole site
 * already has lives — the tokens, the glass card, the buttons, the steps,
 * the `or` rule, the footnote, the rail and the one typeface. This sheet
 * adds everything that exists only here: a long page told as one story,
 * and the fork inside it.
 *
 * The story is the link itself. The page opens inside a screen; scrolling
 * pulls back until the screen is a Mac standing on a planet of lights (one
 * light per device, drawn by home-world.js). Then the link leaves the Mac
 * as a thread of light and runs down the page — past the fork, through the
 * four steps a link takes, through the hub that reaches every device — and
 * ends in the last "Get a link to send" (home-thread.js). Everything the
 * thread reaches lights up as it arrives, and that is the page's motion:
 * things answer the reader's scroll, they do not perform on their own.
 *
 * The room is a night sky: --sky, the iPhone app's launch-screen navy,
 * fading into --night, with a fine grain over everything so the gradients
 * read as light rather than as banding. Headings are two lines in two
 * inks — what it is in --ink, what it means in the link's own light.
 *
 * home-scene.js turns the scroll position into custom properties (--zoom,
 * --copy, --cover, --w1..3 on .hero; --in on each heading; --lit on the
 * paragraph that lights up; --tilt on the phone; --read on the rail) and a
 * few classes. Without the module, or under prefers-reduced-motion, every
 * one of them falls back to its finished value, and the page is the same
 * words in the same order, standing still.
 *
 * The fork does not move, ever (test/home-page.test.mjs). Someone is
 * reading it to make one decision.
 *
 * Every colour is a token from site.css and there is no hex literal in
 * this file. What is written out here are white and black at an alpha, the
 * same way site.css writes its hairlines.
 *
 * Scale. The laptop is a size container, and everything in it is measured
 * in cqw of the thing that contains it, so the whole drawing scales as one
 * picture from a phone to a wide monitor. */

/* ---- The room -------------------------------------------------------- */

html:has(body[data-page="home"]) {
  background: var(--night);
  scrollbar-color: var(--surface-3) var(--night);
}

/* The site's dot grid belongs to pages that are one card tall. Here the
   floor is a planet, drawn where the laptop stands. */
html:has(body[data-page="home"])::before {
  display: none;
}

body[data-page="home"] {
  overflow-x: clip;
}

body[data-page="home"] ::selection {
  background: rgb(79 123 255 / 0.42);
  color: var(--ink);
}

/* The sky: --sky behind the top of the window, still drifting on
   site.css's clock, with none of the aurora's violet. */
body[data-page="home"]::before {
  inset: -10vh -10vw auto;
  height: 110vh;
  background:
    radial-gradient(70vw 62vh at 50% 0%, var(--sky-glow), transparent 72%),
    radial-gradient(40vw 40vh at 18% 12%, rgb(79 123 255 / 0.12), transparent 70%),
    radial-gradient(40vw 40vh at 84% 18%, rgb(79 123 255 / 0.1), transparent 70%);
}

/* Grain, over everything: a 128px tile of noise (assets/img/home/
   grain.png), nudged six times a second so it reads as film rather than
   as a dirty screen. It is what keeps a long dark gradient from banding
   into stripes. Under reduced motion it holds still. */
body[data-page="home"]::after {
  inset: -96px;
  height: auto;
  z-index: 60;
  background: url("/assets/img/home/grain.png") 0 0 / 128px 128px;
  opacity: 0.055;
  animation: grain 800ms steps(6) infinite;
}

@keyframes grain {
  0% { transform: translate(0, 0); }
  17% { transform: translate(-37px, 23px); }
  33% { transform: translate(29px, -41px); }
  50% { transform: translate(-13px, 47px); }
  67% { transform: translate(43px, 11px); }
  83% { transform: translate(-31px, -19px); }
  100% { transform: translate(0, 0); }
}

/* The sheet stops being a column: each band below sets its own measure. */
body[data-page="home"] .sheet {
  max-width: none;
  padding: 0;
}

/* ---- The rail -------------------------------------------------------- */

/* Out of the flow, so the hero can start at the top of the window, and
   wide, so the mark sits over the edge of the picture rather than over a
   column that is not there. home-scene.js adds .rail-clear to the body
   while the hero fills the window: the glass goes and the mark floats on
   the sky. Without the module it is ordinary glass all the way down. */
body[data-page="home"] .rail {
  position: fixed;
  inset: 0 0 auto;
  transition:
    background-color var(--slow) var(--ease),
    border-color var(--slow) var(--ease),
    -webkit-backdrop-filter var(--slow) var(--ease),
    backdrop-filter var(--slow) var(--ease);
}

body[data-page="home"].rail-clear .rail {
  background: transparent;
  border-bottom-color: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

body[data-page="home"] .rail-inner {
  max-width: 1200px;
}

/* How far down the story you are, as a hairline of the thread's light
   along the foot of the rail (--read, 0 to 1). */
body[data-page="home"] .rail::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), var(--lavender));
  transform: scaleX(var(--read, 0));
  transform-origin: 0 50%;
  pointer-events: none;
}

/* ---- A band ---------------------------------------------------------- */

/* Every section after the hero: centred, generous, and the same gutter as
   the rest of the site at the edges. */
.band {
  position: relative;
  z-index: 1;
  padding: clamp(112px, 18vh, 208px) calc(env(safe-area-inset-right) + var(--gutter)) 0
    calc(env(safe-area-inset-left) + var(--gutter));
}

.wrap {
  max-width: 1120px;
  margin: 0 auto;
}

/* Two lines, two inks: what it is, then what it means, in the link's own
   light. Weight 500 and tight, because at this size the type is the
   picture. Each line rises out of a blur as the heading comes up the
   window (--in, --in2, from home-scene.js); without the module both are 1
   and the heading simply stands there. */
.title {
  margin: 0 auto;
  color: var(--ink);
  font-size: clamp(2.4rem, 6.2vw, 5.4rem);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: -0.05em;
  text-align: center;
  text-wrap: balance;
}

.title > span {
  display: block;
  opacity: calc(0.1 + 0.9 * var(--in, 1));
  transform: translateY(calc((1 - var(--in, 1)) * 0.34em));
  filter: blur(calc((1 - var(--in, 1)) * 10px));
}

.title > .title-2 {
  padding-bottom: 0.08em;
  background: linear-gradient(100deg, var(--accent-hi) 8%, var(--lavender) 52%, var(--ice) 96%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  opacity: calc(0.1 + 0.9 * var(--in2, 1));
  transform: translateY(calc((1 - var(--in2, 1)) * 0.34em));
  filter: blur(calc((1 - var(--in2, 1)) * 10px));
}

.band-lead {
  max-width: 52ch;
  margin: 24px auto 0;
  color: var(--ink-2);
  font-size: clamp(1rem, 1.5vw, 1.18rem);
  line-height: 1.6;
  text-align: center;
  text-wrap: pretty;
}

/* Apple's badge under the lead it belongs to, centred as the lead is
   (site.css .store-badge sizes it). */
.band-lead + .store-badge {
  margin: 28px auto 0;
}

/* The icons the bands draw: one stroke weight, the site's. */
.icon {
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---- The thread ------------------------------------------------------ */

/* The link, as a line of light down the page (home-thread.js). It lies
   behind every band's content, so it passes behind the cards, the step
   numbers, the hub and the last button rather than over any of them: where
   it seems to enter something, it does. The way ahead is a faint dotted
   route; the way already travelled is lit, with a soft glow under it and
   a spark at its head. */
.thread {
  position: absolute;
  z-index: 0;
  top: 0;
  left: 0;
  overflow: visible;
  pointer-events: none;
}

.thread-ink-a {
  stop-color: var(--accent-hi);
}

.thread-ink-b {
  stop-color: var(--lavender);
}

.thread-ink-c {
  stop-color: var(--accent);
}

.thread-halo-a {
  stop-color: var(--ice);
  stop-opacity: 0.9;
}

.thread-halo-b {
  stop-color: var(--accent);
  stop-opacity: 0;
}

.thread-way {
  fill: none;
  stroke: rgb(134 162 255 / 0.16);
  stroke-width: 1;
  stroke-dasharray: 1 8;
  stroke-linecap: round;
}

.thread-glow {
  fill: none;
  stroke: url(#thread-ink);
  stroke-width: 8;
  stroke-linecap: round;
  opacity: 0.14;
}

.thread-line {
  fill: none;
  stroke: url(#thread-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
}

.thread-tip {
  opacity: 0;
  transition: opacity var(--slow) var(--ease);
}

.thread.is-drawing .thread-tip {
  opacity: 1;
}

.thread-tip-halo {
  fill: url(#thread-halo);
}

.thread-tip-core {
  fill: var(--ice);
}

/* ---- The hero -------------------------------------------------------- */

/* Still, this is a column: the words, then the picture. The rail floats
   over it, so the stage clears the rail's height before anything else. */
.hero {
  position: relative;
}

.hero-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: calc(env(safe-area-inset-top) + 64px + clamp(28px, 8vh, 88px)) var(--gutter) 0;
  overflow: clip;
  text-align: center;
}

/* The planet home-world.js draws: the whole stage, behind everything. */
.hero-canvas {
  position: absolute;
  z-index: 0;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.hero-copy {
  position: relative;
  z-index: 3;
  max-width: 820px;
}

/* The link, as it lands on his screen: a notification from Priya, with
   the two ticks that say it was opened. It drops in first, on its own
   spring, and the ticks draw themselves a moment later. */
.hero-pill {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  max-width: 100%;
  margin: 0;
  padding: 8px 10px 8px 8px;
  border: 1px solid var(--line);
  border-radius: 22px;
  background: rgb(10 14 28 / 0.72);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--shadow-lift);
  text-align: left;
  animation: pill-in 1000ms cubic-bezier(0.2, 1.25, 0.32, 1) 200ms both;
}

@keyframes pill-in {
  from {
    opacity: 0;
    transform: translateY(-28px) scale(0.9);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.hero-pill-avatar {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--grad);
  color: var(--accent-ink);
  font-size: 16px;
  font-weight: 700;
}

.hero-pill-body {
  display: grid;
  min-width: 0;
  line-height: 1.3;
}

.hero-pill-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.hero-pill-name {
  color: var(--ink);
  font-size: 14px;
  font-weight: 650;
}

.hero-pill-time {
  color: var(--faint);
  font-size: 12px;
  font-weight: 550;
}

.hero-pill-text {
  overflow: hidden;
  max-width: 290px;
  color: var(--ink-2);
  font-size: 13.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hero-pill-seen {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-left: 10px;
  border: 1.5px solid var(--ok);
  border-radius: 50%;
  color: var(--ok);
}

.hero-pill-seen svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 16;
  animation: ticks 700ms var(--ease) 1150ms both;
}

@keyframes ticks {
  from {
    stroke-dashoffset: 16;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* A poster, not a card title. Each line rises once out of its own mask,
   the second a beat after the first: the page's opening, and the only
   motion on it that nobody asked for. */
.hero h1 {
  max-width: 14ch;
  margin: 30px auto 0;
  color: var(--ink);
  font-size: clamp(2.7rem, 7vw, 6.2rem);
  font-weight: 600;
  line-height: 0.98;
  letter-spacing: -0.055em;
}

.hero h1 .line {
  display: block;
  overflow: clip;
  padding-bottom: 0.1em;
  margin-bottom: -0.1em;
}

.hero h1 .line > span {
  display: inline-block;
  animation: line-rise 1150ms cubic-bezier(0.16, 0.84, 0.22, 1) 420ms both;
}

.hero h1 .line + .line > span {
  animation-delay: 540ms;
}

@keyframes line-rise {
  from {
    transform: translateY(108%);
  }
  to {
    transform: none;
  }
}

.hero .lead {
  max-width: 50ch;
  margin: 26px auto 0;
  font-size: clamp(1rem, 1.4vw, 1.2rem);
  animation: settle 1000ms var(--ease) 860ms both;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 36px;
}

.hero .hero-actions {
  animation: settle 1000ms var(--ease) 1000ms both;
}

@keyframes settle {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.hero-actions .button {
  width: auto;
  min-width: 214px;
  margin: 0;
}

/* The filled button catches a line of light under the pointer: a band of
   white swept once across it, so it answers being aimed at. */
.hero-actions .primary {
  position: relative;
  overflow: hidden;
}

.hero-actions .primary::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 30%, rgb(255 255 255 / 0.38) 50%, transparent 70%);
  transform: translateX(-120%);
  pointer-events: none;
}

@media (hover: hover) {
  .hero-actions .primary:hover::after {
    transform: translateX(120%);
    transition: transform 900ms var(--ease);
  }
}

/* The quiet partner of the filled button: an outline on the sky, the same
   height, so the pair reads as one row. */
.ghost {
  background: rgb(255 255 255 / 0.04);
  border: 1px solid var(--line-loud);
  color: var(--ink);
  font-size: 16px;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

@media (hover: hover) {
  .ghost:hover {
    background: rgb(255 255 255 / 0.08);
    border-color: var(--accent-line);
  }
}

/* "There is more below": a small pill with a dot running down it, at the
   foot of the first screen. It goes with the headline. */
.hero-cue {
  position: absolute;
  z-index: 3;
  left: 50%;
  bottom: max(26px, 4vh);
  display: none;
  width: 24px;
  height: 38px;
  translate: -50% 0;
  border: 1.5px solid var(--line-loud);
  border-radius: var(--radius-pill);
}

.hero.is-scrubbed .hero-cue {
  display: block;
  opacity: calc(var(--copy, 1) * 0.85);
}

.hero-cue-dot {
  position: absolute;
  left: 50%;
  top: 7px;
  width: 4px;
  height: 8px;
  translate: -50% 0;
  border-radius: 2px;
  background: var(--ink);
  animation: cue 2s var(--ease) 1.6s infinite;
}

@keyframes cue {
  0% {
    opacity: 0;
    transform: translateY(0);
  }
  30% {
    opacity: 1;
  }
  80%,
  100% {
    opacity: 0;
    transform: translateY(13px);
  }
}

/* The three words only exist in the scroll story (below). */
.hero-words {
  display: none;
}

/* The picture, still: under the words, on the planet. Hidden until
   home-scene.js has measured it, so the scroll story never opens on one
   frame of the still layout; shown at once where there is no script to
   wait for, or no motion to set up. */
.device {
  position: relative;
  z-index: 2;
  width: min(920px, 100%);
  margin: clamp(44px, 8vh, 80px) auto 0;
  padding-bottom: 10vh;
  opacity: 0;
  transition: opacity 900ms var(--ease);
}

.hero.is-ready .device {
  opacity: 1;
}

@media (scripting: none) {
  .device {
    opacity: 1;
  }
}

/* A stage light behind the machine, so the eye lands on the screen. */
.device::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -12%;
  width: 120%;
  height: 90%;
  translate: -50% 0;
  background: radial-gradient(closest-side, var(--sky-glow), transparent);
  pointer-events: none;
}

.scene {
  position: relative;
  container-type: inline-size;
  pointer-events: none;
  user-select: none;
}

/* What the screen shows while it fills the window: a lock-screen of
   slowly turning light, darker in the middle where the headline sits.
   Only the scroll story turns it up (--cover); still, it is off. */
.screen-cover {
  position: absolute;
  z-index: 7;
  inset: 0;
  overflow: hidden;
  background: var(--night);
  opacity: var(--cover, 0);
  pointer-events: none;
}

.screen-cover::before {
  content: "";
  position: absolute;
  inset: -30%;
  background:
    radial-gradient(36% 32% at 26% 30%, rgb(79 123 255 / 0.62), transparent 70%),
    radial-gradient(32% 30% at 74% 24%, rgb(124 92 255 / 0.55), transparent 70%),
    radial-gradient(44% 36% at 58% 80%, rgb(27 127 163 / 0.45), transparent 72%),
    radial-gradient(60% 50% at 50% 50%, var(--sky), transparent 80%);
  animation: wallpaper 26s ease-in-out infinite alternate;
}

.screen-cover::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(50% 40% at 50% 40%, rgb(4 6 13 / 0.6), transparent 78%),
    linear-gradient(180deg, transparent 50%, rgb(4 6 13 / 0.75));
}

@keyframes wallpaper {
  from {
    transform: rotate(0deg) scale(1);
  }
  to {
    transform: rotate(16deg) scale(1.14);
  }
}

/* ---- The hero as a scroll story -------------------------------------- */

/* Three and a half windows of scroll for one window of picture: the stage
   sticks while the hero scrolls past it. */
.hero.is-scrubbed {
  height: 340vh;
}

.hero.is-scrubbed .hero-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  min-height: 0;
}

/* The words go first, up and out, while the screen is still dark behind
   them. Once they are gone they are gone for the keyboard too (.copy-gone),
   so nobody tabs into a link they cannot see. */
.hero.is-scrubbed .hero-copy {
  opacity: var(--copy, 1);
  transform: translateY(calc((1 - var(--copy, 1)) * -8vh)) scale(calc(0.94 + 0.06 * var(--copy, 1)));
}

.hero.copy-gone .hero-copy {
  visibility: hidden;
}

/* The machine is centred on the stage and starts scaled up around the top
   centre of its screen (--ox, --oy), pushed down by --ty so only the rim
   shows; both run to their resting values as the scroll goes on. */
.hero.is-scrubbed .device {
  --device-w: min(800px, 54vw);
  position: absolute;
  left: 50%;
  top: 52%;
  width: var(--device-w);
  margin: 0;
  padding: 0;
  translate: -50% -50%;
  transform: translateY(var(--ty, 0px)) scale(var(--zoom, 1));
  transform-origin: var(--ox, 50%) var(--oy, 0);
  will-change: transform;
}

.hero.is-scrubbed .device::before {
  opacity: calc(1 - var(--cover, 0));
}

/* The still layout's opening (lid, power-on) has no place here: the screen
   wakes with the scroll instead. The picture on it keeps playing. */
.hero.is-scrubbed .laptop,
.hero.is-scrubbed .lid,
.hero.is-scrubbed .screen > :not(.glare),
.hero.is-scrubbed .screen::after {
  animation: none;
}

.hero.is-scrubbed .hero-words {
  display: block;
  position: absolute;
  z-index: 1;
  inset: 0;
  margin: 0;
  pointer-events: none;
}

/* Each word arrives out of focus and thin and settles sharp and heavy:
   the variable axis runs from 200 to 600 as --w goes from 0 to 1, the
   tracking closes, the blur clears. */
.word {
  position: absolute;
  color: var(--ink);
  font-size: clamp(3rem, 7.6vw, 8rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.055em;
  white-space: nowrap;
}

.word-send {
  left: max(var(--gutter), 4vw);
  top: 48%;
  font-weight: calc(200 + 400 * var(--w1, 0));
  letter-spacing: calc(0.14em - 0.195em * var(--w1, 0));
  opacity: var(--w1, 0);
  filter: blur(calc((1 - var(--w1, 0)) * 16px));
  transform: translate(calc((1 - var(--w1, 0)) * -5vw), -50%);
}

.word-see {
  right: max(var(--gutter), 4vw);
  top: 48%;
  padding-right: 0.06em;
  background: linear-gradient(100deg, var(--accent-hi), var(--lavender));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: calc(200 + 400 * var(--w2, 0));
  letter-spacing: calc(0.14em - 0.195em * var(--w2, 0));
  opacity: var(--w2, 0);
  filter: blur(calc((1 - var(--w2, 0)) * 16px));
  transform: translate(calc((1 - var(--w2, 0)) * 5vw), -50%);
}

.word-fix {
  left: 50%;
  bottom: 4vh;
  font-weight: calc(200 + 400 * var(--w3, 0));
  letter-spacing: calc(0.14em - 0.195em * var(--w3, 0));
  opacity: var(--w3, 0);
  filter: blur(calc((1 - var(--w3, 0)) * 16px));
  transform: translate(-50%, calc((1 - var(--w3, 0)) * 5vh));
}

/* A phone held upright: the laptop takes the width, two words stand above
   it and the third below. */
@media (max-width: 760px) {
  .hero.is-scrubbed {
    height: 300vh;
  }

  .hero.is-scrubbed .device {
    --device-w: calc(100vw - 2 * var(--gutter));
    top: 50%;
  }

  .word-send,
  .word-see {
    top: 25%;
  }

  .word-fix {
    bottom: 16%;
  }
}

/* ---- The machine ----------------------------------------------------- */

/* A container of its own, so everything below is drawn in fractions of
   the laptop. It hovers slowly once the still hero has opened it. */
.laptop {
  position: relative;
  width: 100%;
  container-type: inline-size;
  perspective: 2400px;
  animation: hover 7s ease-in-out 2.6s infinite alternate;
}

@keyframes hover {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-0.7cqw);
  }
}

/* The lid, hinged on its bottom edge. It starts folded down onto the deck
   and swings up once; the anodised rim is the lid's own padding. */
.lid {
  position: relative;
  width: 88cqw;
  margin: 0 auto;
  padding: 0.38cqw;
  border-radius: 3.2cqw 3.2cqw 0.6cqw 0.6cqw;
  background: linear-gradient(180deg, var(--metal-hi), var(--metal) 45%, var(--metal-lo));
  transform-origin: 50% 100%;
  animation: lid-open 1500ms cubic-bezier(0.18, 0.84, 0.24, 1) 350ms both;
  box-shadow:
    0 0 0 1px rgb(0 0 0 / 0.5),
    0 3cqw 8cqw -2cqw rgb(79 123 255 / 0.35);
}

@keyframes lid-open {
  from {
    transform: rotateX(-86deg);
  }
  to {
    transform: rotateX(0);
  }
}

.bezel {
  position: relative;
  padding: 1.5cqw 1.4cqw 2.3cqw;
  border-radius: 2.9cqw 2.9cqw 0.4cqw 0.4cqw;
  background: var(--bezel);
}

.notch {
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 1.45cqw;
  width: 10cqw;
  height: 1.5cqw;
  translate: -50% 0;
  border-radius: 0 0 0.7cqw 0.7cqw;
  background: var(--bezel);
}

.notch::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 0.35cqw;
  width: 0.55cqw;
  height: 0.55cqw;
  translate: -50% 0;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, rgb(79 123 255 / 0.8), rgb(0 0 0) 70%);
}

/* The panel. Its own container, so the desktop inside is drawn in
   fractions of the screen and stays pin-sharp at every size. */
.screen {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: 0.8cqw 0.8cqw 0.2cqw 0.2cqw;
  container-type: inline-size;
}

/* It comes on after the lid is up: a flash of backlight, then the picture. */
.screen > :not(.glare):not(.screen-cover) {
  animation: power-on 700ms var(--ease) 1650ms both;
}

.screen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 9;
  background: radial-gradient(circle at 50% 50%, rgb(160 180 255 / 0.9), rgb(79 123 255 / 0.25) 45%, transparent 75%);
  opacity: 0;
  animation: backlight 900ms ease-out 1500ms both;
  pointer-events: none;
}

@keyframes power-on {
  from {
    opacity: 0;
    filter: brightness(2.2) saturate(0.4);
  }
  to {
    opacity: 1;
    filter: none;
  }
}

@keyframes backlight {
  0% {
    opacity: 0;
    transform: scaleY(0.02);
  }
  35% {
    opacity: 1;
    transform: scaleY(1);
  }
  100% {
    opacity: 0;
  }
}

.glare {
  position: absolute;
  inset: 0;
  z-index: 8;
  background: linear-gradient(118deg, rgb(255 255 255 / 0.09) 0%, rgb(255 255 255 / 0.02) 34%, transparent 35%);
}

/* The deck, seen edge-on: a slab a little wider than the lid, lit along its
   top, with the thumb scoop in the middle of the front edge. */
.deck {
  position: relative;
  width: 100cqw;
  height: 2.3cqw;
  margin-top: -0.1cqw;
  border-radius: 0.4cqw 0.4cqw 3cqw 3cqw / 0.4cqw 0.4cqw 1.6cqw 1.6cqw;
  background:
    linear-gradient(90deg, rgb(0 0 0 / 0.45), transparent 8%, transparent 92%, rgb(0 0 0 / 0.45)),
    linear-gradient(180deg, var(--metal-hi) 0%, var(--metal) 32%, var(--metal-lo) 100%);
  box-shadow: 0 1px 0 rgb(255 255 255 / 0.08) inset;
}

.deck-lip {
  position: absolute;
  left: 50%;
  top: 0;
  width: 15cqw;
  height: 0.8cqw;
  translate: -50% 0;
  border-radius: 0 0 1cqw 1cqw;
  background: linear-gradient(180deg, var(--metal-lo), var(--metal));
}

/* The screen's light on the floor, and the machine's shadow in it. */
.laptop-shadow {
  position: absolute;
  left: -8cqw;
  right: -8cqw;
  bottom: -7cqw;
  height: 11cqw;
  z-index: -1;
  background:
    radial-gradient(50% 30% at 50% 40%, rgb(0 0 0 / 0.75), transparent),
    radial-gradient(50% 50% at 50% 45%, rgb(79 123 255 / 0.32), transparent 75%);
}

/* ---- Your Mac's screen ----------------------------------------------- */

.mac-bar {
  position: absolute;
  inset: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 1.6cqw;
  height: 2.5cqw;
  padding: 0 2cqw;
  background: rgb(10 13 26 / 0.92);
}

.mac-dot {
  width: 1.1cqw;
  height: 1.1cqw;
  border-radius: 50%;
  background: var(--ink-2);
}

.mac-bar i {
  width: 3.4cqw;
  height: 0.7cqw;
  border-radius: 0.4cqw;
  background: rgb(255 255 255 / 0.28);
}

.mac-bar i:first-of-type {
  width: 4.8cqw;
  background: rgb(255 255 255 / 0.6);
}

.mac-clock {
  margin-left: auto;
  color: var(--ink-2);
  font-size: 1.25cqw;
  font-weight: 600;
  line-height: 1;
}

/* Behind the browser, your own wallpaper: the site's own aurora. */
.screen {
  background:
    radial-gradient(60% 70% at 18% 20%, rgb(124 92 255 / 0.55), transparent),
    radial-gradient(60% 70% at 85% 90%, rgb(79 123 255 / 0.5), transparent),
    var(--paper);
}

.browser {
  position: absolute;
  top: 3.8cqw;
  left: 2.4cqw;
  right: 2.4cqw;
  bottom: 2.4cqw;
  overflow: hidden;
  border-radius: 1.1cqw;
  background: var(--surface);
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.08),
    0 2cqw 5cqw rgb(0 0 0 / 0.55);
}

.browser-bar {
  display: flex;
  align-items: center;
  height: 3.6cqw;
  padding: 0 1.4cqw;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}

.lights {
  display: flex;
  gap: 0.6cqw;
}

.lights i {
  width: 1cqw;
  height: 1cqw;
  border-radius: 50%;
  background: var(--danger);
}

.lights i:nth-child(2) {
  background: var(--warn);
}

.lights i:nth-child(3) {
  background: var(--ok);
}

.url {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6cqw;
  width: 44cqw;
  height: 2.2cqw;
  margin: 0 auto;
  translate: -2.4cqw 0;
  border-radius: 0.7cqw;
  background: rgb(255 255 255 / 0.06);
  color: var(--ink-2);
  font-size: 1.2cqw;
  font-weight: 550;
  line-height: 1;
  white-space: nowrap;
}

.url svg {
  width: 1.2cqw;
  height: 1.2cqw;
  fill: none;
  stroke: var(--ok);
  stroke-width: 2.2;
}

/* ---- Their PC, in the tab -------------------------------------------- */

/* Positions inside here are percentages of their screen, so the cursor and
   the windows it drags share one coordinate system and cannot drift apart. */
.remote {
  position: absolute;
  inset: 3.6cqw 0 0;
  overflow: hidden;
}

.remote-wall {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(55% 75% at 22% 18%, var(--desk-b), transparent 70%),
    radial-gradient(60% 80% at 88% 92%, var(--desk-c), transparent 72%),
    linear-gradient(160deg, var(--desk-a), var(--desk-a));
}

.rwin {
  position: absolute;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 0.8cqw;
  background: var(--win);
  box-shadow:
    0 0 0 1px rgb(0 0 0 / 0.08),
    0 1.6cqw 3.4cqw rgb(0 0 0 / 0.38);
}

.rwin-bar {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: flex-end;
  gap: 1.1cqw;
  height: 2.3cqw;
  padding: 0 1.1cqw;
  background: var(--win-soft);
  border-bottom: 1px solid var(--win-line);
}

.rwin-bar i {
  width: 0.9cqw;
  height: 0.9cqw;
  border: 1.5px solid rgb(26 34 64 / 0.55);
  border-radius: 0.15cqw;
}

.rwin-bar i:first-child {
  height: 0;
  border-width: 1px 0 0;
}

.rwin-doc {
  left: 7%;
  top: 11%;
  width: 42%;
  height: 62%;
  gap: 1.15cqw;
}

.rwin-doc > span:not(.rwin-bar) {
  margin-left: 2.2cqw;
}

.doc-title {
  width: 45%;
  height: 1.5cqw;
  margin-top: 1.4cqw;
  border-radius: 0.4cqw;
  background: var(--win-ink);
}

.doc-line {
  width: 82%;
  height: 0.8cqw;
  border-radius: 0.4cqw;
  background: var(--win-line);
}

.doc-line-short {
  width: 56%;
}

/* The line being typed: a darker bar that grows in keystrokes, with the
   caret riding its end. */
.doc-type {
  display: flex;
  align-items: center;
  width: 70%;
  height: 1.2cqw;
}

.doc-typed {
  width: 0;
  height: 0.8cqw;
  border-radius: 0.4cqw;
  background: var(--accent);
  animation: type 10s 2.6s infinite both;
}

.caret {
  width: 0.22cqw;
  height: 1.5cqw;
  margin-left: 0.25cqw;
  background: var(--accent-2);
  animation: blink 1s steps(1) infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

@keyframes type {
  0%,
  38% {
    width: 0;
    opacity: 1;
    animation-timing-function: steps(14, end);
  }
  56%,
  92% {
    width: 100%;
    opacity: 1;
  }
  96% {
    width: 100%;
    opacity: 0;
  }
  97%,
  100% {
    width: 0;
    opacity: 1;
  }
}

.rwin-chart {
  left: 50%;
  top: 24%;
  width: 40%;
  height: 50%;
  animation: drag 10s ease-in-out 2.6s infinite both;
}

.chart {
  display: flex;
  flex: 1;
  align-items: flex-end;
  gap: 1cqw;
  padding: 1.8cqw 2cqw 2cqw;
  background:
    repeating-linear-gradient(180deg, transparent 0 2.4cqw, rgb(26 34 64 / 0.07) 2.4cqw calc(2.4cqw + 1px));
}

.chart i {
  flex: 1;
  height: 40%;
  border-radius: 0.4cqw 0.4cqw 0 0;
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  transform-origin: 50% 100%;
  animation: bar 3.2s ease-in-out infinite alternate;
}

.chart i:nth-child(1) { height: 38%; animation-delay: 0.2s; }
.chart i:nth-child(2) { height: 62%; animation-delay: 1.1s; }
.chart i:nth-child(3) { height: 48%; animation-delay: 0.6s; }
.chart i:nth-child(4) { height: 80%; animation-delay: 1.7s; }
.chart i:nth-child(5) { height: 56%; animation-delay: 0.9s; }
.chart i:nth-child(6) { height: 92%; animation-delay: 2.2s; }
.chart i:nth-child(7) { height: 70%; animation-delay: 1.4s; }

@keyframes bar {
  to {
    transform: scaleY(0.72);
  }
}

.taskbar {
  position: absolute;
  inset: auto 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.9cqw;
  height: 8%;
  background: rgb(8 12 28 / 0.72);
  border-top: 1px solid rgb(255 255 255 / 0.08);
}

.taskbar i {
  width: 2.2cqw;
  height: 2.2cqw;
  border-radius: 0.5cqw;
  background: rgb(255 255 255 / 0.2);
}

.taskbar i:nth-child(1) {
  background: linear-gradient(135deg, var(--desk-b), var(--accent));
}

.task-hit {
  position: relative;
  animation: task 10s 2.6s infinite both;
}

@keyframes task {
  0%,
  65% {
    background: rgb(255 255 255 / 0.2);
    box-shadow: none;
  }
  67%,
  88% {
    background: var(--win);
    box-shadow: 0 0 1.4cqw rgb(255 255 255 / 0.6);
  }
  92%,
  100% {
    background: rgb(255 255 255 / 0.2);
    box-shadow: none;
  }
}

/* /connect/'s viewer bar, in miniature. */
.live-pill {
  position: absolute;
  top: 3%;
  left: 50%;
  z-index: 4;
  display: flex;
  align-items: center;
  gap: 0.6cqw;
  translate: -50% 0;
  padding: 0.55cqw 1.2cqw;
  border: 1px solid rgb(255 255 255 / 0.12);
  border-radius: 999px;
  background: rgb(7 10 20 / 0.82);
  color: var(--ink);
  font-size: 1.15cqw;
  font-weight: 650;
  line-height: 1;
  white-space: nowrap;
}

.live-dot {
  width: 0.9cqw;
  height: 0.9cqw;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 0 rgb(53 211 153 / 0.6);
  animation: pulse 1.8s ease-out infinite;
}

@keyframes pulse {
  to {
    box-shadow: 0 0 0 0.9cqw rgb(53 211 153 / 0);
  }
}

.live-sep {
  width: 1px;
  height: 1.2cqw;
  background: rgb(255 255 255 / 0.2);
}

.live-pill svg {
  width: 1.2cqw;
  height: 1.2cqw;
  fill: var(--accent-2);
}

/* ---- Your cursor on their screen ------------------------------------- */

/* One ten-second loop, shared with the window it drags, the line it types
   and the taskbar icon it opens: same duration, same delay, so every click
   lands on the thing it clicks.
     10%  press on the chart's title bar     26%  let go, window moved
     36%  click into the document            38-56%  a line types in
     66%  open the taskbar icon              76-88%  drag the chart back
   The left/top pairs are the cursor tip in the remote screen's own
   percentages; the drag offsets the window by exactly what the cursor
   travels, which is (-12%, -8%). */
.cursor {
  position: absolute;
  z-index: 6;
  left: 64%;
  top: 72%;
  width: 2.6cqw;
  animation: steer 10s 2.6s infinite both;
}

.cursor svg {
  display: block;
  width: 100%;
  margin: -0.35cqw 0 0 -0.5cqw;
  fill: var(--accent-2);
  stroke: var(--win);
  stroke-width: 1.6;
  stroke-linejoin: round;
  filter: drop-shadow(0 0.3cqw 0.4cqw rgb(0 0 0 / 0.45));
}

.cursor-tag {
  position: absolute;
  left: 1.6cqw;
  top: 2cqw;
  padding: 0.3cqw 0.7cqw;
  border-radius: 999px 999px 999px 0.3cqw;
  background: var(--accent-2);
  color: var(--accent-ink);
  font-size: 1.05cqw;
  font-weight: 700;
  line-height: 1.1;
  box-shadow: 0 0.3cqw 1cqw rgb(124 92 255 / 0.5);
}

@keyframes steer {
  0%,
  100% {
    left: 64%;
    top: 72%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
  }
  10%,
  12% {
    left: 74%;
    top: 27.5%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.35, 1);
  }
  26% {
    left: 62%;
    top: 19.5%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
  }
  34%,
  37% {
    left: 22%;
    top: 44%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
  }
  42%,
  56% {
    left: 30%;
    top: 56%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
  }
  64%,
  67% {
    left: 50%;
    top: 96%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
  }
  74%,
  76% {
    left: 62%;
    top: 19.5%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.35, 1);
  }
  88% {
    left: 74%;
    top: 27.5%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
  }
}

/* The chart window follows the cursor between press and release. */
@keyframes drag {
  0%,
  12%,
  88%,
  100% {
    left: 50%;
    top: 24%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.35, 1);
  }
  26%,
  76% {
    left: 38%;
    top: 16%;
    animation-timing-function: cubic-bezier(0.45, 0, 0.35, 1);
  }
}

/* Where each click lands: a ring that opens out and fades. */
.ripple {
  position: absolute;
  z-index: 5;
  width: 4.4cqw;
  height: 4.4cqw;
  translate: -50% -50%;
  border: 0.25cqw solid var(--accent-2);
  border-radius: 50%;
  opacity: 0;
  animation: 10s 2.6s infinite both;
}

.ripple-1 { left: 74%; top: 27.5%; animation-name: click-1; }
.ripple-2 { left: 22%; top: 44%; animation-name: click-2; }
.ripple-3 { left: 50%; top: 96%; animation-name: click-3; }
.ripple-4 { left: 62%; top: 19.5%; animation-name: click-4; }

@keyframes click-1 {
  0%, 10% { opacity: 0; transform: scale(0.3); }
  11% { opacity: 1; }
  16%, 100% { opacity: 0; transform: scale(1.4); }
}

@keyframes click-2 {
  0%, 35% { opacity: 0; transform: scale(0.3); }
  36% { opacity: 1; }
  41%, 100% { opacity: 0; transform: scale(1.4); }
}

@keyframes click-3 {
  0%, 65% { opacity: 0; transform: scale(0.3); }
  66% { opacity: 1; }
  71%, 100% { opacity: 0; transform: scale(1.4); }
}

@keyframes click-4 {
  0%, 75% { opacity: 0; transform: scale(0.3); }
  76% { opacity: 1; }
  81%, 100% { opacity: 0; transform: scale(1.4); }
}


/* ---- The fork -------------------------------------------------------- */

/* The card holds the two doors exactly as it always has; the band only
   gives it a heading and room. */
.start .card {
  max-width: 1040px;
  margin: clamp(40px, 7vh, 64px) auto 0;
}

.start .home-aside {
  text-align: center;
}

.card > .door:first-child {
  margin-top: 0;
}

/* ---- A door ---------------------------------------------------------- */

/* The bigger ask. On a light ground this panel was a step DOWN — --paper
   inside a white card — because on paper, recessed means darker. Down here
   the relationship inverts: an inset surface has to be a step UP in
   lightness or it disappears into the card it is cut into. So --surface-2,
   the canvas's third step, and no shadow at all. A shadow would claim the
   panel is lifted off the card, and it is sunk into it.
   The border stays the site's --line rather than the quieter --line-soft
   the system gives most insets: this one panel is the page's whole
   hierarchy, and it is allowed the louder edge. */
.door {
  margin: 28px 0 0;
  padding: 20px 20px 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius-inset);
  background: var(--surface-2);
}

/* The lighter half. It keeps the same internal rhythm as the bordered one —
   title, sentence, button — so the two read as a pair of answers to one
   question rather than a block and an afterthought. No face and no edge:
   the weight between the tiers is space, never colour, so this one is the
   card showing through. */
.door-quiet {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
}

/* A shade under the card title in site.css's scale, and set on the variable
   axis at 650 rather than snapped to 600 — the half-step is what keeps a
   heading this small from reading as bold body copy. */
.door-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--ink);
  font-size: 18px;
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

/* The two glyphs are the site's own: the pointer that stands for control,
   and the eye that stands for view-only on /share/ and on /j/<code>. Nobody
   has to learn a new pair here. Both are --accent, and deliberately the
   same --accent: tinting the quiet door's eye down would make the fork a
   colour hierarchy, which is the one thing this page may not be.
   site.css's icon rule lists .badge/.callout-icon/.footnote and does not
   reach in here, so the stroke setup is restated rather than inherited —
   without it these two ship as solid silhouettes. */
.door-title svg {
  width: 20px;
  height: 20px;
  color: var(--accent);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.door-text {
  margin: 9px 0 0;
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.55;
}

/* Inside a door the button follows its sentence closely: the two are one
   statement, and site.css's 24px would let the panel come between them.
   The quiet door's button needs the gap stated too, because site.css gives
   a margin to the filled button and not to the outlined one. */
.door .primary,
.door .secondary {
  margin-top: 18px;
}

/* The steps are consequences, not instructions to this reader — they happen
   on someone else's computer — so they sit a size down from the sentence
   that introduced them. */
.door .steps {
  margin-top: 18px;
}

.door .steps li {
  padding-top: 4px;
  padding-bottom: 4px;
  font-size: 14px;
}

/* Only the vertical nudge is needed now. The numeral chip's fill is
   site.css's --surface-3, which is already one step above the --surface-2
   this door is made of, so the chip keeps reading as a chip without this
   file restating a colour. (It used to have to: on white, a chip inside a
   panel had to be painted back up to --card by hand.) */
.door .steps li::before {
  top: 6px;
}

/* The caveat under a door: the thing that is true whether or not anyone
   wants it to be. It goes to --muted, which on this ground is a genuine
   5.4:1 and carries words again — on the white build the same token was
   4.35:1 and the comment here had to apologise for reaching past it to
   --ink-2. Three tiers of ink now do the work three sizes used to:
   title --ink, sentence --ink-2, caveat --muted. */
.door-note {
  margin: 15px 0 0;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.5;
}

/* ---- Under the card -------------------------------------------------- */

/* The third way in — nine digits read aloud — lives outside the card, below
   both doors, because it is not a third choice of the same kind: it needs
   someone at the other computer who already has Nexivo open. Out here it is
   sitting straight on --paper with the aurora behind it, so it takes
   --ink-2 rather than --muted; the card's lift is not under it to help. */
.home-aside {
  margin: 20px 0 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.5;
}

.home-aside a {
  color: var(--accent);
  font-weight: 600;
  text-underline-offset: 2px;
  transition: color var(--fast) var(--ease);
}

/* Hover goes LIGHTER here, not darker. On paper a link deepened under the
   cursor; over near-black the same move would walk it towards the
   background. --accent-2 is the mark's upper stop and the same colour the
   focus ring uses, so keyboard and mouse agree about which blue means
   "this responds". */
@media (hover: hover) {
  .home-aside a:hover {
    color: var(--accent-2);
  }
}

/* ---- The fork goes two-up -------------------------------------------- */

/* Above 900px the card stops being a column. The markup is not touched:
   one .card holding .door, p.or and .door-quiet, in that order. Turning the
   card into a three-track grid drops them into door | rule | door without a
   single element moving in the HTML. */
@media (min-width: 900px) {
  .card {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    column-gap: clamp(28px, 3.2vw, 48px);
    padding: 44px 40px 40px;
  }

  /* Both doors start on the same line and end on the same line — the grid
     stretches them to a shared height — so the pair reads as one object
     with a rule through it rather than as a card sitting inside a card. */
  .card > .door {
    margin: 0;
  }

  /* The rule stands up. Same element, same word, same hairline token: only
     the axis changes. .or itself stays in site.css and is never re-declared
     here — this is a descendant override, hence .card > .or. */
  .card > .or {
    flex-direction: column;
    gap: 16px;
    margin: 0;
  }

  /* In a column flex box the pseudo-elements' cross size is their width,
     and site.css leaves it to the content, which is "". Without an explicit
     width the two hairlines measure zero and the rule vanishes. */
  .card > .or::before,
  .card > .or::after {
    width: 1px;
    height: auto;
  }
}

/* The card's edge catches the light from above and from its far corner:
   a hairline drawn with a gradient through a mask, still. The decision
   inside it never moves. */
.start .card::after {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1px;
  border-radius: inherit;
  background: linear-gradient(160deg, rgb(134 162 255 / 0.55), transparent 32%, transparent 68%, rgb(199 187 255 / 0.32));
  -webkit-mask: linear-gradient(black, black) content-box, linear-gradient(black, black);
  -webkit-mask-composite: xor;
  mask: linear-gradient(black, black) content-box exclude, linear-gradient(black, black);
  pointer-events: none;
}

/* ---- How a link travels ---------------------------------------------- */

/* On a wide screen, four steps in a row, each picture over its number and
   the numbers on one line, so the thread can run through them like a
   wire through beads. Narrower, a timeline: numbers down the left, the
   thread down through them, each step's picture and words to the right. */
.flow-steps {
  display: grid;
  gap: 56px;
  margin: clamp(56px, 9vh, 96px) 0 0;
  padding: 0;
  list-style: none;
}

.flow-step {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  column-gap: 18px;
  align-items: start;
}

.flow-step .vignette {
  grid-column: 2;
}

.flow-node {
  grid-column: 1;
  grid-row: 2;
  margin-top: 22px;
}

.flow-step h3 {
  grid-column: 2;
  grid-row: 2;
  margin: 24px 0 0;
}

.flow-step p {
  grid-column: 2;
}

@media (min-width: 1040px) {
  .flow-steps {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 28px;
  }

  .flow-step {
    display: block;
  }

  .flow-node {
    margin-top: 30px;
  }

  .flow-step h3 {
    margin-top: 18px;
  }
}

/* The bead the thread runs through. A ring on --night until the thread
   reaches it (.is-lit), then the link's own blue with a halo. */
.flow-node {
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 1px solid var(--line-loud);
  border-radius: 50%;
  background: var(--night);
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition:
    background-color var(--slow) var(--ease),
    border-color var(--slow) var(--ease),
    color var(--slow) var(--ease),
    box-shadow var(--slow) var(--ease);
}

.flow-node.is-lit {
  border-color: var(--accent-hi);
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow:
    0 0 0 5px rgb(79 123 255 / 0.16),
    0 0 28px rgb(79 123 255 / 0.65);
}

.flow-step h3 {
  color: var(--ink);
  font-size: 20px;
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.02em;
}

.flow-step p {
  max-width: 34ch;
  margin: 8px 0 0;
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.55;
}

/* Each step's picture: a dark panel with the sky in it, and on it the one
   thing on someone's screen at that moment. Drawn in px, because these are
   small and fixed, unlike the laptop. */
.vignette {
  position: relative;
  display: grid;
  place-items: center;
  height: 240px;
  overflow: hidden;
  border: 1px solid var(--line-soft);
  border-radius: 24px;
  background:
    radial-gradient(80% 70% at 50% 0%, rgb(37 78 190 / 0.34), transparent 75%),
    var(--surface);
  box-shadow: var(--shadow);
}

.v-card {
  display: grid;
  gap: 10px;
  width: min(238px, 86%);
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--card-fill), var(--surface-2);
  box-shadow: var(--shadow-lift);
  color: var(--ink-2);
  font-size: 12.5px;
  line-height: 1.3;
  text-align: left;
}

.v-card .icon {
  width: 14px;
  height: 14px;
}

.v-label {
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
}

.v-url {
  display: flex;
  align-items: center;
  gap: 7px;
  overflow: hidden;
  padding: 9px 10px;
  border-radius: 10px;
  background: var(--surface-3);
  color: var(--ink);
  font-weight: 600;
  white-space: nowrap;
}

/* Copy link, and then Copied: the two labels share one cell and trade
   places, and the button turns the colour of done. */
.v-button {
  display: grid;
  overflow: hidden;
  padding: 8px;
  border-radius: 10px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 650;
  text-align: center;
  transition: background-color var(--slow) var(--ease), color var(--slow) var(--ease);
}

.v-button > span {
  grid-area: 1 / 1;
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
}

.v-copied {
  opacity: 0;
  transform: translateY(100%);
}

.flow-step.is-lit .v-button {
  background: var(--ok);
  color: var(--night);
}

.flow-step.is-lit .v-copy {
  opacity: 0;
  transform: translateY(-100%);
}

.flow-step.is-lit .v-copied {
  opacity: 1;
  transform: none;
}

.v-small {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 11.5px;
}

/* A sent message, the way a phone draws one: whose chat this is along the
   top, the bubble on the right with its tail nearest the sender, and the
   receipt under it. */
.v-chat {
  justify-items: end;
  gap: 8px;
  padding: 12px;
}

.v-chat-head {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-self: stretch;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 650;
}

.v-chat-avatar {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--ink-2);
  font-size: 11px;
}

.v-bubble {
  display: grid;
  gap: 6px;
  max-width: 200px;
  padding: 10px 12px;
  border-radius: 18px 18px 5px 18px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 12.5px;
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
}

.v-bubble-url {
  font-weight: 650;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.v-read {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--accent-hi);
  font-size: 11px;
}

.v-read-label {
  display: grid;
}

.v-read-label > span {
  grid-area: 1 / 1;
  transition: opacity var(--slow) var(--ease) 500ms;
}

.v-sent {
  opacity: 0;
}

.v-who {
  color: var(--ink);
  font-size: 13px;
  font-weight: 650;
}

.v-id {
  margin-top: -6px;
  color: var(--accent-hi);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}

.v-choice {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  font-weight: 550;
  transition:
    border-color var(--slow) var(--ease),
    background-color var(--slow) var(--ease),
    color var(--slow) var(--ease);
}

.v-choice-on {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--ink);
}

.v-radio {
  position: relative;
  flex: none;
  width: 12px;
  height: 12px;
  border: 1.5px solid var(--faint);
  border-radius: 50%;
  transition: border-color var(--slow) var(--ease);
}

.v-radio::after {
  content: "";
  position: absolute;
  inset: 1.5px;
  border-radius: 50%;
  background: var(--accent-2);
  transform: scale(0);
  transition: transform var(--slow) cubic-bezier(0.3, 1.6, 0.4, 1);
}

.v-choice-on .v-radio {
  border-color: var(--accent);
}

.v-choice-on .v-radio::after {
  transform: scale(1);
}

/* Their desktop in your tab, small: a window, a document, your pointer and
   the viewer's Live pill with whose PC it is. The stranger's colours, not
   this site's. */
.v-live {
  position: relative;
  gap: 0;
  padding: 0;
  overflow: hidden;
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
}

.v-window,
.v-desk {
  display: block;
}

.v-window-bar {
  display: flex;
  gap: 5px;
  padding: 8px 10px;
  background: var(--surface-3);
}

.v-window-bar i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--faint);
}

.v-desk {
  position: relative;
  height: 136px;
  background: linear-gradient(135deg, var(--desk-a), var(--desk-b) 55%, var(--desk-c));
}

.v-doc {
  position: absolute;
  left: 12%;
  top: 30%;
  width: 54%;
  height: 58%;
  border-radius: 6px;
  background:
    linear-gradient(var(--win-ink), var(--win-ink)) 10px 10px / 46% 5px no-repeat,
    repeating-linear-gradient(180deg, transparent 0 22px, var(--win-line) 22px 25px) 10px 4px / calc(100% - 20px) 100% no-repeat,
    var(--win);
  box-shadow: 0 10px 24px -10px rgb(0 0 0 / 0.6);
}

.v-pointer {
  position: absolute;
  left: 60%;
  top: 56%;
  width: 18px;
  height: 18px;
}

.v-pointer svg {
  width: 100%;
  height: 100%;
  fill: var(--ink);
  stroke: var(--win-ink);
  stroke-width: 1.4;
  stroke-linejoin: round;
}

.v-live-pill {
  position: absolute;
  top: 36px;
  left: 50%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  translate: -50% 0;
  border-radius: var(--radius-pill);
  background: rgb(4 6 13 / 0.82);
  color: var(--ink);
  font-size: 11px;
  font-weight: 650;
  white-space: nowrap;
  transition: opacity var(--slow) var(--ease) 350ms, transform var(--slow) var(--ease) 350ms;
}

.v-live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ok);
}

.v-live-name {
  padding-left: 6px;
  border-left: 1px solid var(--line-loud);
  color: var(--ink-2);
  font-weight: 550;
}

/* Before the thread reaches a step, its picture waits on the moment before
   its moment. Only once home-scene.js has armed the band: without it every
   picture already shows the moment itself. */
.flow.is-armed .flow-step:not(.is-lit) .v-bubble {
  opacity: 0;
  transform: translateY(16px) scale(0.94);
}

.flow.is-armed .flow-step:not(.is-lit) .v-seen {
  opacity: 0;
}

.flow.is-armed .flow-step:not(.is-lit) .v-sent {
  opacity: 1;
}

.flow.is-armed .flow-step:not(.is-lit) .v-choice-on {
  border-color: var(--line-soft);
  background: transparent;
  color: var(--ink-2);
}

.flow.is-armed .flow-step:not(.is-lit) .v-choice-on .v-radio {
  border-color: var(--faint);
}

.flow.is-armed .flow-step:not(.is-lit) .v-choice-on .v-radio::after {
  transform: scale(0);
}

.flow.is-armed .flow-step:not(.is-lit) .v-live {
  opacity: 0.25;
  transform: scale(0.9);
}

.flow.is-armed .flow-step:not(.is-lit) .v-live-pill {
  opacity: 0;
  transform: translateY(-8px);
}

.flow.is-armed .flow-step.is-lit .v-pointer {
  animation: v-steer 2.8s var(--ease) 500ms both;
}

@keyframes v-steer {
  from {
    transform: translate(46px, 34px);
  }
  to {
    transform: none;
  }
}

/* ---- The phone ------------------------------------------------------- */

/* A phone drawn around a real screenshot: the bezel, the screen's own
   corner, and the island. */
.phone {
  position: relative;
  width: min(260px, 64vw);
  aspect-ratio: 560 / 1217;
  padding: 9px;
  border-radius: 46px;
  background: var(--bezel);
  box-shadow:
    0 0 0 1.5px var(--metal),
    0 0 0 3px var(--metal-lo),
    0 50px 110px -40px var(--sky-glow);
}

.phone-shot {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 37px;
  object-fit: cover;
  object-position: top;
}

.phone-island {
  position: absolute;
  top: 19px;
  left: 50%;
  width: 30%;
  height: 22px;
  translate: -50% 0;
  border-radius: var(--radius-pill);
  background: var(--bezel);
}

.phone-sheen {
  display: none;
}

/* On a phone, each feature is its words, its screen and its chips, one
   after the other. The phone that stays put is a wide-screen thing. */
.pocket-track {
  max-width: 1160px;
  margin: clamp(24px, 5vh, 56px) auto 0;
}

.pocket-phone {
  display: none;
}

.pocket-feature {
  display: grid;
  justify-items: center;
  gap: 28px;
  padding: 56px 0 8px;
  text-align: center;
}

.pocket-text h3 {
  margin: 0;
  color: var(--ink);
  font-size: clamp(1.7rem, 3.2vw, 2.6rem);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.04em;
}

.pocket-text p {
  max-width: 40ch;
  margin: 14px auto 0;
  color: var(--ink-2);
  font-size: 16px;
  line-height: 1.6;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.chip {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px 10px 10px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--card-fill), var(--surface);
  box-shadow: var(--shadow);
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
}

.chip .icon {
  width: 34px;
  height: 34px;
  padding: 8px;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--accent-hi);
}

/* A wide screen: the phone stands still in the middle of the window while
   the three features scroll past it, words on its left and chips on its
   right. The track is a one-column grid and the phone spans all three of
   its rows, under the features, so its sticky range is exactly the three
   features: it lets go with the last one rather than riding on into the
   next band. home-scene.js sets data-screen on the band as each feature's
   words cross the middle of the window, which swaps the screenshot and the
   colour of the light behind the phone, and --tilt turns the phone a few
   degrees as each feature hands over to the next. */
@media (min-width: 960px) {
  .pocket {
    --phone-h: min(620px, 74vh);
  }

  .pocket-track {
    display: grid;
    grid-template-columns: 1fr;
  }

  .pocket-phone {
    position: sticky;
    z-index: 2;
    top: calc(50vh - var(--phone-h) / 2);
    grid-row: 1 / span 3;
    grid-column: 1;
    align-self: start;
    display: flex;
    justify-content: center;
    height: var(--phone-h);
    perspective: 1400px;
    pointer-events: none;
  }

  .pocket-feature {
    grid-column: 1;
  }

  .pocket-feature:nth-of-type(1) {
    grid-row: 1;
  }

  .pocket-feature:nth-of-type(2) {
    grid-row: 2;
  }

  .pocket-feature:nth-of-type(3) {
    grid-row: 3;
  }

  .pocket-phone .phone {
    width: auto;
    height: 100%;
    transform: rotateY(calc(var(--tilt, 0) * 16deg)) rotateX(calc(var(--tilt, 0) * -3deg));
  }

  .pocket-phone .phone-shot {
    position: absolute;
    inset: 9px;
    width: calc(100% - 18px);
    height: calc(100% - 18px);
    opacity: 0;
    transition: opacity var(--slow) var(--ease);
  }

  .pocket[data-screen="1"] .pocket-phone [data-shot="1"],
  .pocket[data-screen="2"] .pocket-phone [data-shot="2"],
  .pocket[data-screen="3"] .pocket-phone [data-shot="3"] {
    opacity: 1;
  }

  /* Glass catches the light as it turns. */
  .phone-sheen {
    display: block;
    position: absolute;
    inset: 9px;
    border-radius: 37px;
    background: linear-gradient(112deg, transparent 32%, rgb(255 255 255 / 0.14) 46%, transparent 60%);
    background-size: 260% 100%;
    background-position: calc(50% + var(--tilt, 0) * 70%) 0;
    pointer-events: none;
  }

  /* The light behind the phone: the link's blue while it asks, the green
     of safe while it only shows, the mark's violet while it reaches out. */
  .pocket-glow {
    position: absolute;
    left: 50%;
    top: 50%;
    width: calc(var(--phone-h) * 1.25);
    aspect-ratio: 1;
    translate: -50% -50%;
    border-radius: 50%;
    background: radial-gradient(closest-side, currentColor, transparent);
    color: var(--accent);
    opacity: 0.3;
    transition: color 900ms var(--ease);
  }

  .pocket[data-screen="2"] .pocket-glow {
    color: var(--ok);
  }

  .pocket[data-screen="3"] .pocket-glow {
    color: var(--accent-2);
  }

  .phone-inline {
    display: none;
  }

  .pocket-feature {
    grid-template-columns: 1fr calc(var(--phone-h) * 0.46 + 112px) 1fr;
    align-items: center;
    min-height: 92vh;
    padding: 0;
    text-align: left;
    transition: opacity var(--slow) var(--ease);
  }

  .pocket-text {
    grid-column: 1;
    justify-self: end;
    max-width: 390px;
  }

  .pocket-text p {
    margin-left: 0;
  }

  .chips {
    grid-column: 3;
    flex-direction: column;
    align-items: flex-start;
    justify-self: start;
  }

  /* Only once the script is there to light them up does a feature dim
     while it is not the one on the phone, and its chips wait to slide out
     from behind the phone until it is. */
  .pocket.is-live .pocket-feature:not(.is-on) {
    opacity: 0.3;
  }

  .pocket.is-live .chip {
    transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
  }

  .pocket.is-live .pocket-feature:not(.is-on) .chip {
    opacity: 0;
    transform: translateX(-24px);
  }

  .pocket.is-live .pocket-feature.is-on .chip:nth-child(2) {
    transition-delay: 90ms;
  }

  .pocket.is-live .pocket-feature.is-on .chip:nth-child(3) {
    transition-delay: 180ms;
  }
}

/* ---- Platforms ------------------------------------------------------- */

/* On a phone, a list: the hub first, then five rows with hairlines
   between them, each saying what that device can do today and whether
   its app is out. */
.orbit {
  margin: clamp(48px, 7vh, 72px) auto 0;
}

.orbit-lines {
  display: none;
}

.hub {
  position: relative;
  display: grid;
  place-items: center;
  width: 108px;
  height: 108px;
  margin: 0 auto 28px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 30%, var(--surface-3), var(--night) 72%);
  box-shadow:
    0 0 0 1px var(--line),
    0 0 60px -6px var(--sky-glow);
  transition: box-shadow 900ms var(--ease);
}

.hub-ring {
  position: absolute;
  inset: -8px;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 55%, rgb(134 162 255 / 0.85) 80%, transparent 100%);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), black calc(100% - 1.5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2px), black calc(100% - 1.5px));
  animation: spin 7s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(1turn);
  }
}

.hub-mark {
  width: 34%;
  height: 34%;
  margin-top: -10%;
  fill: none;
  stroke: var(--accent-hi);
  stroke-width: 20;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.hub-label {
  position: absolute;
  bottom: 20%;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 650;
}

.hub.is-lit {
  box-shadow:
    0 0 0 1px var(--accent-line),
    0 0 0 10px rgb(79 123 255 / 0.08),
    0 0 110px 4px rgb(79 123 255 / 0.55);
}

.platform-list {
  max-width: 880px;
  margin: 0 auto;
  padding: 0;
  border-top: 1px solid var(--line);
  list-style: none;
}

.platform {
  display: grid;
  grid-template-columns: 44px 1fr;
  grid-template-areas:
    "icon name"
    "icon text"
    "icon state";
  column-gap: 18px;
  align-items: center;
  padding: 22px 4px;
  border-bottom: 1px solid var(--line);
}

.platform-icon {
  grid-area: icon;
  align-self: start;
  width: 44px;
  height: 44px;
  padding: 10px;
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--accent-hi);
}

.platform h3 {
  grid-area: name;
  margin: 0;
  color: var(--ink);
  font-size: 19px;
  font-weight: 650;
  letter-spacing: -0.015em;
}

.platform p {
  grid-area: text;
  margin: 2px 0 0;
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.5;
}

.platform-state {
  grid-area: state;
  justify-self: start;
  margin-top: 10px;
  padding: 5px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  color: var(--muted);
  font-size: 13px;
  font-weight: 650;
  white-space: nowrap;
}

.platform-state.is-ready {
  border-color: rgb(53 211 153 / 0.35);
  background: rgb(53 211 153 / 0.08);
  color: var(--ok);
}

@media (min-width: 640px) and (max-width: 959px) {
  .platform {
    grid-template-columns: 44px 1fr auto;
    grid-template-areas:
      "icon name state"
      "icon text state";
  }

  .platform-state {
    justify-self: end;
    margin: 0 0 0 16px;
  }
}

/* A wide screen draws it as what it is: one link in the middle and every
   device around it, joined by lines the link runs along. The line ends
   and the cards' centres are the same percentages of the same box, so the
   SVG (stretched to the box, strokes kept 1px) meets the cards exactly
   without anything being measured. When the thread reaches the hub it
   lights, and so do the lines. */
@media (min-width: 960px) {
  .orbit {
    position: relative;
    max-width: 1040px;
    height: 640px;
  }

  .orbit-lines {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
  }

  .orbit-line {
    fill: none;
    stroke: rgb(134 162 255 / 0.3);
    stroke-width: 1.2;
    stroke-dasharray: 2 7;
    vector-effect: non-scaling-stroke;
    animation: orbit-flow 1.4s linear infinite;
    transition: stroke var(--slow) var(--ease);
  }

  .orbit.is-lit .orbit-line {
    stroke: rgb(134 162 255 / 0.75);
  }

  .hub {
    position: absolute;
    z-index: 2;
    left: 50%;
    top: 50%;
    width: 156px;
    height: 156px;
    margin: 0;
    translate: -50% -50%;
  }

  .hub-label {
    font-size: 12.5px;
  }

  .platform-list {
    position: absolute;
    inset: 0;
    max-width: none;
    border: 0;
  }

  .platform {
    position: absolute;
    z-index: 1;
    display: grid;
    grid-template-columns: none;
    grid-template-areas: none;
    justify-items: center;
    gap: 6px;
    width: 236px;
    padding: 18px 16px 16px;
    translate: -50% -50%;
    border: 1px solid var(--line);
    border-radius: 22px;
    background: var(--card-fill), var(--surface);
    box-shadow: var(--shadow);
    text-align: center;
  }

  /* The list's named areas belong to the phone layout; out here each card
     is one centred column, in source order. */
  .platform .platform-icon,
  .platform h3,
  .platform p,
  .platform .platform-state {
    grid-area: auto;
  }

  .platform-icon {
    align-self: center;
    width: 48px;
    height: 48px;
    padding: 12px;
    border-radius: 50%;
    background: var(--surface-3);
  }

  .platform h3 {
    margin-top: 4px;
    font-size: 17px;
  }

  .platform p {
    font-size: 13.5px;
  }

  .platform-state {
    justify-self: center;
    margin-top: 8px;
  }

  .platform-browser {
    left: 50%;
    top: 11%;
  }

  .platform-mac {
    left: 15%;
    top: 30%;
  }

  .platform-windows {
    left: 85%;
    top: 30%;
  }

  .platform-iphone {
    left: 21%;
    top: 81%;
  }

  .platform-android {
    left: 79%;
    top: 81%;
  }
}

@keyframes orbit-flow {
  to {
    stroke-dashoffset: -18;
  }
}

.platforms .home-aside {
  margin-top: 36px;
  text-align: center;
}

/* ---- What the other person can count on ------------------------------ */

/* One paragraph, set large, that lights up a word at a time as it comes
   up the window: home-scene.js wraps each word and numbers it (--i), then
   sets --lit on the paragraph, and each word's brightness is how far --lit
   has passed it. Without the module there are no wrapped words and the
   paragraph is simply lit. */
.lit {
  max-width: 30ch;
  margin: clamp(48px, 7vh, 72px) auto 0;
  color: var(--ink);
  font-size: clamp(1.7rem, 3.5vw, 3.05rem);
  font-weight: 500;
  line-height: 1.24;
  letter-spacing: -0.03em;
  text-align: center;
  text-wrap: balance;
}

.lit .w {
  opacity: clamp(0.16, calc(var(--lit, 9999) - var(--i, 0)), 1);
}

.proof {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px 32px;
  margin: 48px 0 0;
  padding: 0;
  list-style: none;
}

.proof li {
  color: var(--ink-2);
  font-size: 15px;
  font-weight: 600;
}

/* ---- Questions ------------------------------------------------------- */

/* Every answer open. On a wide screen the heading stays put on the left
   while the questions go by on the right. */
.faq-list {
  display: grid;
  column-gap: 56px;
  max-width: 980px;
  margin: clamp(48px, 7vh, 72px) auto 0;
}

@media (min-width: 720px) and (max-width: 959px) {
  .faq-list {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 960px) {
  .faq .wrap {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: 72px;
    align-items: start;
  }

  .faq .title {
    position: sticky;
    top: 140px;
    margin: 0;
    font-size: clamp(2.6rem, 4.6vw, 4.2rem);
    text-align: left;
  }

  .faq-list {
    margin: 0;
  }
}

.faq-item {
  padding: 26px 0 28px;
  border-top: 1px solid var(--line);
}

.faq-item h3 {
  margin: 0;
  color: var(--ink);
  font-size: 18px;
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -0.015em;
}

.faq-item p {
  margin: 8px 0 0;
  color: var(--ink-2);
  font-size: 15.5px;
  line-height: 1.6;
}

.faq-item a {
  color: var(--accent-hi);
  font-weight: 600;
  text-underline-offset: 2px;
}

/* ---- The last screen ------------------------------------------------- */

/* The planet again, as the page ends: the top of a world far wider than
   the window, its rim lit, a dusting of lights near the rim, rising under
   the last heading. Plain CSS this time, and still. */
.finale {
  overflow: clip;
  padding-bottom: clamp(240px, 38vh, 400px);
  text-align: center;
}

.finale-planet {
  position: absolute;
  left: 50%;
  top: calc(100% - clamp(150px, 22vh, 230px));
  width: max(1500px, 170vw);
  aspect-ratio: 1;
  translate: -50% 0;
  border-radius: 50%;
  background:
    radial-gradient(40% 9% at 50% 0%, rgb(79 123 255 / 0.32), transparent 100%),
    var(--night);
  box-shadow:
    0 0 0 1px rgb(134 162 255 / 0.5),
    0 -2px 24px rgb(134 162 255 / 0.4),
    0 -50px 160px -20px rgb(79 123 255 / 0.5);
  pointer-events: none;
}

.finale-planet::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-image: radial-gradient(circle, var(--floor-dot) 1.1px, transparent 1.7px);
  background-size: 18px 18px;
  -webkit-mask-image: radial-gradient(26% 7% at 50% 0%, black, transparent 100%);
  mask-image: radial-gradient(26% 7% at 50% 0%, black, transparent 100%);
}

.finale-planet::after {
  content: "";
  position: absolute;
  inset: 0;
  border-top: 1.5px solid var(--ice);
  border-radius: 50%;
  -webkit-mask-image: linear-gradient(90deg, transparent 34%, black 50%, transparent 66%);
  mask-image: linear-gradient(90deg, transparent 34%, black 50%, transparent 66%);
}

.finale .wrap {
  position: relative;
}

/* Where the thread ends: the button takes the light in, once. */
.finale-go.is-lit {
  animation: ignite 1600ms var(--ease) both;
}

@keyframes ignite {
  0% {
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.22), 0 0 0 0 rgb(134 162 255 / 0.75), var(--glow);
  }
  55% {
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.3), 0 0 0 18px rgb(134 162 255 / 0), var(--glow-strong);
  }
  100% {
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.22), 0 0 0 0 rgb(134 162 255 / 0), var(--glow-strong);
  }
}

/* ---- The foot -------------------------------------------------------- */

/* The name, as large as the window allows, standing on the planet's
   night and fading into it; then the quiet line under every page. */
.home-foot {
  position: relative;
  z-index: 1;
  overflow: clip;
  padding-bottom: calc(env(safe-area-inset-bottom) + 28px);
}

.home-mark {
  margin: 0 0 -0.06em;
  background: linear-gradient(180deg, rgb(134 162 255 / 0.3), rgb(134 162 255 / 0.03) 80%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-size: clamp(5rem, 26vw, 23rem);
  font-weight: 700;
  line-height: 0.86;
  letter-spacing: -0.075em;
  text-align: center;
  user-select: none;
}

.home-foot-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  max-width: calc(1120px + 2 * var(--gutter));
  margin: 0 auto;
  padding: 24px calc(env(safe-area-inset-right) + var(--gutter)) 0
    calc(env(safe-area-inset-left) + var(--gutter));
  border-top: 1px solid var(--line-soft);
}

.home-foot .footnote,
.home-foot .legal-links {
  margin: 0;
}

/* ---- Reduced motion -------------------------------------------------- */

/* The last frame, still. site.css's reduce block already shortens every CSS
   animation to its end state; home-scene.js never starts the scroll story,
   draws the planet once, lays the whole thread down lit, and leaves every
   word at full strength. This makes sure the picture is there even if the
   module never runs. */
@media (prefers-reduced-motion: reduce) {
  .device {
    opacity: 1;
  }
}

/* Windows High Contrast and forced-colors. site.css gives the card, the
   callout, the badge and the secondary button their edges back; the fork
   has two surfaces of its own that the OS palette would flatten, and they
   are listed here rather than there because they exist only on this page.
   The door's tint becomes Canvas like everything else, so the border is the
   only thing left saying where the bigger ask begins — and the `or` rule is
   generated content whose background would be forced to Canvas on Canvas,
   i.e. to nothing, in both the lying-down and the stood-up orientation. */
@media (forced-colors: active) {
  .door {
    border-color: CanvasText;
  }

  .or::before,
  .or::after {
    background: CanvasText;
  }
}

/* Text drawn in a gradient is transparent ink over a painted background,
   and forced colours throw the background away; give it real ink back.
   The thread, the planet and the lines are pictures the OS palette has no
   place for. */
@media (forced-colors: active) {
  .title > .title-2,
  .word-see,
  .home-mark {
    background: none;
    color: CanvasText;
  }

  .thread,
  .hero-canvas,
  .orbit-lines,
  .finale-planet {
    display: none;
  }
}
