:root {
  --bg: #08070A;
  --bg-lift: #0D0C10;
  --ink: #F5F3EF;
  --text: rgba(245, 243, 239, 0.78);
  --text2: rgba(245, 243, 239, 0.60);
  --text3: rgba(245, 243, 239, 0.42);
  --hair: rgba(245, 243, 239, 0.10);
  --hair2: rgba(245, 243, 239, 0.055);
  --fill: rgba(245, 243, 239, 0.035);
  --fill2: rgba(245, 243, 239, 0.07);
  --ember: #AA2D00;
  --ember-lit: #FF5314;
  --on-ember: #FDF6F2;
  --sage: #8FA894;
  --slate: #7C8AA8;

  --sans: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --serif: "Literata", Georgia, "Times New Roman", serif;

  --gutter: clamp(20px, 5vw, 48px);
  --measure: 1120px;
  --radius: 24px;

  /* The masthead floats over the hero instead of sitting above it, so whatever
     the hero lays out has to know how much room the bar takes. Kept as a pair so
     the bar's own padding and the hero's reservation cannot drift apart. */
  --masthead-pad: clamp(22px, 3vw, 34px);
  /* What the hero has to keep clear is the bar's top padding and the button in
     it, plus a little air — not the bar's bottom padding, which is empty room
     the hero is welcome to use. Reserving the whole box costs twice over and
     squeezed the tour bar off the foot of a laptop window. */
  --masthead: calc(var(--masthead-pad) + 42px + 12px);
}

*, *::before, *::after { box-sizing: border-box; }

/* The sideways clip belongs here, not on <body>. A `body { overflow-x: hidden }`
   never clipped anything: with <html> at `visible` the body's overflow is handed
   to the viewport instead, so anything wider than the window still counted as
   scrollable and a phone let you drag the whole page sideways. `clip` on the root
   holds, and unlike `hidden` it makes no scroll container — the pinned reel keeps
   sticking to the window rather than to a box inside it. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-weight: 500; color: var(--ink); }
p { margin: 0; }
a { color: inherit; }
ol, ul { margin: 0; padding: 0; list-style: none; }

.wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 30;
  background: var(--bg-lift);
  color: var(--ink);
  border: 1px solid var(--hair);
  border-radius: 12px;
  padding: 12px 18px;
}
.skip:focus { left: var(--gutter); top: 12px; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── The one light source ─────────────────────────────── */

.glow {
  position: absolute;
  z-index: 0;
  border-radius: 50%;
  pointer-events: none;
  filter: blur(90px);
}

.glow--hero {
  top: -18vw;
  left: 50%;
  width: min(1100px, 130vw);
  aspect-ratio: 1.6;
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(170, 45, 0, 0.55), rgba(170, 45, 0, 0.14) 55%, transparent 72%);
}

.glow--end {
  bottom: -28vw;
  left: 50%;
  width: min(1400px, 160vw);
  aspect-ratio: 1.9;
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(170, 45, 0, 0.50), rgba(170, 45, 0, 0.12) 55%, transparent 72%);
}

.dust {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(1.5px 1.5px at 12% 22%, rgba(245, 243, 239, 0.5), transparent),
    radial-gradient(1.5px 1.5px at 84% 14%, rgba(255, 83, 20, 0.6), transparent),
    radial-gradient(1.5px 1.5px at 68% 62%, rgba(245, 243, 239, 0.35), transparent),
    radial-gradient(1.5px 1.5px at 26% 76%, rgba(255, 83, 20, 0.45), transparent),
    radial-gradient(1.5px 1.5px at 92% 48%, rgba(245, 243, 239, 0.3), transparent);
}

/* ── Type ─────────────────────────────────────────────── */

