/*
 * Beady, the site.
 *
 * The tokens below are lifted from the app's own `@theme` block
 * (`src/app/globals.css` in the Beady repo) and the rules from
 * `DESIGN_SYSTEM.md`. Four of them govern everything here:
 *
 *   1. Colour never argues. Bright colour is a verdict, a signal that the app
 *      wants you, or the inside of an illustration. Never decoration, never a
 *      link.
 *   2. Big type, light weight. Display sizes run at 400; weight is for small
 *      text, and scale does the shouting.
 *   3. A ring, never a shadow. There is not one drop shadow on this page.
 *   4. The contract keeps its serif. Anything quoted from a signed document is
 *      Newsreader, and nothing else ever is.
 */

:root {
  color-scheme: light;

  --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
  --font-serif: "Newsreader", ui-serif, Georgia, serif;

  /* Ink */
  --color-ink: #121212;
  --color-ink-body: #474645;
  --color-ink-muted: #6e6d6b;
  --color-ink-faint: #b4b1ac;

  /* Surface: three steps and the edge between them */
  --color-canvas: #fbfaf9;
  --color-surface: #ffffff;
  --color-sunk: #f2f0ed;
  --color-ring: #e6e2dc;

  /* Verdict. All three carry an ink label, so none needs a darkened cousin */
  --color-covered: #00ca48;
  --color-unsettled: #ffbb26;
  --color-extra: #ff3e00;

  /* Ember carries links, and ember as text is not ember as a fill */
  --color-ember-text: #cc2e00;
  --color-ember-text-hover: #a52500;

  /* Signal: the app asking for you */
  --color-signal: #ff58ae;

  /* The evidence band */
  --color-honey-pale: #fff3d6;

  /* Drawing: inside illustrations and nowhere else. These were used before
     they were declared, so the honey in the ink band rendered as inherited
     white. */
  --color-draw-sky: #64c6ff;
  --color-draw-honey: #ffbb26;
  --color-draw-mint: #00ca48;
  --color-draw-peach: #ff8a5b;

  /* Note paper, from the board's own palette */
  --paper-fill: #ede6d8;
  --paper-edge: #dbd1be;

  --radius-badge: 6px;
  --radius-control: 8px;
  --radius-card: 10px;
  --radius-window: 14px;
  --radius-block: 16px;
  --radius-button: 32px;

  --ease-out-soft: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.5, 1);
  /* A card put down on a desk: fast off the hand, a little past the mark, and
     settled. Gentler than --ease-spring, which is for things that pop. */
  --ease-deal: cubic-bezier(0.18, 1.1, 0.28, 1);
  --ease-in-out-soft: cubic-bezier(0.65, 0, 0.35, 1);
  --motion-fast: 140ms;
  --motion-base: 240ms;
  --motion-slow: 420ms;
}

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

html,
body {
  margin: 0;
  background-color: var(--color-canvas);
  color: var(--color-ink);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

h1,
p,
dl,
dd,
dt {
  margin: 0;
}

:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 2px;
  border-radius: 4px;
}

/* The only elevation in the system. */
.ring {
  box-shadow: 0 0 0 1px var(--color-ring);
}

/* ---------------------------------------------------------------- the bar */

.bar {
  position: sticky;
  top: 0;
  z-index: 30;
  background-color: color-mix(in srgb, var(--color-canvas) 86%, transparent);
  backdrop-filter: blur(8px);
}

.bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  max-width: 1320px;
  height: 60px;
  margin: 0 auto;
  padding: 0 32px;
}

.bar-name {
  display: flex;
  align-items: center;
  gap: 10px;
}

.mark {
  width: 34px;
  aspect-ratio: 1020 / 1140;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  cursor: pointer;
}

.wordmark {
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.2px;
}

.bar-links {
  display: flex;
  align-items: center;
  gap: 22px;
}

.link {
  color: var(--color-ember-text);
  font-size: 15px;
  text-decoration: none;
}

.link:hover {
  color: var(--color-ember-text-hover);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.link-button {
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
}

/* --------------------------------------------------------- the statement */

/* Tightened by about a hundred pixels so the window under it is visibly a
   window on a 779 tall viewport, not a strip of title bar. The savings are
   taken out of the padding and the gaps rather than out of the headline,
   which only came down from 72 to 68. */
.hero {
  max-width: 1320px;
  margin: 0 auto;
  padding: 10px 24px 0;
}

.statement {
  position: relative;
  padding: 16px 0 16px;
  text-align: center;
}

/* The client's question, above the answer to it. Sentence case in the body
   face rather than a letterspaced tag: an uppercase eyebrow would be the one
   thing on this page that looks like every other landing page. */
.kicker {
  margin: 0 0 12px;
  color: var(--color-ink-muted);
  font-size: 17px;
  letter-spacing: -0.01em;
}

.display {
  max-width: 17ch;
  margin: 0 auto;
  font-size: clamp(42px, 5.6vw, 68px);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

/* 62ch at 18px is a hair over 60 characters of measure, which is where a
   centred paragraph under a display line stops being a block and starts
   being a sentence. */
.lede {
  max-width: 62ch;
  margin: 16px auto 0;
  color: var(--color-ink-body);
  font-size: 17px;
  line-height: 1.55;
  text-wrap: pretty;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 22px;
}

.terms {
  margin-top: 16px;
  color: var(--color-ink-muted);
  font-size: 14px;
  letter-spacing: 0.01em;
}

/* Button: radius 32, padding 15/28, label 17/500. One primary per screen, and
   on this page that is Download for Mac. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 15px 28px;
  border-radius: var(--radius-button);
  font-size: 17px;
  font-weight: 500;
  text-decoration: none;
  transition:
    transform var(--motion-fast) var(--ease-out-soft),
    background-color var(--motion-fast) var(--ease-out-soft);
}

.button:active {
  transform: translateY(1px);
}

.button-sm {
  padding: 9px 18px;
  font-size: 15px;
}

.button-primary {
  background-color: var(--color-ink);
  color: var(--color-surface);
}

.button-primary:hover {
  background-color: #2b2a29;
}

.button-secondary {
  background-color: var(--color-sunk);
  color: var(--color-ink-body);
}

.button-secondary:hover {
  background-color: #e9e6e1;
}

/* The drawn objects scattered around the statement. They are illustration,
   which is the one place this system allows a bright fill that is not a
   verdict, and they are drawn to its rule: 5px ink outline, flat fill, round
   joins, no gradient and no shadow. */
.scatter {
  position: absolute;
  inset: 0;
  pointer-events: none;

  /* Parallax, three depths. The script writes these on scroll and leaves them
     at zero under a reduced-motion setting. They are applied through `top` and
     `bottom` rather than a transform because `translate` already belongs to
     the drift animation and `transform` to each object's own rotation, and a
     third writer on either of those properties simply wins the fight. */
  --p-near: 0px;
  --p-mid: 0px;
  --p-far: 0px;
}

.float {
  position: absolute;
  animation: drift 9s ease-in-out infinite;
  will-change: top;
}

.float-page {
  top: calc(4px + var(--p-near));
  left: 3%;
  width: 92px;
  transform: rotate(-8deg);
  animation-delay: -0.4s;
}

.float-bubble {
  top: calc(212px + var(--p-far));
  left: 8%;
  width: 96px;
  transform: rotate(6deg);
  animation-delay: -3.1s;
}

/* The clip used to hang below the statement so it overlapped the first bento
   tile by the same amount at every width. The demo took that tile's place and
   the "Try it" line sits where the clip was, so it has come up into the
   statement's own bottom corner, beside a facts line that is centred and never
   reaches it. The spark below still hangs, because nothing is under it. */
.float-clip {
  bottom: calc(18px - var(--p-mid));
  left: 2%;
  width: 54px;
  transform: rotate(-14deg);
  animation-delay: -5.6s;
}

.float-note {
  top: calc(16px + var(--p-mid));
  right: 4%;
  width: 100px;
  transform: rotate(7deg);
  animation-delay: -1.9s;
}

.float-tick {
  top: calc(198px + var(--p-near));
  right: 9%;
  width: 72px;
  transform: rotate(-5deg);
  animation-delay: -4.4s;
}

.float-spark {
  bottom: calc(-8px - var(--p-far));
  right: 3%;
  width: 62px;
  transform: rotate(10deg);
  animation-delay: -6.8s;
}

/* A laptop at 1024 still has room for them beside a 54ch measure, so they
   shrink there rather than leaving. Below 900 the copy wants the whole width
   and an object beside it becomes an object behind it. */
@media (min-width: 900px) and (max-width: 1099px) {
  .float {
    scale: 0.78;
  }
}

@media (max-width: 899px) {
  .scatter {
    display: none;
  }

  .statement {
    padding: 34px 0 44px;
  }
}

/* -------------------------------------------------------------- the bento */

.band-bento {
  padding-top: 84px;
}

.bento {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 14px;
}

.tile {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 26px;
  border-radius: var(--radius-block);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
}

/* Seven tiles across six columns. The board used to be the eighth and the tall
   one; it is now its own section above, because a live demo folded into a
   corner of a grid is a demo somebody has to find. */
@media (min-width: 1100px) {
  .tile-scope {
    grid-column: 1 / 4;
    grid-row: 1;
  }
  .tile-evidence {
    grid-column: 4 / 7;
    grid-row: 1;
  }
  .tile-timeline {
    grid-column: 1 / 3;
    grid-row: 2;
  }
  .tile-drop {
    grid-column: 3 / 5;
    grid-row: 2;
  }
  .tile-note {
    grid-column: 5 / 7;
    grid-row: 2;
  }
  .tile-reply {
    grid-column: 1 / 5;
    grid-row: 3;
  }
  .tile-reads {
    grid-column: 5 / 7;
    grid-row: 3;
  }
}

@media (min-width: 720px) and (max-width: 1099px) {
  .bento {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .tile-scope,
  .tile-evidence,
  .tile-reply {
    grid-column: 1 / -1;
  }
}

@media (max-width: 719px) {
  .bento {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* The evidence size is the system's own 23, which is right in a panel the
   width of a window and too big inside a tile at half that. */
@media (max-width: 1099px) {
  .evidence-still .evidence-quote {
    font-size: 19px;
  }
}

.tile-title {
  margin: 0;
  font-size: 22px;
  font-weight: 400;
  line-height: 1.18;
  letter-spacing: -0.32px;
  text-wrap: balance;
}

.tile-say {
  max-width: 48ch;
  color: var(--color-ink-body);
  font-size: 15px;
  line-height: 1.55;
  text-wrap: pretty;
}

.tile-say em {
  font-style: normal;
  color: var(--color-ink);
}

.eyebrow,
.evidence-label {
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------- the art

   Each tile carries a piece of the real interface rather than an icon, and
   the tile crops it. A fragment that runs off its own edge reads as part of
   something larger; the same fragment centred with room around it reads as a
   diagram of it. */

.art {
  position: relative;
  overflow: hidden;
  height: 200px;
  padding: 18px 20px;
  border-radius: var(--radius-card);
  background-color: var(--color-canvas);
}

/* Scope: the clauses it pulled out, the third one cut by the tile. */
.art-scope {
  padding-bottom: 0;
}

.clause {
  padding: 12px 0;
  border-bottom: 1px solid var(--color-ring);
}

.clause:first-child {
  padding-top: 0;
}

.clause .type {
  display: inline-block;
  margin-bottom: 7px;
  padding: 2px 8px;
  border-radius: var(--radius-badge);
  background-color: var(--color-sunk);
  color: var(--color-ink-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.clause p {
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.4;
}

/* Evidence: the band runs off the right edge of its tile. */
.art-evidence {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.art-evidence .evidence-still {
  margin-right: -40px;
}

/* Timeline: two bands, and the one row that is still a question. */
.art-timeline {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-bottom: 0;
}

.tl-band {
  color: var(--color-ink-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.tl-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
}

.tl-name {
  font-size: 14px;
  font-weight: 500;
}

.tl-meta {
  color: var(--color-ink-muted);
  font-size: 12px;
}

.tl-date {
  color: var(--color-ink-body);
  font-size: 13px;
  white-space: nowrap;
}

/* Signal, because a row with no date is the app asking for you. It is not a
   verdict and it may never take a verdict colour. */
.tl-set {
  padding: 3px 9px;
  border-radius: var(--radius-badge);
  background-color: var(--color-signal);
  color: var(--color-ink);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

/* A dropped screenshot, cropped by its tile the way the board crops it. */
.art-drop {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.shot {
  display: flex;
  flex-direction: column;
  gap: 7px;
  width: 128%;
  margin-right: -28%;
  padding: 14px;
  border-radius: var(--radius-card);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
}

.shot-bubble {
  height: 26px;
  border-radius: 12px;
  background-color: var(--color-sunk);
}

.shot-them {
  width: 64%;
  border-bottom-left-radius: 4px;
}

.shot-them.short {
  width: 42%;
}

.shot-me {
  width: 52%;
  align-self: flex-end;
  border-radius: 12px;
  border-bottom-right-radius: 4px;
  background-color: #dce9f5;
}

.shot-read {
  color: var(--color-ink-muted);
  font-size: 13px;
  line-height: 1.4;
}

/* A note with the sticky bar over it. */
.art-note {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.note-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px;
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
}

.bar-swatch {
  width: 18px;
  height: 18px;
  border-radius: 999px;
  background-color: var(--paper-fill);
  box-shadow: 0 0 0 1px var(--paper-edge);
}

.bar-item {
  padding: 0 4px;
  color: var(--color-ink-body);
  font-size: 13px;
  font-weight: 600;
}

.bar-check {
  padding: 4px 10px;
  border-radius: var(--radius-badge);
  background-color: var(--color-ink);
  color: var(--color-surface);
  font-size: 12px;
  font-weight: 500;
}

.sticky {
  width: 190px;
  padding: 14px 16px;
  border-radius: 2px;
  background-color: var(--paper-fill);
  box-shadow: 0 0 0 1px var(--paper-edge);
  font-size: 14px;
  line-height: 1.45;
}

/* The reply, with the one control anybody presses on it. */
.art-reply {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12px;
}

.reply {
  padding: 16px 18px;
  border-radius: var(--radius-card);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
  font-size: 15px;
  line-height: 1.55;
}

.reply-foot {
  display: flex;
  align-items: center;
  gap: 12px;
}

.reply-note {
  color: var(--color-ink-muted);
  font-size: 13px;
}

/* Who reads, and what state each one is in. */
.art-reads {
  display: flex;
  align-items: center;
}

.stack {
  width: 100%;
  padding: 0;
  list-style: none;
}

.stack li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid var(--color-ring);
  font-size: 15px;
  font-weight: 500;
}

.stack li:last-child {
  border-bottom: 0;
}

.stack li span {
  color: var(--color-ink-muted);
  font-size: 13px;
  font-weight: 400;
}

/* ==========================================================================
   The demo

   The product doing its whole job at the top of the page: the request on the
   left, and everything it gives back on the right, inside one window, so the
   verdict, the clause and the reply all land in the same view as the gesture
   that produced them.
   ========================================================================== */

.demo {
  max-width: 1320px;
  margin: 0 auto;
  padding: 0 24px;
}

.demo-ask {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  color: var(--color-ink-muted);
  font-size: 15px;
  transition: opacity var(--motion-base) var(--ease-out-soft);
}

/* A drawn arrow rather than a character, so it keeps the weight of the rest
   of the drawing on this page. It points down at the board. */
.demo-ask::before {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background-color: currentColor;
  -webkit-mask: var(--arrow) center / contain no-repeat;
  mask: var(--arrow) center / contain no-repeat;
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 4v14M6 13l6 6 6-6' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  animation: nudge-down 2.6s var(--ease-in-out-soft) infinite;
}

/* Once somebody has read one, the page stops asking them to. */
.demo[data-used] .demo-ask {
  opacity: 0;
}

@keyframes nudge-down {
  0%,
  70%,
  100% {
    transform: none;
  }
  82% {
    transform: translateY(3px);
  }
}

/* -------------------------------------------------------------- the stage */

.window {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  border-radius: var(--radius-window);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
  overflow: hidden;
}

/* The one on the demo is a real window rather than a panel, so it is sized
   to sit inside a laptop viewport with the hero's last line still above it. */
.demo .window {
  height: min(78vh, 720px);
  /* 40 of title bar, 49 of toolbar and the 560 the ground asks for in column
     layout. Anything less and the window clips Beady's feet, because the
     ground's min-height wins and the window's `overflow: hidden` takes the
     difference off the bottom. */
  min-height: 664px;
}

/* The title bar. macOS chrome, drawn rather than screenshotted: the three
   lights are an illustration of a window, which is the reason they are
   allowed a fill. They are not saying anything about a request. There is no
   drop shadow under this window and there is not one anywhere on the page:
   the system's only elevation is a one pixel ring. */
.window-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
  height: 40px;
  padding: 0 14px;
  border-bottom: 1px solid var(--color-ring);
  background-color: color-mix(in srgb, var(--color-sunk) 58%, var(--color-surface));
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  backdrop-filter: saturate(1.6) blur(12px);
}

.lights {
  display: inline-flex;
  flex: none;
  gap: 8px;
}

.lights i {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 0.5px rgb(0 0 0 / 0.14);
}

.lights i:nth-child(1) {
  background-color: #ff5f57;
}

.lights i:nth-child(2) {
  background-color: #febc2e;
}

.lights i:nth-child(3) {
  background-color: #28c840;
}

.window-title {
  flex: 1;
  text-align: center;
  color: var(--color-ink-muted);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Balances the lights, so the title is centred on the window and not on the
   space left over beside them. */
.window-tail {
  flex: none;
  width: 52px;
}

.window-body {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr);
  flex: 1;
  min-height: 0;
}

.stage-side {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border-right: 1px solid var(--color-ring);
}

/* Everything Beady gives back. It scrolls inside the window rather than
   growing it, so the board never moves under the hand that is using it. */
.readout {
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  background-color: var(--color-surface);
}

.readout-slot {
  padding: 26px 28px 30px;
}

.readout-steps {
  display: grid;
  gap: 14px;
  margin: 18px 0 0;
  padding: 0;
  list-style: none;
}

.readout-steps li {
  display: flex;
  gap: 12px;
  color: var(--color-ink-body);
  font-size: 15px;
  line-height: 1.5;
  text-wrap: pretty;
}

.readout-n {
  display: grid;
  flex: none;
  place-items: center;
  width: 22px;
  height: 22px;
  margin-top: 1px;
  border-radius: 999px;
  box-shadow: 0 0 0 1px var(--color-ring);
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 600;
}

.readout-foot {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--color-ring);
  color: var(--color-ink-muted);
  font-size: 14px;
  line-height: 1.55;
  text-wrap: pretty;
}

.readout-foot em {
  font-style: normal;
  color: var(--color-ink);
}

/* A card never nests inside another card, and the readout is already a panel
   of the window, so the verdict drops its own chrome in here. */
.readout .verdict {
  padding: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}

/* The draft, which is the last thing to arrive and the thing people came for */
.draft {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--color-ring);
}

.draft-body {
  margin-top: 10px;
  font-size: 15px;
  line-height: 1.6;
  text-wrap: pretty;
}

.draft-body .w {
  display: inline-block;
  animation: word-in 380ms var(--ease-out-soft) backwards;
  animation-delay: calc(var(--n) * 30ms + 120ms);
}

.draft-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 18px;
  animation: rise 420ms var(--ease-out-soft) var(--after-words, 1.2s) backwards;
}

.draft-note {
  color: var(--color-ink-muted);
  font-size: 13px;
}

.copy {
  border: 0;
  font-family: inherit;
  cursor: pointer;
}

/* One column below a laptop: the readout goes under the board rather than
   beside it, and the window stops being a fixed height because the thing it
   is holding is now twice as tall. */
@media (max-width: 899px) {
  .demo .window {
    height: auto;
    min-height: 0;
  }

  .window-body {
    grid-template-columns: minmax(0, 1fr);
  }

  .stage-side {
    border-right: 0;
    border-bottom: 1px solid var(--color-ring);
  }

  .readout {
    overflow: visible;
  }
}

.window-chrome {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex: none;
  padding: 12px 14px;
  border-bottom: 1px solid var(--color-ring);
}

/* View switcher: a sunk track at radius 8 with 3 of padding. Board sits
   first, because it is the default. */
.switcher {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-control);
  background-color: var(--color-sunk);
}

.switcher-option {
  padding: 6px 14px;
  border-radius: var(--radius-badge);
  color: var(--color-ink-muted);
  font-size: 13px;
  font-weight: 500;
}

.switcher-option.is-on {
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
  color: var(--color-ink);
  font-weight: 600;
}

.chrome-hint {
  color: var(--color-ink-muted);
  font-size: 14px;
  transition: opacity var(--motion-base) var(--ease-out-soft);
}

/* The ground is dots at 32, so a thing reads as sitting on something. */
.ground {
  position: relative;
  flex: 1;
  min-height: 410px;
  background-color: var(--color-canvas);
  background-image: radial-gradient(
    circle,
    var(--color-ring) 1px,
    transparent 1px
  );
  background-size: 32px 32px;
  touch-action: none;
}

/* The height follows the layout `hero.js` actually chose, not a media query's
   guess at it: a column of three notes is taller than a pile of three, and the
   two disagreed at exactly the widths where it mattered. */
.ground[data-lay="column"] {
  min-height: 560px;
}

.ground[data-lay="pile"] {
  min-height: 470px;
}



/* The drop target is ink-dashed on the ground it already has. Colour here
   would claim a verdict about something nobody has read. */
.well {
  position: absolute;
  right: 22px;
  bottom: 200px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  width: 220px;
  height: 150px;
  padding-top: 12px;
  border-radius: var(--radius-block);
  outline: 2px dashed transparent;
  outline-offset: -2px;
  color: var(--color-ink-muted);
  font-size: 14px;
  opacity: 0.7;
  outline-color: var(--color-ring);
  transition:
    opacity var(--motion-base) var(--ease-out-soft),
    outline-color var(--motion-fast) var(--ease-out-soft),
    background-color var(--motion-fast) var(--ease-out-soft);
}

.ground[data-dragging="true"] .well {
  opacity: 1;
  outline-color: var(--color-ink-faint);
}

/* Once it is holding something it stops asking. */
.ground[data-holding="true"] .well {
  opacity: 0;
}

.ground[data-holding="true"][data-dragging="true"] .well {
  opacity: 1;
}

.ground[data-over="true"] .well {
  outline-color: var(--color-ink);
  background-color: color-mix(in srgb, var(--color-sunk) 70%, transparent);
  color: var(--color-ink-muted);
}

.stage-beady {
  position: absolute;
  right: 40px;
  bottom: 2px;
  width: 150px;
  aspect-ratio: 1020 / 1140;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  cursor: pointer;
}

/* His speech bubble is the notification surface: ink fill, radius 16, white
   text, no ring. It is the one surface in the system allowed to invert. */
.beady-says {
  position: absolute;
  right: 196px;
  bottom: 14px;
  max-width: 200px;
  padding: 12px 16px;
  border-radius: var(--radius-block);
  background-color: var(--color-ink);
  color: var(--color-surface);
  font-size: 14px;
  line-height: 1.45;
  animation: rise var(--motion-slow) var(--ease-out-soft) backwards;
}

/* A column of three notes and a drop well do not both fit in a phone's width,
   so the notes become a pile in the corner and everything else moves down. */
@media (max-width: 619px) {
  /* The bubble carries the instruction at this width, and the chrome line was
     wrapping onto three lines to say it a second time. */
  .chrome-hint {
    display: none;
  }

  .well {
    bottom: 140px;
    height: 140px;
  }

  .stage-beady {
    right: 16px;
    bottom: 0;
    width: 112px;
  }

  .beady-says {
    right: auto;
    left: 12px;
    bottom: 12px;
    max-width: 200px;
  }
}

/* ---------------------------------------------------------------- a note */

.note {
  position: absolute;
  width: 180px;
  min-height: 112px;
  padding: 14px 16px;
  border: 0;
  border-radius: 2px;
  background-color: var(--paper-fill);
  box-shadow: 0 0 0 1px var(--paper-edge);
  color: var(--color-ink);
  font-family: inherit;
  font-size: 15px;
  line-height: 1.45;
  text-align: left;
  cursor: grab;
  touch-action: none;
  transition:
    left 300ms var(--ease-spring),
    top 300ms var(--ease-spring),
    transform var(--motion-fast) var(--ease-out-soft),
    box-shadow var(--motion-fast) var(--ease-out-soft);
  animation: place 520ms var(--ease-spring) backwards;
}

.note:hover {
  transform: translateY(-2px);
}

/* The first one breathes until somebody touches the board, which is what turns
   a pile of paper into an invitation. It stops for good on the first read
   rather than looping at somebody who is trying to read the page. */
.note.is-first::before {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 6px;
  pointer-events: none;
  box-shadow: 0 0 0 2px var(--color-ink-faint);
  opacity: 0;
  animation: note-ask 2.8s var(--ease-in-out-soft) infinite;
}

@keyframes note-ask {
  0%,
  100% {
    opacity: 0;
    transform: scale(0.985);
  }
  40% {
    opacity: 0.85;
    transform: scale(1);
  }
  70% {
    opacity: 0;
    transform: scale(1.01);
  }
}

@media (prefers-reduced-motion: reduce) {
  .note.is-first::before {
    animation: none;
  }
}

.note[data-dragging="true"] {
  cursor: grabbing;
  transform: scale(1.03);
  box-shadow: 0 0 0 2px var(--color-ink);
  z-index: 3;
  transition: none;
}

.note[data-read="true"] {
  cursor: default;
}

.note-who {
  display: block;
  margin-bottom: 6px;
  color: var(--color-ink-muted);
  font-size: 13px;
}

.note-text {
  display: block;
}

/* The count badge: a 28px signal disc with an ink numeral, on the card's
   top-right corner. It says how many asks were read out of that note and
   nothing more. A verdict colour here would claim a judgement. */
.note-count {
  position: absolute;
  top: -10px;
  right: -10px;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background-color: var(--color-signal);
  color: var(--color-ink);
  font-size: 13px;
  font-weight: 600;
  animation: place 520ms var(--ease-spring) backwards;
}

/* A band of light travels across the paper, the way a scanner passes over a
   page. Slow and low-contrast on purpose: anything brisk enough to be
   interesting at second five is unbearable by second fifty. */
.reading-note {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.reading-note::after {
  content: "";
  position: absolute;
  inset: -30% -20%;
  z-index: 1;
  pointer-events: none;
  transform: translateX(-60%);
  background: linear-gradient(
    105deg,
    transparent 30%,
    rgb(255 255 255 / 0.9) 50%,
    transparent 70%
  );
  animation: reading-sweep 2.4s var(--ease-out-soft) infinite;
}

.note-working {
  display: block;
  margin-top: 10px;
  color: var(--color-ink-muted);
  font-size: 13px;
}

/* -------------------------------------------------------- the verdict card */

.verdict {
  padding: 22px 24px;
  border-radius: var(--radius-card);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
  animation: rise var(--motion-slow) var(--ease-out-soft) backwards;
}

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

.eyebrow {
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* Verdict badge: radius 6, padding 4/11, 12/500, sentence case. It hugs its
   label and never wraps, and the label is always ink, never white. */
.badge {
  display: inline-block;
  width: fit-content;
  padding: 4px 11px;
  border-radius: var(--radius-badge);
  color: var(--color-ink);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}

.badge[data-verdict="covered"] {
  background-color: var(--color-covered);
}

.badge[data-verdict="unsettled"] {
  background-color: var(--color-unsettled);
}

.badge[data-verdict="extra"] {
  background-color: var(--color-extra);
}

.verdict-answer {
  margin-top: 12px;
  font-size: 21px;
  line-height: 1.2;
  letter-spacing: -0.3px;
  text-wrap: pretty;
}

.verdict-reason {
  margin-top: 8px;
  color: var(--color-ink-body);
  font-size: 15px;
}

/* The evidence band. Honey is the marker pen, not a verdict: it stays the
   same colour whether the finding was covered, unsure or extra, because the
   band means *this is the wording it rests on* and nothing else. */
.evidence {
  margin-top: 18px;
  padding: 16px 20px;
  border-radius: var(--radius-block);
  background-color: var(--color-honey-pale);
}

.evidence-still {
  margin-top: 0;
  padding: 20px 24px;
}

.evidence-still .evidence-quote {
  margin: 0;
  font-size: 23px;
}

.evidence-label {
  color: var(--color-ink);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.evidence-quote {
  margin: 10px 0 0;
  font-family: var(--font-serif);
  font-size: 19px;
  line-height: 1.45;
  text-wrap: pretty;
}

.stage-foot {
  display: flex;
  justify-content: flex-end;
  min-height: 24px;
  margin-top: 14px;
}

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

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

@keyframes place {
  from {
    opacity: 0;
    transform: scale(0.94);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* The objects breathe. `translate` is its own property, so it composes with
   the `transform` rotation each object carries instead of fighting it. */
@keyframes drift {
  0%,
  100% {
    translate: 0 0;
  }
  50% {
    translate: 0 -12px;
  }
}

@keyframes reading-sweep {
  from {
    transform: translateX(-60%);
  }
  to {
    transform: translateX(60%);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    /* Delays as well, or nothing moves but everything still arrives in
       sequence: the reply's last word is 2.3 seconds behind its first, and a
       staggered reveal is exactly the thing somebody asking for reduced motion
       is asking not to have. */
    animation-delay: 0ms !important;
    transition-delay: 0ms !important;
  }

  .reading-note::after {
    animation: none;
    opacity: 0.35;
    transform: none;
    inset: 0;
    background: var(--color-sunk);
  }
}

/* Below this the two actions cannot sit side by side without wrapping into a
   ragged second row, so they stack and take the full measure. */
@media (max-width: 520px) {
  .actions {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .button {
    width: 100%;
  }
}

/* The bar's text link wrapped onto two lines beside the button at phone
   width, and the button is the one that matters. */
@media (max-width: 520px) {
  .bar-links .link {
    display: none;
  }

  .bar-inner {
    padding: 0 16px;
  }

  .hero {
    padding-left: 16px;
    padding-right: 16px;
  }
}

/* One tile per row at this width, so there is no neighbouring title to line
   up with and a fixed height would only crop things for no reason. This sits
   at the end of the file because it overrides `.art`, which is declared after
   the bento's own media queries. */
@media (max-width: 719px) {
  .art {
    height: auto;
    min-height: 160px;
  }
}

/* ==========================================================================
   The tiles come alive

   Colour here is louder than the app allows itself, and it is allowed for one
   reason: everything inside a fragment is illustration, and illustration is
   where `DESIGN_SYSTEM.md` 5 lets the drawing palette out. Each fragment sits
   in a pale tint of its own accent, the way the spec's illustration well does.
   The chrome around them — the tiles, the type, the buttons, the verdict
   chips — is untouched and still argues with nobody.

   Every animation says what its tile says. Nothing here is motion for the
   sake of it: the clauses get pulled out one at a time, the marker sweeps the
   line the verdict rests on, the screenshot drops and is scanned, the note is
   checked and gains its count, the reply is written a word at a time.
   ========================================================================== */

.art-scope {
  background-color: var(--color-canvas);
}
.art-evidence {
  background-color: var(--color-sunk);
}
.art-timeline {
  background-color: #ffeaf3;
}
.art-drop {
  background-color: #e4f4ff;
}
.art-note {
  background-color: #f6f0e4;
}
.art-reply {
  background-color: #ece7f7;
}
.art-reads {
  background-color: #e8f9ef;
}

/* The clause types, told apart by tint. Ink labels, so the colour is carrying
   recognition and never the meaning. */
.clause:nth-child(1) .type {
  background-color: #e8f9ef;
  color: var(--color-ink-body);
}
.clause:nth-child(2) .type {
  background-color: #fff3d6;
  color: var(--color-ink-body);
}
.clause:nth-child(3) .type {
  background-color: #ffe6da;
  color: var(--color-ink-body);
}

/* The state dots on the reader list. */
.state {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.state::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background-color: var(--color-ink-faint);
}

.state-on::before {
  background-color: var(--color-covered);
}

.state-ready::before {
  background-color: var(--color-unsettled);
}

/* --------------------------------------------------- arriving on the page

   Every tile is dealt onto the grid like a card onto a desk, and that is the
   whole of its arrival.

   There was an ink ring that swept clockwise around each tile as it landed and
   then faded. It was removed: seven outlines drawing themselves in sequence
   read as a block outline snapping on down the page rather than as seven
   things being put down, and the tiles already announce themselves by leaning
   in and by the film each one starts playing. Do not put it back. */

.bento[data-anim] .tile {
  position: relative;
  opacity: 0;
  transform: translate3d(0, 32px, 0) rotate(var(--lean, -1.2deg)) scale(0.972);
  transform-origin: 50% 130%;
  transition:
    opacity 480ms var(--ease-out-soft),
    transform 880ms var(--ease-deal),
    box-shadow var(--motion-base) var(--ease-out-soft);
  transition-delay: calc(var(--i, 0) * 80ms);
}

/* They do not all lean the same way, or the grid arrives as one slab that has
   been rotated rather than as seven things that were put down. */
.bento[data-anim] .tile:nth-child(even) {
  --lean: 1.2deg;
}
.bento[data-anim] .tile:nth-child(3n) {
  --lean: -0.7deg;
}

.bento[data-anim] .tile.in-view {
  opacity: 1;
  transform: none;
}


/* The fragment answers the pointer by the smallest amount that still reads as
   an answer. No tilt, no shadow, no lift: the piece of interface inside comes
   very slightly forward and the tile's ring darkens by one step.

   The tile's own `transform` is left alone on purpose. It belongs to the
   entrance, and a hover writing to it would be transitioned by the 880ms deal
   curve on the way back out, so a tile would sag for nearly a second every
   time the pointer left it. */
.art {
  transition: transform 420ms var(--ease-out-soft);
  transform-origin: 50% 46%;
}

@media (hover: hover) {
  .bento[data-anim] .tile.in-view:hover {
    box-shadow: 0 0 0 1px var(--color-ink-faint);
    transition-delay: 0ms;
  }

  .tile:hover .art {
    transform: scale(1.016);
  }
}

/* ------------------------------------------------------- scope: pulled out

   A honey beam travels down the contract and each clause develops where it
   passes, out of focus and into focus, the way a page comes up in a tray. The
   beam is honey because honey is this system's marker: what is moving down the
   page is Beady finding the wording, and when it reaches the bottom the marker
   goes back and draws the line the verdict will rest on.

   The clause timings are not decorative. The beam's leading edge is at the top
   of the fragment at 200ms and at the bottom at 1520ms, so a clause sitting
   18, 78 and 138 pixels down develops at 320, 715 and 1110. Move the beam and
   these move with it. */

.art-scope {
  --beam-in: 200ms;
  --beam-run: 1500ms;
}

.in-view .art-scope::after {
  content: "";
  position: absolute;
  top: -46px;
  right: 0;
  left: 0;
  z-index: 4;
  height: 46px;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgb(255 187 38 / 0) 0%,
    rgb(255 187 38 / 0.16) 76%,
    var(--color-draw-honey) 95%
  );
  animation: scope-beam var(--beam-run) var(--ease-in-out-soft) var(--beam-in)
    both;
}

@keyframes scope-beam {
  0% {
    transform: translateY(0);
    opacity: 0;
  }
  6% {
    opacity: 1;
  }
  88% {
    transform: translateY(200px);
    opacity: 1;
  }
  100% {
    transform: translateY(216px);
    opacity: 0;
  }
}

.bento[data-anim] .art-scope .clause {
  opacity: 0;
}

.in-view .art-scope .clause {
  animation: clause-develop 640ms var(--ease-out-soft) forwards;
}

@keyframes clause-develop {
  0% {
    opacity: 0;
    clip-path: inset(0 0 100% 0);
    filter: blur(7px);
    transform: translateY(7px);
  }
  55% {
    opacity: 1;
  }
  100% {
    opacity: 1;
    clip-path: inset(0 0 0 0);
    filter: blur(0);
    transform: none;
  }
}

.in-view .art-scope .clause:nth-child(1) {
  animation-delay: 320ms;
}
.in-view .art-scope .clause:nth-child(2) {
  animation-delay: 715ms;
}
.in-view .art-scope .clause:nth-child(3) {
  animation-delay: 1110ms;
}

/* The type chip lands after the words it labels, not with them. */
.in-view .art-scope .clause .type {
  animation: chip-pop 420ms var(--ease-spring) backwards;
}

.in-view .art-scope .clause:nth-child(1) .type {
  animation-delay: 620ms;
}
.in-view .art-scope .clause:nth-child(2) .type {
  animation-delay: 1015ms;
}
.in-view .art-scope .clause:nth-child(3) .type {
  animation-delay: 1410ms;
}

@keyframes chip-pop {
  from {
    opacity: 0;
    transform: scale(0.72);
  }
}

/* The motif: one honey-highlighted line in every drawing. The marker is a
   background rather than a layer behind the text, so nothing has to be
   stacked over anything. It runs after the beam has finished, because the
   story is that it read the whole thing and then went back and marked a line. */
.clause-mark p {
  /* Inline, so the marker hugs the words and breaks with them the way a real
     one does, instead of painting the whole line box. */
  display: inline;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  background-image: linear-gradient(
    var(--color-honey-pale),
    var(--color-honey-pale)
  );
  background-repeat: no-repeat;
  background-size: 0 100%;
  padding: 1px 4px;
  margin-left: -4px;
  border-radius: 4px;
}

.in-view .clause-mark p {
  animation: mark-sweep 620ms cubic-bezier(0.32, 0.86, 0.3, 1) 1680ms forwards;
}

@keyframes mark-sweep {
  to {
    background-size: 100% 100%;
  }
}

/* ------------------------------------------------ evidence: the marker runs

   A stroke with a nib on the front of it. The band is clipped open left to
   right and a twelve pixel square of honey rides its leading edge and lifts
   off the end, which is the difference between a rectangle appearing and
   somebody drawing one. */

.art-evidence .evidence-still {
  position: relative;
  overflow: hidden;
}

.in-view .art-evidence .evidence-still {
  animation: marker-stroke 780ms cubic-bezier(0.22, 0.88, 0.26, 1) 260ms
    backwards;
}

@keyframes marker-stroke {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

/* Full width, with only the first twelve pixels painted, so the nib can be
   moved with a transform instead of a layout property. */
.in-view .art-evidence .evidence-still::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    90deg,
    var(--color-draw-honey) 0 12px,
    transparent 12px
  );
  animation: nib-run 780ms cubic-bezier(0.22, 0.88, 0.26, 1) 260ms both;
}

@keyframes nib-run {
  0% {
    transform: translateX(-12px);
    opacity: 1;
  }
  88% {
    opacity: 1;
  }
  100% {
    transform: translateX(100%);
    opacity: 0;
  }
}

.in-view .art-evidence .evidence-quote {
  animation: rise 460ms var(--ease-out-soft) 760ms backwards;
}

/* And then it keeps checking. Every seven seconds a pale pass crosses the
   band, which is the same gesture Beady makes over a note he is reading: the
   quote is not stored and trusted, it is found again every time. */
.in-view .art-evidence .evidence-still::after {
  content: "";
  position: absolute;
  inset: -40% -20%;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    102deg,
    transparent 40%,
    rgb(255 255 255 / 0.62) 50%,
    transparent 60%
  );
  animation: verify-pass 7s var(--ease-in-out-soft) 2.2s infinite;
}

@keyframes verify-pass {
  0% {
    transform: translateX(-70%);
  }
  26%,
  100% {
    transform: translateX(70%);
  }
}

/* ------------------------------------------- timeline: and one row is asking */

.in-view .art-timeline .tl-row {
  animation: row-land 620ms var(--ease-spring) backwards;
}

@keyframes row-land {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
}

.in-view .art-timeline .tl-row:nth-of-type(1) {
  animation-delay: 300ms;
}
.in-view .art-timeline .tl-row:nth-of-type(2) {
  animation-delay: 480ms;
}

/* A date that came off a contract settles rather than appears. */
.in-view .art-timeline .tl-date {
  display: inline-block;
  animation: date-settle 560ms var(--ease-out-soft) 560ms backwards;
}

@keyframes date-settle {
  from {
    opacity: 0;
    transform: perspective(300px) rotateX(-72deg);
  }
}

.tl-set {
  position: relative;
}

/* Signal means the app is asking for you, and a row with no date is the one
   thing on this page that is. Two rings, half a cycle apart, so it reads as a
   thing waiting rather than a thing blinking. It keeps asking. */
.in-view .tl-set::after,
.in-view .tl-set::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  animation: signal-ring 3s var(--ease-out-soft) 900ms infinite;
}

.in-view .tl-set::before {
  animation-delay: 2.4s;
}

@keyframes signal-ring {
  0% {
    box-shadow: 0 0 0 0 rgb(255 88 174 / 0.55);
  }
  70%,
  100% {
    box-shadow: 0 0 0 15px rgb(255 88 174 / 0);
  }
}

/* ------------------------------------------ the drop: it lands, then is read

   A photograph dropped on a desk: it falls, it is off square, and it settles.
   Then the scanner crosses it, and the line underneath is typed out as the
   scanner passes, because the reading is what produces the line. */

.in-view .shot {
  animation: shot-drop 820ms var(--ease-spring) 240ms backwards;
}

@keyframes shot-drop {
  from {
    opacity: 0;
    transform: translateY(-34px) rotate(-5.5deg) scale(0.9);
  }
}

.shot {
  position: relative;
  overflow: hidden;
}

/* The same band that crosses a note while it is being read, at the same slow
   speed and the same low contrast. */
.in-view .shot::after {
  content: "";
  position: absolute;
  inset: -30% -20%;
  pointer-events: none;
  background: linear-gradient(
    105deg,
    transparent 30%,
    rgb(255 255 255 / 0.85) 50%,
    transparent 70%
  );
  animation: reading-sweep 2.6s var(--ease-out-soft) 1s infinite;
}

/* The line is typed, with a caret that runs along in front of it and blinks a
   few times at the end before it goes. Thirty-eight steps for thirty-eight
   characters: change the words and change the count, or the letters arrive in
   clumps. */
.shot-read {
  position: relative;
  width: fit-content;
  max-width: none;
  white-space: nowrap;
}

.shot-typed {
  display: inline-block;
}

.in-view .shot-typed {
  animation: type-line 1080ms steps(38, end) 1180ms both;
}

@keyframes type-line {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 -2px 0 0);
  }
}

.shot-caret {
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 0;
  width: 1.5px;
  background-color: var(--color-ink);
  opacity: 0;
}

.in-view .shot-caret {
  animation:
    caret-run 1080ms steps(38, end) 1180ms both,
    caret-blink 760ms steps(1) 2260ms 5 both;
}

@keyframes caret-run {
  from {
    left: 0;
    opacity: 1;
  }
  to {
    left: 100%;
    opacity: 1;
  }
}

@keyframes caret-blink {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

/* --------------------------------------- the note: pressed, and it counts */

.sticky {
  position: relative;
  transition: transform var(--motion-base) var(--ease-out-soft);
}

.in-view .bar-check {
  animation: press 5.2s var(--ease-out-soft) 700ms infinite;
}

@keyframes press {
  0%,
  8%,
  100% {
    transform: none;
  }
  3% {
    transform: scale(0.9);
  }
}

/* The paper answers the press before the badge does. */
.in-view .sticky {
  animation: sticky-take 5.2s var(--ease-spring) 700ms infinite;
}

@keyframes sticky-take {
  0%,
  4%,
  22%,
  100% {
    transform: none;
  }
  9% {
    transform: translateY(-3px) scale(1.012);
  }
}

/* What the press produces: the count badge the board puts on anything it has
   read. Signal, never a verdict colour, because a count is not a judgement. */
.in-view .sticky::after {
  content: "1";
  position: absolute;
  top: -11px;
  right: -11px;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background-color: var(--color-signal);
  color: var(--color-ink);
  font-size: 13px;
  font-weight: 600;
  animation: badge-pop 5.2s var(--ease-spring) 700ms infinite;
}

/* A ring goes out from under it as it lands, once, the way the board's own
   count badge does. */
.in-view .sticky::before {
  content: "";
  position: absolute;
  top: -11px;
  right: -11px;
  z-index: 1;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  pointer-events: none;
  animation: badge-burst 5.2s var(--ease-out-soft) 700ms infinite;
}

@keyframes badge-burst {
  0%,
  6% {
    box-shadow: 0 0 0 0 rgb(255 88 174 / 0.5);
  }
  24%,
  100% {
    box-shadow: 0 0 0 18px rgb(255 88 174 / 0);
  }
}

@keyframes badge-pop {
  0%,
  6% {
    opacity: 0;
    transform: scale(0.4);
  }
  14%,
  86% {
    opacity: 1;
    transform: none;
  }
  96%,
  100% {
    opacity: 0;
    transform: scale(0.9);
  }
}

/* --------------------------------- the reply: written a word at a time

   The caret is the whole trick, and it costs one pseudo-element and no
   JavaScript. Every word carries its own caret on its right edge, lit only for
   its own beat, so what you see is one caret travelling along the line as the
   words arrive under it. The last word's caret blinks four times and goes.

   **The caret's duration is the beat, not the word's fade.** They were both
   380ms against a 36ms beat to begin with, which lit eleven carets at a time
   and read as `today|and|keep|it|off|the|`. The caret is 64ms against a 66ms
   beat now: two milliseconds of slack so a rounding error can never light two,
   and never long enough to catch the next one.

   The beat also had to slow down. At 36ms a caret is on screen for two frames
   per word, which is a streak rather than a cursor. The fade stays at 380ms
   and overlaps several beats, so the caret runs ahead of the ink settling
   behind it, which is what typing looks like.

   The same rules drive the draft in the demo window, because it is the same
   thing happening. Its beat is quicker (46ms) because somebody is waiting on
   that one, where the tile is a loop somebody is watching. */

.art-reply .w,
.draft-body .w {
  position: relative;
  display: inline-block;
}

.in-view .art-reply .w {
  animation: word-in 380ms var(--ease-out-soft) backwards;
  animation-delay: calc(var(--n) * 66ms + 340ms);
}

@keyframes word-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
}

.in-view .art-reply .w::after,
.draft-body .w::after {
  content: "";
  position: absolute;
  top: 0.14em;
  right: -2px;
  bottom: 0.04em;
  width: 1.5px;
  background-color: var(--color-ink);
  opacity: 0;
}

.in-view .art-reply .w::after {
  animation: caret-hold 64ms steps(1);
  animation-delay: calc(var(--n) * 66ms + 340ms);
}

.draft-body .w::after {
  animation: caret-hold 44ms steps(1);
  animation-delay: calc(var(--n) * 46ms + 120ms);
}

/* On for its own word's window and off the instant the next word starts, which
   is what makes one caret out of thirty.

   **No fill mode on this one, and that is the whole reason it works.** With
   `backwards` the caret painted its first keyframe through the delay as well,
   so every word that had not been written yet was already showing a caret and
   the line read `today|and|keep|it|off|the|`. With no fill the pseudo-element
   falls back to its own `opacity: 0` outside its window, and exactly one caret
   is lit at a time. */
@keyframes caret-hold {
  0%,
  99% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

.in-view .art-reply .w:last-of-type::after {
  animation:
    caret-hold 64ms steps(1) calc(var(--n) * 66ms + 340ms),
    caret-blink 760ms steps(1) calc(var(--n) * 66ms + 404ms) 4 forwards;
}

.draft-body .w:last-of-type::after {
  animation:
    caret-hold 44ms steps(1) calc(var(--n) * 46ms + 120ms),
    caret-blink 760ms steps(1) calc(var(--n) * 46ms + 164ms) 4 forwards;
}

.in-view .art-reply .reply-foot {
  animation: rise 420ms var(--ease-out-soft) var(--after-words, 1.6s) backwards;
}

/* ------------------------------------------------ the readers: one is chosen */

.art-reads .stack {
  position: relative;
}

.stack li {
  position: relative;
  z-index: 1;
  height: 46px;
  padding: 0;
  align-items: center;
}

.in-view .art-reads .stack::before {
  content: "";
  position: absolute;
  z-index: 0;
  top: 0;
  left: -12px;
  right: -12px;
  height: 46px;
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
  animation: pick 8.4s var(--ease-in-out-soft, ease-in-out) 600ms infinite;
}

/* It dwells on a row and snaps to the next one. Half a second of travel put
   the bar across two rows for long enough to read as a glitch rather than as
   a choice. */
@keyframes pick {
  0%,
  31% {
    transform: translateY(0);
  }
  33%,
  64% {
    transform: translateY(46px);
  }
  66%,
  97% {
    transform: translateY(92px);
  }
  99%,
  100% {
    transform: translateY(0);
  }
}

/* The chosen row comes forward with the bar rather than waiting under it. One
   keyframe for all three, offset by a negative delay of a third of the cycle
   each, so the three can never drift apart from the bar or from each other. */
.in-view .art-reads .stack li {
  animation: row-chosen 8.4s var(--ease-in-out-soft) 600ms infinite;
}

.in-view .art-reads .stack li:nth-child(2) {
  animation-delay: calc(600ms - 8.4s / 3);
}

.in-view .art-reads .stack li:nth-child(3) {
  animation-delay: calc(600ms - 8.4s * 2 / 3);
}

@keyframes row-chosen {
  0%,
  31% {
    color: var(--color-ink);
  }
  34%,
  97% {
    color: var(--color-ink-muted);
  }
  100% {
    color: var(--color-ink);
  }
}

/* --------------------------------------------------------------- the board */

/* Beady's own engine already stops under a reduced-motion setting, and the
   demo is the one place whose motion is the product rather than a portrait of
   it, so nothing is added to it here. */

@media (prefers-reduced-motion: reduce) {
  /* The global rule at the top of this file already collapses every duration.
     Everything below would otherwise sit in its starting frame forever,
     because what reveals it is an animation rather than a transition. */
  .bento[data-anim] .art-scope .clause {
    opacity: 1;
    transform: none;
    clip-path: none;
    filter: none;
  }

  .clause-mark p {
    background-size: 100% 100%;
  }

  .in-view .art-evidence .evidence-still,
  .in-view .shot-typed {
    clip-path: none;
  }

  .in-view .art-evidence .evidence-still::before,
  .in-view .art-evidence .evidence-still::after,
  .in-view .art-scope::after,
  .in-view .shot::after,
  .in-view .shot-caret,
  .in-view .art-reply .w::after,
  .draft-body .w::after {
    display: none;
  }
}

/* ==========================================================================
   The rest of the page

   Bands under the hero, each one a different shape so a long page has a
   rhythm rather than eleven of the same card. One of them inverts to ink,
   which is the surface the app already uses when it speaks as itself.
   ========================================================================== */

.band {
  max-width: 1320px;
  margin: 0 auto;
  padding: 96px 24px;
}

.band + .band {
  padding-top: 0;
}

.band-head {
  max-width: 62ch;
  margin-bottom: 44px;
}

.band-title {
  margin: 0;
  font-size: clamp(30px, 3.6vw, 42px);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

.band-lede {
  margin-top: 16px;
  color: var(--color-ink-body);
  font-size: 17px;
  line-height: 1.53;
  text-wrap: pretty;
}

/* ------------------------------------------------------------- the steps */

.steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

@media (max-width: 899px) {
  .steps {
    grid-template-columns: minmax(0, 1fr);
  }
}

.step {
  position: relative;
  padding: 28px 28px 30px;
  border-radius: var(--radius-block);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
}

.step-n {
  display: block;
  color: var(--color-ink-muted);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.16em;
}

/* The drawn objects again, at the size the spec gives an icon well rather
   than an illustration: these are markers for a step, not the picture on it. */
/* Height, not width: the three objects have three different aspect ratios,
   and sizing them by width left their titles at three different heights. */
.step-art {
  display: block;
  width: auto;
  height: 62px;
  margin: 20px 0 22px;
  overflow: visible;
}

.step-title {
  margin: 0;
  font-size: 21px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.3px;
  text-wrap: balance;
}

.step-say {
  margin-top: 10px;
  color: var(--color-ink-body);
  font-size: 15px;
  text-wrap: pretty;
}

/* ------------------------------------------------------------- the inbox */

.band-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 56px;
  align-items: center;
}

@media (max-width: 899px) {
  .band-split {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
}

.split-say .band-lede {
  max-width: 52ch;
}

.ticks {
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
}

.ticks li {
  position: relative;
  padding: 11px 0 11px 30px;
  border-bottom: 1px solid var(--color-ring);
  color: var(--color-ink-body);
  font-size: 15px;
}

.ticks li:first-child {
  border-top: 1px solid var(--color-ring);
}

/* A drawn tick rather than a character, so it keeps the weight of everything
   else the product draws itself. */
.ticks li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 17px;
  width: 13px;
  height: 7px;
  border-left: 2.5px solid var(--color-ink);
  border-bottom: 2.5px solid var(--color-ink);
  transform: rotate(-45deg);
}

.split-art {
  padding: 26px;
  border-radius: var(--radius-block);
  background-color: #e4f4ff;
}

.mail {
  padding: 20px;
  border-radius: var(--radius-card);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
}

.mail-head {
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.mail-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--color-ring);
}

.mail-row:first-of-type {
  border-top: 1px solid var(--color-ring);
  margin-top: 14px;
}

.mail-who {
  font-size: 14px;
  font-weight: 500;
}

.mail-what {
  color: var(--color-ink-body);
  font-size: 14px;
}

/* A message that asks for nothing is skipped rather than recorded, and the
   row says so in words. It is not a verdict, so it takes no verdict colour. */
.mail-row.is-old .mail-who,
.mail-row.is-old .mail-what {
  color: var(--color-ink-muted);
}

.mail-skip {
  margin-left: auto;
  padding: 3px 9px;
  border-radius: var(--radius-badge);
  background-color: var(--color-sunk);
  color: var(--color-ink-muted);
  font-size: 12px;
  white-space: nowrap;
}

.mail-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 16px;
  color: var(--color-ink-body);
  font-size: 14px;
}

.mail-count {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background-color: var(--color-signal);
  color: var(--color-ink);
  font-size: 13px;
  font-weight: 600;
}

/* The architecture, folded away. True and worth having, but it is a lot of
   machinery to put in front of somebody who has not decided they want the app
   yet, so the reassurance is the section and this is underneath it. */
.tech {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--color-ring);
}

.tech summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--color-ember-text);
  font-size: 15px;
  cursor: pointer;
  list-style: none;
}

.tech summary::-webkit-details-marker {
  display: none;
}

.tech summary::after {
  content: "";
  width: 8px;
  height: 8px;
  border-right: 1.75px solid currentColor;
  border-bottom: 1.75px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--motion-base) var(--ease-out-soft);
}

.tech[open] summary::after {
  transform: translateY(1px) rotate(-135deg);
}

.tech summary:hover {
  color: var(--color-ember-text-hover);
}

.tech p {
  max-width: 62ch;
  margin-top: 14px;
  color: var(--color-ink-body);
  font-size: 15px;
  line-height: 1.6;
  text-wrap: pretty;
  animation: drop-open var(--motion-base) var(--ease-out-soft);
}

/* ------------------------------------------------------------- the limits */

.limits {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 56px;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--color-ring);
}