.display {
  font-size: clamp(31px, 4.4vw, 56px);
  line-height: 1.06;
  letter-spacing: -0.035em;
  /* background-clip: text paints only inside the box, so a descender hanging
     below the last line loses its fill and disappears. The padding gives the
     gradient somewhere to reach; the margins below already absorb it. */
  padding-bottom: 0.14em;
  background: linear-gradient(180deg, #FFFFFF 18%, rgba(245, 243, 239, 0.62) 96%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-wrap: balance;
}

.display--section { font-size: clamp(30px, 4.4vw, 54px); text-wrap: balance; }

.kicker {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: clamp(13px, 1.1vw, 15px);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text);
}
.lede {
  font-size: clamp(17px, 1.45vw, 20px);
  color: var(--text);
  line-height: 1.65;
  text-wrap: pretty;
}

/* ── Masthead ─────────────────────────────────────────── */

.masthead {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  padding-block: var(--masthead-pad);
}

.masthead .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.wordmark {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}

.ghost {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: 9px 18px;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.ghost:hover { background: var(--fill2); border-color: var(--text3); }

/* ── Hero ─────────────────────────────────────────────── */

/* The first screen owns the window, so on a tall monitor the whole thing sits
   in the middle rather than clinging to the top with a field of black beneath. */
.hero {
  position: relative;
  /* The hero's own glow is 130vw across, so like the closing one it has to be
     held inside the section that owns it. `clip` rather than `hidden`: this
     element is the pinned stage, and `hidden` would make it a scroll container. */
  overflow: clip;
  text-align: center;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  /* Centred while it fits, and from the top once it does not. Plain `center`
     splits an overflow evenly, which on a short phone pushed the screen up
     under the masthead — the wordmark and the button ended up on the phone. */
  align-content: center;
  align-content: safe center;
  /* Only the top has a bar above it to clear; the foot keeps the room it had,
     so a window that used to fit the hero still fits it. */
  padding-block: clamp(52px, 6vh, 92px);
  padding-top: max(clamp(52px, 6vh, 92px), var(--masthead));
}

/* The headline sits over the tail of the screen, so it gets its own ground:
   a scrim that starts at nothing and reaches the page colour by the time the
   first line begins. Above the phone, below the words. */
.hero__copy {
  position: relative;
  z-index: 2;
  padding-bottom: 0;
}

.hero__copy::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 50%;
  top: clamp(-130px, -9vh, -68px);
  width: 100vw;
  height: clamp(180px, 20vh, 280px);
  transform: translateX(-50%);
  background: linear-gradient(to bottom, rgba(8, 7, 10, 0), rgba(8, 7, 10, 0.55) 42%, rgba(8, 7, 10, 0.92) 72%, var(--bg) 100%);
  pointer-events: none;
}

.points-line {
  margin-top: clamp(14px, 1.7vw, 20px);
  margin-inline: auto;
  max-width: 44rem;
  font-size: clamp(12px, 1vw, 13.5px);
  line-height: 1.6;
  color: var(--text2);
  text-wrap: pretty;
}

.hero .display { margin-bottom: 10px; }

.hero__sub {
  font-size: clamp(15px, 1.15vw, 17px);
  color: var(--text2);
  line-height: 1.55;
  max-width: 44rem;
  margin-inline: auto;
  text-wrap: pretty;
}

.hero__stage {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  padding-top: clamp(8px, 2vw, 28px);
  margin-bottom: clamp(-100px, -6vw, -30px);
}