@media (max-width: 899px) {
  .limits {
    grid-template-columns: minmax(0, 1fr);
  }
}

.limits li {
  padding: 26px 0;
  border-bottom: 1px solid var(--color-ring);
}

.limits h3 {
  margin: 0;
  font-size: 17px;
  font-weight: 500;
}

.limits p {
  margin-top: 8px;
  max-width: 52ch;
  color: var(--color-ink-body);
  font-size: 15px;
  text-wrap: pretty;
}

/* ------------------------------------------------------------ the download */

.band-get {
  text-align: center;
}

.get-title {
  margin: 0;
  font-size: clamp(34px, 4.6vw, 56px);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.035em;
}

.get-say {
  margin-top: 16px;
  color: var(--color-ink-body);
  font-size: 17px;
}

.get-actions {
  margin-top: 28px;
}

.get-facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
  max-width: 760px;
  margin: 44px auto 0;
  padding-top: 24px;
  border-top: 1px solid var(--color-ring);
  text-align: left;
}

@media (max-width: 619px) {
  .get-facts {
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
  }
}

.get-facts dt {
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.get-facts dd {
  margin: 6px 0 0;
  font-size: 15px;
}

/* Four true things, and only true things. There is no Apple notarisation line
   because the build is deliberately unsigned, which the page says twice. */
.get-trust {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 14px;
  max-width: 760px;
  margin: 28px auto 0;
  padding: 0;
  list-style: none;
}

.get-trust li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 8px 12px;
  border-radius: 999px;
  box-shadow: 0 0 0 1px var(--color-ring);
  color: var(--color-ink-body);
  font-size: 14px;
}

/* The same drawn tick the inbox band uses, at the size of a mark rather than
   an illustration. */
.get-trust li::before {
  content: "";
  flex: none;
  width: 14px;
  height: 14px;
  background-color: var(--color-ink);
  -webkit-mask: var(--tick) center / contain no-repeat;
  mask: var(--tick) center / contain no-repeat;
  --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 13l6 6L20 5' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

@media (max-width: 619px) {
  .get-facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ================================================================ support

   Free is the point, not the disclaimer, so this is the second biggest
   surface on the page after the demo and it runs the full width.

   Honey pale, which is the marker colour the system already uses as a ground
   under a quoted clause. Not the ember orange the review asked for: ember is
   the `extra` verdict, and a whole band of it would be the page shouting a
   judgement at somebody who has not asked it anything. Rule 1. */

.band-support {
  margin-top: 96px;
  padding: 88px 24px 96px;
  background-color: var(--color-honey-pale);
}

.support-inner {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: 72px;
  max-width: 1272px;
  margin: 0 auto;
}

@media (max-width: 899px) {
  .band-support {
    margin-top: 72px;
    padding: 56px 24px 64px;
  }

  .support-inner {
    grid-template-columns: minmax(0, 1fr);
    gap: 44px;
  }
}

.support-title {
  margin: 0;
  max-width: 20ch;
  font-size: clamp(32px, 4vw, 50px);
  font-weight: 400;
  line-height: 1.07;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

.support-lede {
  max-width: 60ch;
  margin-top: 20px;
  color: var(--color-ink-body);
  font-size: 17px;
  line-height: 1.55;
  text-wrap: pretty;
}

/* --- the amounts --------------------------------------------------------

   Real controls over a destination that does not exist yet. See HANDOFF.md
   section 8.2: the seller is an individual in India and the open question is
   a merchant of record rather than a gateway, so every href here is still a
   placeholder and the copy never claims a payment will happen. */

.give {
  margin-top: 34px;
}

.give-when {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-control);
  background-color: color-mix(in srgb, var(--color-ink) 7%, transparent);
}

.give-tab {
  padding: 8px 18px;
  border: 0;
  border-radius: var(--radius-badge);
  background: none;
  color: var(--color-ink-body);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-out-soft);
}

.give-tab.is-on {
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-ink) 9%, transparent);
  color: var(--color-ink);
  font-weight: 600;
}