.hero__masked {
  -webkit-mask-image: linear-gradient(to bottom, #000 90%, rgba(0, 0, 0, 0.3) 96%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 90%, rgba(0, 0, 0, 0.3) 96%, transparent 100%);
}

/* ── Waitlist ─────────────────────────────────────────── */

.signup {
  margin: clamp(30px, 4vw, 44px) auto 0;
  max-width: 30rem;
}

.signup__row {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--fill);
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: 6px 6px 6px 8px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.signup__row:focus-within {
  border-color: rgba(255, 83, 20, 0.7);
  box-shadow: 0 0 0 4px rgba(170, 45, 0, 0.18);
}

.signup input[type="email"] {
  flex: 1 1 8rem;
  min-width: 0;
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  background: none;
  border: 0;
  padding: 11px 12px;
}
.signup input[type="email"]::placeholder { color: var(--text3); }
.signup input[type="email"]:focus { outline: none; }

.signup button {
  flex: none;
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  color: var(--on-ember);
  background: var(--ember);
  border: 0;
  border-radius: 999px;
  padding: 12px 22px;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 6px 26px rgba(170, 45, 0, 0.45);
  transition: transform 0.08s ease, box-shadow 0.15s ease;
}
.signup button:hover { box-shadow: 0 8px 34px rgba(170, 45, 0, 0.6); }
.signup button:active { transform: translateY(1px); }
.signup button:disabled { opacity: 0.6; cursor: default; }
.signup button:focus-visible { outline: 2px solid var(--ember-lit); outline-offset: 3px; }

/* Side by side on a phone the button wins and the field is left about 150px —
   too narrow to show a whole address, so the placeholder read "you@example.cor"
   and a typed address scrolled out of sight. Below this they stack, and the
   pill becomes a rounded box because a tall pill reads as a mistake. */
@media (max-width: 480px) {
  .signup__row {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    border-radius: 20px;
    padding: 8px;
  }
  /* `flex: 1 1 8rem` sized the field along the row. Stacked, the main axis is
     the other one, and that 8rem became a 128px-tall input. */
  .signup input[type="email"] { flex: none; text-align: center; padding: 13px 12px; }
  .signup button { width: 100%; padding: 14px 22px; }
}

.signup__note { margin-top: 14px; font-size: 14px; color: var(--text2); }

.signup__status { margin-top: 10px; font-size: 15px; font-weight: 500; color: var(--ink); }
.signup__status:empty { display: none; }
.signup__status[data-state="error"] { color: var(--ember-lit); }

.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.section__head { max-width: 34rem; }
.section__head .kicker { margin-bottom: 22px; }
.section__head .display { margin-bottom: 16px; }

section[id] { scroll-margin-top: 28px; }

/* ── The tour ─────────────────────────────────────────── */

.tour {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: clamp(16px, 1.9vw, 22px);
  padding: 5px;
  gap: 2px;
  border: 1px solid var(--hair);
  border-radius: 999px;
  background: var(--fill);
}

.tour a {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text2);
  text-decoration: none;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.tour a { white-space: nowrap; }

.tour a:hover { color: var(--ink); background: var(--fill2); }
.tour a:hover svg { color: var(--ember-lit); }
.tour a:focus-visible { outline: 2px solid var(--ember-lit); outline-offset: 2px; }
.tour svg { flex: none; transition: color 0.15s ease; }

/* One row on a phone. The four words are the map of the app; wrapping them
   into a block turns a bar into a menu. */
@media (max-width: 720px) {
  .tour { padding: 4px; gap: 2px; }
  .tour a { gap: 7px; padding: 10px 13px; font-size: 13px; }
  .tour svg { width: 16px; height: 16px; }
}

/* Below this the icons are 14px of grey and the labels are down to 11.5 to sit
   beside them. Dropping the icons buys every word back its size and turns the
   pill into a segmented control across the column. */
@media (max-width: 480px) {
  .tour {
    display: flex;
    width: 100%;
    padding: 4px;
    gap: 2px;
  }

  .tour a {
    flex: 1;
    justify-content: center;
    padding: 11px 4px;
    font-size: 13.5px;
  }

  .tour svg { display: none; }
}

/* ── A section and the screen it describes ────────────── */

/* Words on the left, the screen they describe on the right, the same way in
   every section. A centred heading over a left-hand column reads as two
   different pages. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
}

.split__art { justify-self: end; }

@media (max-width: 980px) {
  .split { grid-template-columns: minmax(0, 1fr); }
  .split__art { justify-self: center; }
}

.showcase {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(28px, 4vw, 60px);
  align-items: center;
  margin-top: clamp(40px, 5vw, 64px);
}

.showcase > .card,
.showcase > .spaces__grid { margin-top: 0; }

/* Beside a phone the card has half the room, so the two halves stack and the
   rule between them turns from a column divider into a horizontal one. */
.split .swap { grid-template-columns: minmax(0, 1fr); gap: 0; }

.split .swap__side--out {
  border-left: 0;
  border-top: 1px solid var(--hair);
  padding-left: 0;
  padding-top: 24px;
  margin-top: 24px;
}

.showcase--flip > :first-child { order: 2; }
.showcase--solo { grid-template-columns: minmax(0, 1fr); justify-items: center; }

@media (max-width: 980px) {
  .showcase { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .showcase--flip > :first-child { order: 0; }
}

.calendar { position: relative; padding-bottom: clamp(84px, 12vw, 160px); }

/* ── Notes ────────────────────────────────────────────── */

.notes { position: relative; padding-bottom: clamp(84px, 12vw, 160px); }

.swap {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(24px, 3vw, 48px);
}

.swap__side--out {
  border-left: 1px solid var(--hair);
  padding-left: clamp(24px, 3vw, 48px);
}

.swap__raw {
  font-size: clamp(17px, 1.4vw, 19px);
  line-height: 1.6;
  color: var(--text2);
  margin-top: 14px;
}

.swap__stamp {
  font-size: 12px;
  font-weight: 600;
  color: var(--text2);
  margin-top: 14px;
}

.swap__title {
  font-family: var(--serif);
  font-size: clamp(20px, 1.9vw, 24px);
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink);
  margin-top: 8px;
}

.swap__summary {
  font-size: 16.5px;
  line-height: 1.5;
  color: var(--text);
  margin-top: 10px;
}

.swap__points {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text2);
  margin-top: 22px;
}