.give-amounts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
}

.give-amount {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 78px;
  padding: 13px 20px;
  border: 0;
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-ink) 10%, transparent);
  color: var(--color-ink);
  font-family: inherit;
  font-size: 17px;
  font-weight: 500;
  cursor: pointer;
  transition:
    box-shadow var(--motion-fast) var(--ease-out-soft),
    transform var(--motion-fast) var(--ease-out-soft);
}

.give-amount:hover {
  transform: translateY(-1px);
}

.give-amount[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--color-ink);
}

.give-other {
  min-width: 0;
  font-size: 15px;
  color: var(--color-ink-body);
}

.give-go {
  margin-top: 24px;
}

/* The tag is the honest part: it is inside the button, so there is no way to
   read the label without reading it too. Honey on ink is the one pairing the
   system already uses for "the app wants you to know something". */
.give-cta {
  gap: 12px;
  border: 0;
  font-family: inherit;
  cursor: pointer;
}

.give-soon-tag {
  padding: 3px 9px;
  border-radius: var(--radius-badge);
  background-color: var(--color-draw-honey);
  color: var(--color-ink);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.give-note {
  margin-top: 14px;
  max-width: 44ch;
  color: var(--color-ink-muted);
  font-size: 14px;
  line-height: 1.55;
  text-wrap: pretty;
}

.give-soon {
  max-width: 54ch;
  margin-top: 22px;
  padding: 22px 24px 24px;
  border-radius: var(--radius-block);
  background-color: color-mix(in srgb, var(--color-surface) 62%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-ink) 9%, transparent);
  animation: drop-open var(--motion-base) var(--ease-out-soft);
}