.swap__list { margin-top: 10px; }

.swap__list li {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  gap: 8px;
  font-size: 16px;
  line-height: 1.45;
  color: var(--text);
  padding-bottom: 10px;
}

.swap__list li::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--ember-lit);
  margin: 8px 0 0 4px;
}

@media (max-width: 720px) {
  .swap__side--out { border-left: 0; border-top: 1px solid var(--hair); padding-left: 0; padding-top: 24px; }
}

/* ── The thread ───────────────────────────────────────── */

.thread { position: relative; padding-bottom: clamp(84px, 12vw, 160px); }


.rail {
  margin-top: clamp(48px, 6vw, 76px);
  border: 1px solid var(--hair);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--fill), rgba(245, 243, 239, 0.012));
  padding: clamp(26px, 3.4vw, 44px);
}

.rail__name {
  font-family: var(--serif);
  font-style: normal;
  font-size: clamp(21px, 2.3vw, 30px);
  line-height: 1.3;
  color: var(--ink);
  max-width: 26ch;
}

.rail__track {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  margin-top: clamp(34px, 4vw, 52px);
}

.node {
  position: relative;
  padding: 30px 20px 0 0;
}

.node::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--hair);
}

.node::before {
  content: "";
  position: absolute;
  top: -4px;
  left: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--text3);
  z-index: 1;
}

.node--now::before {
  background: var(--ember-lit);
  box-shadow: 0 0 0 4px rgba(170, 45, 0, 0.22), 0 0 18px rgba(255, 83, 20, 0.9);
}

.node--now::after { background: linear-gradient(90deg, var(--ember), var(--hair)); }

.node time {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text2);
  margin-bottom: 10px;
}

.node--now time { color: var(--ember-lit); }

.node p { font-size: 15px; line-height: 1.5; color: var(--text); }

.node--now p { color: var(--ink); }