.give-soon p {
  color: var(--color-ink-body);
  font-size: 15px;
  line-height: 1.6;
  text-wrap: pretty;
}

.give-soon p + p {
  margin-top: 14px;
}

.give-soon-go {
  margin-top: 20px;
}

.give-soon .button-secondary {
  background-color: var(--color-surface);
  color: var(--color-ink);
}

.give-soon .button-secondary:hover {
  background-color: #fffaf0;
}

/* --- what it pays for --------------------------------------------------- */

.support-side {
  position: relative;
  padding-top: 8px;
}

.support-beady {
  width: 108px;
  aspect-ratio: 1020 / 1140;
  margin-bottom: 22px;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  cursor: pointer;
}

.funds {
  display: grid;
  gap: 16px;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}

.funds li {
  padding-bottom: 16px;
  border-bottom: 1px solid color-mix(in srgb, var(--color-ink) 12%, transparent);
  color: var(--color-ink-body);
  font-size: 15px;
  line-height: 1.5;
  text-wrap: pretty;
}

.funds li:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.funds strong {
  display: block;
  color: var(--color-ink);
  font-weight: 500;
}

.support-thanks {
  max-width: 44ch;
  margin-top: 22px;
  color: var(--color-ink-muted);
  font-size: 14px;
  line-height: 1.6;
  text-wrap: pretty;
}