.rail__foot {
  margin-top: clamp(30px, 3.4vw, 44px);
  padding-top: 22px;
  border-top: 1px solid var(--hair2);
  font-size: 15.5px;
  color: var(--text2);
  max-width: 52rem;
  text-wrap: pretty;
}

/* Five columns share about 60px each on a phone, which is not a column but a
   stack of broken words — the dates and the notes ran into each other. The rail
   turns and reads downwards instead, which is the same line of thinking, only
   the way a phone reads it: the track becomes the spine, each note hangs off it. */
@media (max-width: 720px) {
  .rail__track {
    grid-template-columns: 1fr;
    margin-left: 5px;
  }

  .node {
    padding: 0 0 26px 26px;
  }

  .node:last-child { padding-bottom: 0; }

  /* The line that ran across the top of every node now runs down its left. */
  .node::after {
    inset: 0 auto 0 0;
    width: 1px;
    height: auto;
  }

  .node:last-child::after { height: 10px; }

  .node::before {
    top: 2px;
    left: -4px;
  }

  .node--now::after { background: linear-gradient(180deg, var(--ember), var(--hair)); }

  .node time { margin-bottom: 4px; }
}

/* ── Actions ──────────────────────────────────────────── */

.acts { position: relative; padding-bottom: clamp(84px, 12vw, 160px); }


.card {
  margin-top: clamp(44px, 5vw, 68px);
  border: 1px solid var(--hair);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--fill), rgba(245, 243, 239, 0.012));
  padding: clamp(22px, 3vw, 38px);
}

.card__label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text2);
  padding-bottom: 6px;
}

/* ── Spaces ───────────────────────────────────────────── */

.spaces { position: relative; padding-bottom: clamp(84px, 12vw, 160px); }


.spaces__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: clamp(18px, 2vw, 28px);
  margin-top: clamp(44px, 5vw, 68px);
}

/* ── Closing ──────────────────────────────────────────── */

.closing {
  position: relative;
  overflow: hidden;
  text-align: center;
  border-top: 1px solid var(--hair);
}

.closing .wrap { padding-block: clamp(80px, 11vw, 150px) clamp(96px, 14vw, 180px); }

.closing .display { margin-bottom: 14px; }

.trust {
  margin-top: 22px;
  margin-inline: auto;
  max-width: 38rem;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text2);
  text-wrap: pretty;
}

.closing p {
  font-size: clamp(17px, 1.4vw, 19px);
  color: var(--text);
  max-width: 44rem;
  margin-inline: auto;
  text-wrap: pretty;
}

/* ── Footer ───────────────────────────────────────────── */

.foot {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--hair);
  font-size: 14px;
  color: var(--text2);
}

.foot .wrap {
  padding-block: 32px 44px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px 30px;
  align-items: baseline;
  justify-content: space-between;
}

.foot a { color: var(--text2); text-decoration: none; }
.foot a:hover { color: var(--ink); }

.foot__links { display: flex; gap: 24px; flex-wrap: wrap; }


@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}

/* ── Legal pages ──────────────────────────────────────── */

.prose { max-width: 66ch; padding-block: clamp(28px, 4vw, 48px) 96px; }
.prose h1 { font-size: clamp(32px, 4.4vw, 46px); letter-spacing: -0.03em; margin-bottom: 12px; }
.prose h2 { font-size: 22px; margin-top: 44px; margin-bottom: 12px; }
.prose p, .prose li { color: var(--text); line-height: 1.7; }
.prose p + p { margin-top: 16px; }
.prose .updated { color: var(--text2); font-size: 15px; }
.prose a { color: var(--ember-lit); text-underline-offset: 3px; }

/* ── Arrival ──────────────────────────────────────────── */

/* reveal.js puts `anim` on <html> before the first paint and takes it off
   nothing — so if the script never runs, none of these rules match and every
   section is simply there. */
.anim .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.8s ease,
    transform 0.9s cubic-bezier(0.22, 0.68, 0.3, 1);
  transition-delay: var(--in, 0s);
}