/* ----------------------------------------------------------------- the FAQ */

.faq {
  border-top: 1px solid var(--color-ring);
}

.faq details {
  border-bottom: 1px solid var(--color-ring);
}

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 22px 0;
  font-size: 17px;
  cursor: pointer;
  list-style: none;
}

.faq summary::-webkit-details-marker {
  display: none;
}

/* The chevron is drawn here for the reason the app draws its own: the native
   one is a different weight from every other mark in the interface and
   changes shape between platforms. */
.faq summary::after {
  content: "";
  flex: none;
  width: 11px;
  height: 11px;
  margin-right: 4px;
  border-right: 1.75px solid var(--color-ink-muted);
  border-bottom: 1.75px solid var(--color-ink-muted);
  transform: translateY(-3px) rotate(45deg);
  transition: transform var(--motion-base) var(--ease-out-soft);
}

.faq details[open] summary::after {
  transform: translateY(2px) rotate(-135deg);
}

.faq details p {
  max-width: 76ch;
  padding: 0 0 24px;
  color: var(--color-ink-body);
  font-size: 15px;
  line-height: 1.6;
  text-wrap: pretty;
  animation: drop-open var(--motion-base) var(--ease-out-soft);
}

@keyframes drop-open {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
}

/* ---------------------------------------------------------- the closing */