.anim .reveal.shown {
  opacity: 1;
  transform: none;
}

/* The screen rises out of the shadow at the foot of its own frame: the crop
   that hides its lower half is also where it comes in from. */
.anim .stage .device {
  opacity: 0;
  transform: translateY(96px);
  transition:
    opacity 0.9s ease 0.1s,
    transform 1.05s cubic-bezier(0.22, 0.68, 0.3, 1) 0.1s;
}

.anim .stage.shown .device {
  opacity: 1;
  transform: none;
}

/* Asked for less motion, the page keeps its shape and loses its movement: the
   sections are simply there, and the reel still steps but swaps rather than
   slides. */
@media (prefers-reduced-motion: reduce) {
  .anim .reveal,
  .anim .stage .device {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .anim .pages .page,
  .anim .says .say {
    transform: none;
    transition: none;
  }

  .anim .pages .page:not(.is-on),
  .anim .says .say:not(.is-on) { visibility: hidden; }
}

/* The first screen is already in view when the page opens, so it arrives on
   load rather than on scroll — and it arrives as one thing. The wordmark and
   the phone are too large to slide and only lift their light; the words come
   up behind them a moment later. */
.anim .masthead.reveal,
.anim .reel__states.reveal {
  transform: none;
  transition: opacity 1.2s ease;
}

.anim .hero__bar.reveal { --in: 0.32s; }

/* ── The reel ─────────────────────────────────────────── */

/* One screen, five states. The stage is pinned for the length of the section
   and the marks under it are the scroll each state costs — one viewport per
   step, plus a last one with no name on it so the final step is held before
   the stage leaves.
   Without `anim` none of this applies: the stage is an ordinary tall block and
   the five states read down the page in order, which is the page this replaced. */
.anim .reel__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
}

.anim .mark {
  height: 100vh;
  height: 100svh;
}

/* A state is a screen and the words about it, kept together: stacked into one
   grid cell here, and read one after another down the page when the reel is
   off. Splitting them into a stack of screens and a stack of paragraphs left
   the fallback with five phones followed by five descriptions. */
.anim .reel__states { display: grid; }

/* The phone is one object that stays where it is. What changes is what is on
   its screen, and it changes the way a page does on the device: one slides out
   while the next slides in, a full screen's width, clipped by the bezel. No
   fade — a page that dissolves is a slideshow, not a phone. */
.anim .pages { position: relative; }

.anim .pages .page {
  position: absolute;
  inset: 0;
  display: flex;
  visibility: hidden;
  transform: translateX(100%);
  transition:
    transform 0.44s cubic-bezier(0.32, 0.72, 0, 1),
    visibility 0s linear 0.44s;
}

/* Where a page waits says which way the reel is going: already read is off to
   the left, still to come is off to the right, in the order the bar lists them.
   So a swipe towards Actions and a scroll towards Actions move it the same way. */
.anim .pages .page.is-before { transform: translateX(-100%); }

.anim .pages .page.is-on {
  visibility: visible;
  transform: none;
  transition:
    transform 0.44s cubic-bezier(0.32, 0.72, 0, 1),
    visibility 0s;
}

/* The sentence goes with its screen. Fading one paragraph through another put
   two headlines and two paragraphs on top of each other for half a second —
   on a phone, where the words are five lines deep, that is the whole viewport
   turning to mud. So it pages too: same direction, same moment, clipped by its
   own column instead of by the bezel. */
.anim .says {
  position: relative;
  overflow: hidden;
}

.anim .says .say {
  visibility: hidden;
  transform: translateX(100%);
  transition:
    transform 0.44s cubic-bezier(0.32, 0.72, 0, 1),
    visibility 0s linear 0.44s;
}

.anim .says .say.is-before { transform: translateX(-100%); }

.anim .says .say.is-on {
  visibility: visible;
  transform: none;
  transition:
    transform 0.44s cubic-bezier(0.32, 0.72, 0, 1),
    visibility 0s;
}