/* The page used to stop at the FAQ, which is a strange note to end on: the
   last thing anybody read was a list of caveats. */
.band-close {
  padding-top: 24px;
  text-align: center;
}

.close-inner {
  max-width: 820px;
  margin: 0 auto;
  padding: 64px 32px 68px;
  border-radius: var(--radius-block);
  background-color: var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-ring);
}

@media (max-width: 619px) {
  .close-inner {
    padding: 44px 22px 48px;
  }
}

.close-title {
  margin: 0 auto;
  max-width: 18ch;
  font-size: clamp(30px, 4vw, 46px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

.close-say {
  max-width: 46ch;
  margin: 18px auto 0;
  color: var(--color-ink-body);
  font-size: 17px;
  line-height: 1.55;
}

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

/* -------------------------------------------------------------- the footer */

.foot {
  margin-top: 40px;
  border-top: 1px solid var(--color-ring);
}

.foot-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
  max-width: 1320px;
  margin: 0 auto;
  padding: 40px 24px 56px;
}

.foot-name {
  display: flex;
  align-items: center;
  gap: 14px;
}

.foot-beady {
  width: 56px;
  aspect-ratio: 1020 / 1140;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  cursor: pointer;
}

.foot-word {
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.2px;
}

.foot-line {
  color: var(--color-ink-muted);
  font-size: 14px;
}

.foot-links {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
}

.foot-end {
  text-align: right;
}

@media (max-width: 719px) {
  .foot-end {
    text-align: left;
  }
}

.foot-made {
  color: var(--color-ink-body);
  font-size: 14px;
}

.foot-ver {
  margin-top: 4px;
  color: var(--color-ink-muted);
  font-size: 13px;
}

/* ------------------------------------------------- the bands arrive as well */

/* Gated on the attribute the script sets on <html>, so a page whose script
   never runs is a page you can still read rather than an empty column. */
html[data-anim] [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 560ms var(--ease-out-soft),
    transform 560ms var(--ease-out-soft);
}

html[data-anim] [data-reveal].in-view {
  opacity: 1;
  transform: none;
}

.steps [data-reveal]:nth-child(2) {
  transition-delay: 90ms;
}

.steps [data-reveal]:nth-child(3) {
  transition-delay: 180ms;
}