/* The bar is a map of the app and now also a position in it. */
.tour a.is-on {
  color: var(--ink);
  background: var(--fill2);
}

.tour a.is-on svg { color: var(--ember-lit); }

/* Every state occupies one grid cell, so each stack is as tall as its tallest
   member and nothing below it moves when the state changes. */
.says { display: grid; }
.says .say { grid-area: 1 / 1; }

/* ── What you said, what came back ────────────────────── */

.said { position: relative; padding-block: clamp(84px, 12vw, 160px) clamp(84px, 12vw, 160px); }
.said .card { margin-top: 0; }

/* A laptop window is not a tall window. The screen, five descriptions, the bar
   and the footnote all have to sit inside one viewport, and the screen is the
   only piece with real give in it. */
@media (max-width: 560px) {
  .hero__masked {
    -webkit-mask-image: linear-gradient(to bottom, #000 74%, rgba(0, 0, 0, 0.28) 90%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 74%, rgba(0, 0, 0, 0.28) 90%, transparent 100%);
  }
}

@media (max-height: 830px) {
  .device--hero {
    height: clamp(240px, 46vh, 430px);
    height: clamp(240px, 46svh, 430px);
  }
  .hero .display { font-size: clamp(27px, 3.4vw, 42px); }
  .hero__sub { font-size: 14.5px; line-height: 1.5; }
  /* Still never less than the bar overhead — a short window is exactly where
     the hero would otherwise ride up under it. */
  .hero {
    padding-block: clamp(44px, 5.2vh, 78px);
    padding-top: max(clamp(44px, 5.2vh, 78px), var(--masthead));
  }
}

@media (max-height: 690px) {
  .device--hero {
    height: clamp(210px, 40vh, 330px);
    height: clamp(210px, 40svh, 330px);
  }
  .hero .display { font-size: clamp(24px, 3vw, 34px); }
}

/* A phone held sideways has width to spare and no height at all: stacked, the
   screen alone eats the window and the bar falls off the bottom. So the hero
   turns — screen beside the words, the way the calendar section already reads —
   which is the one arrangement that fits a short wide window. */
@media (orientation: landscape) and (max-height: 620px) and (min-width: 640px) {
  .hero {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
    column-gap: clamp(12px, 2.5vw, 36px);
    align-items: center;
    text-align: left;
  }

  .hero__stage {
    grid-column: 1;
    grid-row: 1 / span 2;
    padding-top: 0;
    margin-bottom: 0;
  }

  .hero__copy { grid-column: 2; grid-row: 1; }
  .hero__bar { grid-column: 2; grid-row: 2; }

  /* The scrim exists to hand the headline its own ground when it sits over the
     tail of the screen. Side by side, it never does. */
  .hero__copy::before { display: none; }

  .hero__sub, .points-line { margin-inline: 0; }
  /* The bar now shares a column with the words rather than the whole window,
     and four names with their icons wrap onto a second row it cannot afford.
     The names alone fit one row. */
  .tour { justify-content: flex-start; }
  .tour a svg { display: none; }
  .tour a { gap: 0; }

  /* The screen's own size for this case is set in app.css, which loads second
     and would otherwise win. */
}

/* Below this there is no room left to give: the screen is already at its
   smallest, so the bar, the words and the footnote are what tighten. Reached by
   an old small phone, and by any phone held sideways. */
@media (max-height: 620px) {
  :root { --masthead-pad: 12px; }
  .hero__sub { font-size: 13.5px; line-height: 1.45; }
  .points-line { font-size: 11.5px; line-height: 1.5; margin-top: 10px; }
  .tour a { padding: 7px 12px; font-size: 14px; }
  /* The screen already fades into the words here, so it can sit further under
     them — cheaper than taking another point off the type. */
  .hero__stage { padding-top: 0; margin-bottom: -52px; }
}
