/*
 * The landing page.
 *
 * The layout and palette come from `Invoice Koi - Landing Page.dc.html` on the
 * design canvas; the *content* does not, because the artboard was drawn before
 * anybody checked it against the app. What it claimed and what ships are
 * reconciled in `index.html`; see the note at the top of that file.
 *
 * Three things here are the app's own rather than the artboard's:
 *
 *   - the marks, inlined from `assets/marks/koi-sprite.svg` (the "Tail &
 *     Ripple" set) instead of the artboard's squares and circles;
 *   - the phone, which now plays `video/dist`'s App Store preview rather than
 *     a hand-drawn Home screen that had the wrong tabs on it;
 *   - the palette, which was already `src/theme.ts`.
 *
 * The canvas draws one 1440px artboard with every rule inline. A website is
 * not an artboard, so the rules are classes and the bands stack at 1080px and
 * again at 760px. Nothing is loaded that the strict policy in `vercel.json`
 * would refuse: no inline styles, no third-party anything but the two Google
 * Fonts origins.
 *
 * Light only, deliberately: the hero wash is a dark teal in both of the app's
 * palettes, and a marketing page that flipped underneath it would fight itself.
 */

:root {
  --ink: #101418;
  --paper: #F7F5F1;
  --sand: #EDE9E2;
  --card: #FBF9F6;

  --red: #E4401F;
  --red-dark: #C2340F;
  --beni: #93231A;
  --salmon: #F08C79;

  --asagi: #2E6C88;
  --mist: #C8DCE4;
  --sky: #8FC4DA;
  --gold: #B8862F;

  --deep: linear-gradient(168deg, #153741, #0B1A20 62%, #081216);

  /*
   * The app's dark palette, from `DARK` in `src/theme.ts`, and used by the
   * phone in section 02 and nothing else on this page.
   *
   * There were eleven of these when the six screens in the phone were drawn in
   * CSS rather than photographed. The photographs carry their own colour, so
   * what is left is the ground the picture sits on while it loads and the five
   * swatches the revenue ring was read by.
   *
   * The page around the phone stays light on purpose: the hero wash is a dark
   * teal in both of the app's own palettes, so a marketing page that flipped
   * underneath it would fight itself. What the phone shows is the app, and the
   * app in the dark is what a trade actually has on a phone at five in the
   * afternoon in November.
   */
  --scr-paper: #0A1418;
  --scr-red: #FF6A47;
  --scr-asagi: #7FB6D0;
  --scr-gold: #D6A748;
  --scr-stone: #93A0A7;
  --scr-midnight: #9DC4D4;

  --serif: "Instrument Serif", Georgia, "Times New Roman", serif;
  --sans: "Schibsted Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --pad: 72px;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: var(--red); text-decoration: none; }
a:hover { color: #B83013; }

.wrap { max-width: 1440px; margin: 0 auto; }
.mono { font-family: var(--mono); }

/*
 * The parts of the invoice are toggled with the `hidden` attribute and several
 * of them carry a `display` of their own, an author rule, so it beats the user
 * agent's `[hidden]` and they would all show at once. This puts it back in
 * charge.
 */
[hidden] { display: none !important; }

/* ── the marks ────────────────────────────────────────────────────── */

/*
 * One drawing per `<use>`, from the sprite inlined at the top of the document.
 * The symbols carry their own stroke width and caps and paint from
 * `currentColor`, so a mark takes the colour of the tile it sits in.
 */
.mark {
  width: var(--mark, 22px);
  height: var(--mark, 22px);
  display: block;
  flex: none;
  color: inherit;
}

/* ── the koi mark ─────────────────────────────────────────────────── */

/*
 * The logo, at four sizes. The parts are placed in per cent rather than pixels
 * so the same three elements draw the 38px mark in the masthead and the 26px
 * one inside the download button.
 */
.koi {
  position: relative;
  width: var(--koi, 38px);
  height: var(--koi, 38px);
  border-radius: 50%;
  background: var(--red);
  overflow: hidden;
  flex: none;
  display: block;
}
.koi i { position: absolute; font-style: normal; }
.koi .body {
  left: 10.5%; bottom: 10.5%; width: 50%; height: 50%;
  background: var(--card);
  border-radius: 50% 50% 50% 2px;
}
.koi .eye {
  right: 20.5%; top: 26%; width: 16%; height: 16%;
  background: var(--ink);
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px rgba(251, 249, 246, .85);
}
.koi--lit { box-shadow: 0 8px 22px -8px rgba(228, 64, 31, .8); }

/*
 * The masthead's koi sculls, once every five and a half seconds.
 *
 * Only the body moves, and it turns about its own head rather than about the
 * middle of the disc. The head is the top right of that element, under the
 * eye, and the tail is the sharp corner the `2px` in the body's radius draws
 * at the bottom left. Pivoting there swings the tail and leaves the head where
 * it is, which is what a fish holding station in water actually does; pivoting
 * about the centre would swing the head as well and read as the logo rocking.
 *
 * The eye is deliberately left out of it. It belongs to the head, and the head
 * is the part that is not moving.
 *
 * `koi-scull` is a flick and a decay rather than a sine, and more than half of
 * it is the fish holding still afterwards. A symmetrical wobble at a constant
 * rate is a metronome, and a metronome in the corner of a page is the kind of
 * motion a reader ends up watching instead of reading.
 *
 * Masthead only. The same mark is in the download button, the run button and
 * the footer, and three more of these would be three things moving on a page
 * that now has plenty.
 */
.koi--lit .body {
  transform-origin: 88% 12%;
  animation: koi-scull 5.5s ease-out infinite;
}
.koi-34 { --koi: 34px; }
.koi-26 { --koi: 26px; }

/* ── motion ───────────────────────────────────────────────────────── */

@keyframes koi-shimmer {
  0%   { transform: translateX(-12%); }
  50%  { transform: translateX(12%); }
  100% { transform: translateX(-12%); }
}
@keyframes koi-swim {
  0%   { transform: translate(0, 0) rotate(-5deg); }
  50%  { transform: translate(26px, -18px) rotate(4deg); }
  100% { transform: translate(0, 0) rotate(-5deg); }
}
@keyframes koi-scull {
  0%   { transform: rotate(0deg); }
  6%   { transform: rotate(-5.5deg); }
  17%  { transform: rotate(3.5deg); }
  29%  { transform: rotate(-1.6deg); }
  40%  { transform: rotate(.5deg); }
  50%  { transform: rotate(0deg); }
  100% { transform: rotate(0deg); }
}
@keyframes koi-in {
  0%   { opacity: 0; transform: translateY(7px); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes koi-ripple {
  0%   { transform: scale(.4); opacity: .7; }
  100% { transform: scale(2.2); opacity: 0; }
}
@keyframes koi-stamp {
  0%   { opacity: 0; transform: rotate(-14deg) scale(1.5); }
  60%  { opacity: 1; transform: rotate(-9deg) scale(.96); }
  100% { opacity: 1; transform: rotate(-9deg) scale(1); }
}

/* ── shared type ──────────────────────────────────────────────────── */

.eyebrow {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(16, 20, 24, .45);
}
.eyebrow .n { letter-spacing: 0; text-transform: none; color: var(--red); }

.display {
  margin: 16px 0 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(40px, 5.4vw, 68px);
  line-height: 1;
  letter-spacing: -.02em;
}

.lede {
  font-size: 16.5px;
  line-height: 1.6;
  color: rgba(16, 20, 24, .66);
  text-wrap: pretty;
}

/* ── hero ─────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  background: var(--deep);
  color: var(--paper);
  overflow: hidden;
  padding: 0 0 96px;
}

/*
 * The landing hero, and only that one: every other page on the site is a
 * `.hero` too, and a page whose hero is a heading and a paragraph has no
 * business being a screen tall.
 *
 * `100svh` rather than `100vh` because on a phone `vh` is the viewport with
 * the address bar already gone, which is a hero that starts a bar's worth
 * below the fold and only fits once you have scrolled. `min-height` rather
 * than `height` because under 1080px the phone drops below the words and the
 * section is taller than the screen whatever this says.
 *
 * The masthead keeps its own height and the grid takes the rest, so the
 * spare space on a tall monitor goes between the words and the top of the
 * screen rather than under the phone.
 */
.home-hero {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}
.home-hero > .wrap {
  display: flex;
  flex-direction: column;
  flex: 1;
  width: 100%;
}
.home-hero .hero-grid { flex: 1; }
.home-hero h1 { font-size: clamp(48px, 6vw, 86px); }
/*
 * The pond, under everything else in the hero.
 *
 * `cover` rather than `contain` or a fixed size: the section is about 1.43:1
 * at the 1440px this page is drawn against and nearer 1.9:1 on a wide monitor,
 * so one of the two axes is always spare. The composition is drawn knowing
 * that and keeps the koi away from the edges.
 *
 * Called `pond-film` rather than `pond` because `.pond` was already taken, by
 * the 64 px disc in section 01 that the invoice animation draws its ripple in.
 * The first cut of this did call it `.pond`, and since that rule is `opacity:
 * 0` until the film plays, and the disc never plays anything, section 01's
 * decoration quietly disappeared.
 *
 * Three elements use this: the hero, and the two dark bands at sections 03 and
 * 05. They are not the same shape, which is why there are two films, but they
 * sit in their sections the same way.
 *
 * It starts invisible and `landing.js` fades it up on the first frame that
 * actually plays. Painting it at full strength the moment the element exists
 * shows a black rectangle over the wash for as long as the first frame takes
 * to arrive, and on a slow connection that is most of a second of the hero
 * being the wrong colour.
 */
.pond-film {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.4s ease;
}
.pond-film.up { opacity: 1; }

/*
 * The wash on the two dark bands, once there is a film under it.
 *
 * Half strength rather than off. It is one soft radial in the top right of
 * each section and the film has light of its own, so at full strength the two
 * stack into a bright corner that neither was drawn to make.
 */
.keep.wet .wash { opacity: .5; }

.hero .wash {
  position: absolute;
  inset: -30% -10%;
  background:
    radial-gradient(ellipse 50% 34% at 22% 20%, rgba(200, 220, 228, .14), transparent 70%),
    radial-gradient(ellipse 42% 30% at 78% 66%, rgba(46, 108, 136, .34), transparent 70%);
  animation: koi-shimmer 14s ease-in-out infinite;
  pointer-events: none;
}
/*
 * The one blob left, and only on the inner pages.
 *
 * It is a soft koi-shaped thing drifting through the wash, drawn in CSS
 * because in an artboard that was the only way to have any. The landing hero
 * had two of them, one hung off each side, and over the film they stopped
 * reading as shapes under the water and started reading as shadows on the
 * frame. That hero has a real pond in it now, so it does not need them. The
 * inner pages have the wash and nothing else, and there the drift is the only
 * thing keeping the gradient from being a plain sweep.
 */
.hero .blob-a {
  position: absolute;
  pointer-events: none;
  left: -160px; top: -190px; width: 720px; height: 560px;
  border-radius: 60% 40% 55% 45% / 50% 60% 40% 50%;
  background: var(--red); opacity: .15;
  animation: koi-swim 22s ease-in-out infinite;
}

.masthead {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 30px var(--pad) 0;
}
.wordmark {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--paper);
  font-family: var(--serif);
  font-size: 25px;
  letter-spacing: -.01em;
}
.wordmark:hover { color: var(--paper); }

.masthead nav {
  display: flex;
  align-items: center;
  gap: 34px;
  font-size: 14.5px;
  font-weight: 500;
}
.masthead nav a { color: rgba(200, 220, 228, .82); }
.masthead nav a:hover { color: var(--paper); }
.nav-cta {
  display: flex;
  align-items: center;
  height: 42px;
  padding: 0 20px;
  border-radius: 21px;
  background: rgba(200, 220, 228, .14);
  border: 1px solid rgba(200, 220, 228, .2);
  color: var(--paper) !important;
  font-weight: 600;
}
.nav-cta:hover { background: rgba(200, 220, 228, .24); }

.hero-grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;
  gap: 40px;
  align-items: center;
  padding: 76px var(--pad) 0;
}

.hero h1 {
  margin: 22px 0 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(52px, 7.2vw, 104px);
  line-height: .92;
  letter-spacing: -.025em;
}
.hero h1 em { font-style: italic; color: var(--salmon); }

.hero-lede {
  margin: 26px 0 0;
  max-width: 520px;
  font-size: 18px;
  line-height: 1.6;
  color: rgba(200, 220, 228, .8);
  text-wrap: pretty;
}

.hero-cta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 34px;
}
.btn-download {
  display: flex;
  align-items: center;
  gap: 13px;
  height: 60px;
  padding: 0 28px;
  border-radius: 30px;
  background: var(--red);
  color: #fff !important;
  font-size: 16.5px;
  font-weight: 600;
  box-shadow: 0 18px 40px -16px rgba(147, 35, 26, .85), inset 0 1px 0 rgba(255, 255, 255, .3);
}
.btn-download:hover { background: var(--red-dark); }

.evidence-strip {
  background: var(--card);
  border-bottom: 1px solid rgba(16, 20, 24, .1);
}
.evidence-strip .wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0;
  padding: 19px var(--pad);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .05em;
  color: rgba(16, 20, 24, .68);
}
.evidence-strip span { display: flex; align-items: center; }
.evidence-strip span + span::before {
  content: "";
  width: 4px;
  height: 4px;
  margin: 0 18px;
  border-radius: 50%;
  background: var(--red);
}

/*
 * The second way in. The App Store is one button; the browser generator is the
 * other, and it is the only one that pays off without an install, so it is a
 * quiet outline rather than a second red.
 */
.btn-ghost {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 60px;
  padding: 0 26px;
  border-radius: 30px;
  border: 1px solid rgba(200, 220, 228, .26);
  color: var(--mist) !important;
  font-size: 16.5px;
  font-weight: 600;
}
.btn-ghost:hover { background: rgba(247, 245, 241, .1); color: var(--paper) !important; }
.btn-ghost .mark { --mark: 19px; color: var(--salmon); }

/* Inside the button the mark is inverted: pale disc, red fish. */
.btn-download .koi { background: var(--card); }
.btn-download .koi .body { background: var(--red); }

.stats {
  display: flex;
  align-items: center;
  gap: 30px;
  margin-top: 46px;
  padding-top: 26px;
  border-top: 1px solid rgba(200, 220, 228, .16);
}
.stats .fig {
  font-family: var(--mono);
  font-size: 26px;
  font-weight: 500;
  letter-spacing: -.02em;
}
.stats .cap {
  font-size: 12.5px;
  color: rgba(200, 220, 228, .58);
  margin-top: 2px;
}
.stats .rule { width: 1px; height: 38px; background: rgba(200, 220, 228, .16); flex: none; }

/* ── the phone, playing the film ──────────────────────────────────── */

.phone-slot {
  position: relative;
  width: 400px;
  height: 760px;
  flex: none;
  justify-self: center;
}
.phone-scale {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%) scale(.83);
  transform-origin: top center;
}
.phone {
  position: relative;
  width: 393px;
  height: 812px;
  border-radius: 60px;
  background: #0C0E11;
  padding: 11px;
  box-shadow: 0 50px 90px -34px rgba(0, 0, 0, .8), inset 0 0 0 1.5px rgba(200, 220, 228, .24);
}
.screen {
  position: relative;
  width: 371px;
  height: 790px;
  border-radius: 50px;
  overflow: hidden;
  background: var(--paper);
}
/* The six screens are the app in the dark, so the glass behind them is too. */
#shoal-screen { background: var(--scr-paper); }
/*
 * The film is 886×1920, 0.461 against the screen's 0.470, so `cover` trims a
 * few pixels off the top and bottom rather than letterboxing the sides.
 */
.film {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--paper);
}
.island {
  position: absolute;
  left: 50%;
  top: 10px;
  transform: translateX(-50%);
  width: 110px;
  height: 32px;
  border-radius: 18px;
  background: #000;
  z-index: 2;
}

.film-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 22px;
}
.film-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 16px;
  border-radius: 19px;
  border: 1px solid rgba(200, 220, 228, .22);
  background: rgba(247, 245, 241, .08);
  color: var(--mist);
  font-family: var(--mono);
  font-size: 12px;
  cursor: pointer;
}
.film-btn:hover { background: rgba(247, 245, 241, .16); color: var(--paper); }
.film-btn .mark { --mark: 15px; }

/* ── 01 · the invoice ─────────────────────────────────────────────── */

.forty {
  position: relative;
  background: var(--paper);
  padding: 110px var(--pad) 120px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 520px;
  gap: 72px;
  align-items: start;
}
.forty .lede { margin: 20px 0 0; max-width: 440px; }

.run {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 32px;
  height: 56px;
  padding: 0 28px;
  border: 0;
  border-radius: 28px;
  background: var(--ink);
  color: var(--paper);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  box-shadow: 0 16px 34px -18px rgba(16, 20, 24, .8);
}
.run:hover { background: #1D242B; }
.run .mark { --mark: 18px; color: var(--salmon); }

.beats {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-top: 44px;
  background: rgba(16, 20, 24, .1);
  border-radius: 14px;
  overflow: hidden;
}
.beat {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 20px;
  background: var(--card);
}
.beat .mark { --mark: 20px; color: var(--asagi); }
.beat .said { font-size: 14.5px; font-weight: 500; }

/* the paper */

.paper-slot { position: relative; width: 520px; flex: none; justify-self: center; }
.paper {
  position: relative;
  background: #fff;
  border-radius: 20px;
  border: 1px solid rgba(16, 20, 24, .1);
  box-shadow: 0 40px 80px -44px rgba(16, 20, 24, .4);
  padding: 38px 40px 40px;
  min-height: 560px;
  overflow: hidden;
}
/*
 * The foot of the sheet, where the invoice stops being a page and becomes a
 * file with somewhere to go, is absolutely positioned: the card takes its full
 * height the moment the button is pressed rather than growing under the reader
 * three more times, and `written` is what reserves the room. The artboard left
 * that to the card's fixed height and real text metrics run taller, so the
 * reserve is measured instead.
 */
.paper.written { padding-bottom: 186px; }

.paper-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; }
.paper-from { display: flex; align-items: center; gap: 9px; font-family: var(--serif); font-size: 21px; }
.paper-role { font-size: 12.5px; color: rgba(16, 20, 24, .5); margin-top: 6px; }
.paper-no { text-align: right; }
.tag {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(16, 20, 24, .4);
}
.paper-no .tag { font-size: 11px; }
.paper-no .v { font-family: var(--mono); font-size: 15px; margin-top: 4px; }
.paper hr { height: 1px; border: 0; background: rgba(16, 20, 24, .1); margin: 26px 0 24px; }

.step { animation: koi-in .38s ease both; }

.billed { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; }
.billed .to { font-size: 19px; font-weight: 600; margin-top: 5px; }
.billed .mail { font-size: 13px; color: rgba(16, 20, 24, .55); margin-top: 2px; }
.billed .due { text-align: right; }
.billed .due .v { font-family: var(--mono); font-size: 14px; margin-top: 5px; }

.lines { display: flex; flex-direction: column; margin-top: 26px; }
.line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 13px 0;
  border-top: 1px solid rgba(16, 20, 24, .08);
}
.line .what { font-size: 15px; font-weight: 500; }
.line .rate { font-family: var(--mono); font-size: 12px; color: rgba(16, 20, 24, .5); margin-top: 3px; }
.line .sum { font-family: var(--mono); font-size: 16px; }

.totals { margin-top: 22px; padding-top: 20px; border-top: 1px solid rgba(16, 20, 24, .14); }
.totals .row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 14px;
  color: rgba(16, 20, 24, .6);
  margin-bottom: 10px;
}
.totals .grand { display: flex; align-items: baseline; justify-content: space-between; margin-top: 14px; }
.totals .grand .l { font-family: var(--serif); font-size: 26px; color: var(--ink); }
.totals .grand .v {
  font-family: var(--mono);
  font-size: 30px;
  font-weight: 500;
  letter-spacing: -.02em;
}

/*
 * The outbox: the file, the doors it can leave by, and the stamp.
 *
 * Ruled off from the totals because it is no longer the document. Everything
 * above the rule is what the client is being asked to pay; everything below it
 * is what happens to the page once that is settled.
 */
/* Nothing at the foot of a sheet nobody has written on yet: an idle card
   showing a rule and two blank rows is furniture for a room with no one in
   it. `written` is the same switch that reserves the room above. */
.outbox { display: none; }
.paper.written .outbox {
  display: flex;
  position: absolute;
  left: 40px;
  right: 40px;
  bottom: 32px;
  padding-top: 20px;
  border-top: 1px solid rgba(16, 20, 24, .14);
  flex-direction: column;
  gap: 18px;
  /*
   * Held at the height of all three rows, because the band is pinned by its
   * bottom edge and the rows arrive one beat at a time. Without this the rule
   * and the filename start low and are shoved upwards as the doors and the
   * stamp turn up, which is the one part of the run that should be still. A
   * minimum rather than a fixed height, so a font that renders taller grows
   * the band instead of being cut off by it.
   */
  min-height: 119px;
  justify-content: flex-start;
}

/* Room kept clear on the right for the stamp, which lands over this row. */
.file { display: flex; align-items: center; gap: 12px; padding-right: 128px; }
.file .mark { --mark: 21px; color: var(--red); flex: none; }
.file .fname { font-family: var(--mono); font-size: 14px; }

.doors { display: flex; align-items: flex-start; }

.ways { display: flex; gap: 12px; margin: 0; padding: 0; list-style: none; }

/*
 * Four doors, all four of them open, and a ring round the one this invoice
 * went out by.
 *
 * They are drawn at full colour rather than greyed with the taken one lit,
 * which was the first attempt: three faded tiles read as three apps this phone
 * has not got, and all four of these work. Only the ring and the weight of the
 * word under it say which was chosen.
 *
 * A tick on the taken tile would have been the livelier mark and it is the
 * wrong one. On a WhatsApp tile a tick means delivered, and nothing in the app
 * knows whether anything was delivered: it hands the file to another app and
 * stops there. Being the route taken is all this can honestly say.
 */
.way {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  width: 58px;
}

/*
 * They arrive one after another rather than as a block, which is the
 * difference between a row of apps opening and a picture of a row of apps.
 *
 * Delays rather than durations, so this is nested in a `no-preference` query:
 * the reduced-motion rule at the foot of this file flattens every duration and
 * leaves delays alone, which would hold the last two tiles off the page for a
 * fifth of a second for exactly the reader who asked for less of this.
 */
@media (prefers-reduced-motion: no-preference) {
  .way { animation: koi-in .34s ease both; }
  .way:nth-child(2) { animation-delay: .07s; }
  .way:nth-child(3) { animation-delay: .14s; }
  .way:nth-child(4) { animation-delay: .21s; }
}
.tile {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
}
/* A ring held off the tile by the sheet's own white, so it reads as a ring
   round a square rather than a glow leaking out of one. */
.way.taken .tile { box-shadow: 0 0 0 3px #fff, 0 0 0 5px rgba(228, 64, 31, .45); }
.way .who { font-size: 11px; color: rgba(16, 20, 24, .62); }
.way.taken .who { color: var(--ink); font-weight: 500; }

/*
 * The two trademarks sit on the colour their owner publishes, which is also
 * what every share sheet on the phone already shows. theme-exempt.
 *
 * Their marks are sized against the tile the way `src/brands.ts` sizes them
 * against its own: the WhatsApp glyph is drawn to the edge of its box and the
 * Telegram plane is not, so the two numbers differ to make one size.
 */
.wa .tile { background: #25D366; }
.tg .tile { background: #229ED9; }
/* No trademark for the phone's own messages, and no green either: that is
   WhatsApp's square two along. Ink, so the row reads green, blue, dark, red. */
.sms .tile { background: rgba(16, 20, 24, .74); }
.mail .tile { background: var(--red); }
.wa .tile .mark { --mark: 24px; }
.tg .tile .mark { --mark: 26px; }
.sms .tile .mark, .mail .tile .mark { --mark: 23px; }

.stamp-slot {
  position: absolute;
  right: 0;
  top: 12px;
  animation: koi-stamp .5s cubic-bezier(.2, 1.4, .5, 1) both;
}
.stamp {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 20px;
  border: 2.5px solid var(--red);
  border-radius: 8px;
  color: var(--red);
  font-family: var(--mono);
  font-size: 15px;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.stamp .mark { --mark: 17px; }

.still {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 90px 0 60px;
  text-align: center;
}
.pond { position: relative; width: 64px; height: 64px; border-radius: 50%; background: rgba(228, 64, 31, .1); }
.pond .ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid rgba(228, 64, 31, .4);
  animation: koi-ripple 2.6s ease-out infinite;
}
/*
 * The fish in the still water is the logo itself, not a shape that resembles
 * it. What sat here before was the body without the eye and in red on pale
 * rather than pale on red, which is the mark with the two things that make it
 * a fish taken out of it.
 */
.pond .koi {
  position: absolute;
  left: 50%; top: 50%;
  margin: calc(var(--koi) / -2) 0 0 calc(var(--koi) / -2);
}
.still .t {
  font-family: var(--serif);
  font-style: italic;
  font-size: 24px;
  color: rgba(16, 20, 24, .55);
}
.still .s { font-size: 13.5px; color: rgba(16, 20, 24, .45); }

/* ── 02 · features ────────────────────────────────────────────────── */

.features { background: var(--sand); padding: 110px var(--pad) 120px; }
.features-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 40px;
}

/*
 * A card is what the six used to be, and `.feature` is what is left of that:
 * the band at the top of this section and the three cards on every trade page
 * still want one. The five that used to be cards are buttons around a phone
 * now, further down.
 */
.feature {
  grid-column: span 4;
  background: var(--card);
  border: 1px solid rgba(16, 20, 24, .1);
  border-radius: 18px;
  padding: 22px 22px 26px;
  transition: border-color .2s ease;
}
.feature:hover { border-color: rgba(228, 64, 31, .45); }
.tpl { grid-column: 1 / -1; margin-top: 52px; }
.feature .eyebrow {
  align-items: center;
  gap: 9px;
  margin-top: 22px;
  font-size: 10.5px;
}
.feature .eyebrow .mark { --mark: 16px; }
.m-red { color: var(--red); }
.m-asagi { color: var(--asagi); }
.m-gold { color: var(--gold); }
.m-mist { color: var(--mist); }
.feature h3 {
  font-size: 19.5px;
  font-weight: 600;
  margin: 10px 0 0;
  letter-spacing: -.01em;
}
.feature p {
  margin: 9px 0 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: rgba(16, 20, 24, .62);
  text-wrap: pretty;
}

.feature.dark { background: var(--ink); color: var(--paper); }
.feature.dark:hover { border-color: rgba(16, 20, 24, .1); }
.feature.dark p { color: rgba(200, 220, 228, .72); }
.feature.dark .eyebrow { color: rgba(200, 220, 228, .5); }

/* ── the band across the top: the nine documents ──────────────────── */

/*
 * Nine sheets on a rail, not one sheet behind nine buttons.
 *
 * The picker version showed a single design and asked the reader to press a
 * name to see any other, which is a click for something that costs nothing to
 * look at, and the eight nobody pressed were never seen at all. `/templates/`
 * had already answered this with a rail, so this is that rail with the
 * paragraph about the pond taken out: the sheet on its dark wash, the drawing
 * of the fish it is named after, the name, and one line saying what the design
 * does on paper.
 *
 * Snap on the inline axis so a flick lands on a card rather than between two,
 * and the rail bleeds to the card's own padding on both sides with
 * `scroll-padding` matching it, so a snapped slide sits under the heading
 * above rather than a gutter's width off it. `tabindex` is on the scroller
 * because a keyboard user has to be able to reach a scrolling region that
 * holds nothing else focusable, and Firefox will not focus one without it.
 */

.tpl {
  display: block;
  padding: 26px;
}
.tpl-copy { max-width: 620px; }
.tpl h3 { font-size: 27px; margin-top: 12px; }
/*
 * 560 rather than 500 so the sentence under the heading is one line. It is one
 * sentence now, and a single line that wraps to two words is worse than either
 * a longer sentence or a wider measure.
 */
.tpl-copy > p { font-size: 16px; max-width: 560px; }

.tpl-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 20px;
  font-size: 14.5px;
  font-weight: 600;
}
.tpl-link .mark { --mark: 18px; }
.tpl-link:hover { color: var(--red-dark); }

.tpl-rail {
  margin: 28px -26px 0;
  padding: 4px 26px 16px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 26px;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(16, 20, 24, .22) transparent;
}
.tpl-rail:focus-visible { outline: 2px solid var(--asagi); outline-offset: 4px; }
.tpl-rail::-webkit-scrollbar { height: 8px; }
.tpl-rail::-webkit-scrollbar-thumb {
  background: rgba(16, 20, 24, .18);
  border-radius: 4px;
}
.tpl-rail::-webkit-scrollbar-thumb:hover { background: rgba(16, 20, 24, .3); }

.tpl-track {
  display: flex;
  gap: 20px;
  margin: 0;
  padding: 0;
  list-style: none;
  width: max-content;
}
.tpl-slide {
  scroll-snap-align: start;
  width: 300px;
}

/*
 * The document stands on a washed panel rather than in a box, and runs off the
 * bottom of it. A whole A4 page shrunk to fit a card is a grey smear; the top
 * two thirds at something near reading size is the letterhead, the client and
 * the first lines, which is the part that changes from one design to the next.
 */
.tpl-stage {
  position: relative;
  overflow: hidden;
  height: 322px;
  border-radius: 16px;
  padding: 22px 22px 0;
  /* The wash the app shows its own preview on, so the page stands out of the
     screen here the way it does on the phone. */
  background: var(--deep);
}
.sheet {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px 4px 0 0;
  box-shadow: 0 22px 44px -16px rgba(4, 10, 13, .75);
}

.tpl-face {
  display: flex;
  align-items: center;
  gap: 13px;
  margin-top: 15px;
}
/* The fish itself. Drawn on the dark ground the rest of the illustrations use,
   so it keeps its own edge on the card's near-white rather than dissolving. */
.tpl-plate {
  flex: none;
  width: 68px;
  height: 68px;
  border-radius: 12px;
  object-fit: cover;
}
.tpl-named { min-width: 0; }
.tpl-named h4 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 27px;
  line-height: 1;
  letter-spacing: -.015em;
}
.tpl-slide .tpl-gloss {
  margin: 5px 0 0;
  font-size: 13px;
  letter-spacing: .01em;
  color: var(--red);
}
.tpl-slide .tpl-said {
  margin: 12px 0 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: rgba(16, 20, 24, .58);
  text-wrap: pretty;
}

/* ── the phone, and the five things around it ─────────────────────── */

/*
 * Three buttons, a phone, two buttons: a shoal around it, which is what this
 * is called so that it is not confused with the ripple in section 01.
 *
 * The three on the left are what a trade
 * touches on the job and the two on the right are what matters at the end of
 * a quarter, which is the grouping the old grid made with column spans, said
 * with position instead.
 *
 * `--elbow` is both the gutter and the length of the hairline drawn across
 * it, because they have to be the same number and one of them should not be
 * able to change without the other. The two columns are equal and their
 * buttons are capped at the same width, so both inner edges sit the same
 * distance from the frame whatever the page is: a rule that stops short on
 * one side and overshoots on the other is worse than no rule.
 */
.shoal {
  --elbow: 54px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 338px minmax(0, 1fr);
  gap: var(--elbow);
  align-items: center;
  margin-top: 56px;
}
.shoal-col { display: grid; align-content: center; gap: 20px; }
.shoal-col--left { justify-items: end; }
.shoal-col--right { justify-items: start; }
.shoal-col > * { width: 100%; max-width: 400px; }

.callout {
  position: relative;
  display: flex;
  gap: 14px;
  text-align: left;
  padding: 18px 20px 20px;
  border-radius: 18px;
  border: 1px solid rgba(16, 20, 24, .1);
  background: var(--card);
  font-family: inherit;
  color: inherit;
  cursor: pointer;
  transition: border-color .2s ease, background-color .2s ease, box-shadow .2s ease;
}
.callout:hover { border-color: rgba(228, 64, 31, .45); }
.callout.on {
  border-color: var(--red);
  background: #fff;
  box-shadow: 0 14px 30px -22px rgba(16, 20, 24, .7);
}
.callout-mark {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(16, 20, 24, .05);
  transition: background-color .2s ease;
}
.callout.on .callout-mark { background: rgba(228, 64, 31, .1); }
.callout-mark .mark { --mark: 19px; }
.callout-said { display: block; min-width: 0; }
.callout-eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(16, 20, 24, .45);
}
.callout-h {
  display: block;
  margin-top: 8px;
  font-size: 17.5px;
  font-weight: 600;
  letter-spacing: -.01em;
}
.callout-p {
  display: block;
  margin-top: 8px;
  font-size: 14px;
  line-height: 1.6;
  color: rgba(16, 20, 24, .62);
  text-wrap: pretty;
}

/*
 * The hairline from a button to the frame, drawn in the gutter rather than
 * inside either of the things it joins. That is why it is a pseudo-element on
 * the button and why no column may ever be given an `overflow`.
 */
.callout::after {
  content: "";
  position: absolute;
  top: 50%;
  width: var(--elbow);
  height: 1px;
  background: rgba(16, 20, 24, .16);
  transition: background-color .2s ease;
}
.shoal-col--left .callout::after { left: 100%; }
.shoal-col--right .callout::after { right: 100%; }
.callout.on::after { background: var(--red); }

/*
 * The phone is the hero's, at 393 x 812, drawn at that size and scaled. The
 * stage is the size it ends up rather than the size it is laid out at, so the
 * buttons beside it are centred on the picture instead of on the empty
 * seventh of a phone that scaling leaves behind.
 *
 * The shadow is not the hero's. That one is a black drop with a pale inset
 * ring, which is a phone held against a dark pond; this one sits on sand.
 */
.shoal-stage {
  position: relative;
  width: 338px;
  height: 698px;
}
.shoal-phone {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%) scale(.86);
  transform-origin: top center;
}
.shoal-stage .phone {
  box-shadow: 0 44px 80px -44px rgba(16, 20, 24, .75), inset 0 0 0 1.5px rgba(200, 220, 228, .3);
}

/* ── the screens inside it ────────────────────────────────────────── */

/*
 * Six photographs, one on top of another, and `landing.js` unhides one.
 *
 * The screens were drawn in HTML until now, which is why so much of what
 * follows this rule describes cards and rows and meters: that markup is gone
 * from `index.html` and the rules for it are on their way out with it. What
 * arrives instead is a 742px picture of the running app in its dark palette,
 * which is what the `--scr-` tokens at the top of this file were always for.
 *
 * `cover` rather than `contain` because the picture is 402x874 points against
 * a 371x790 opening, 0.460 against 0.470: covering trims about eight points
 * off the top and the bottom, and containing would letterbox the sides of a
 * phone, which is the one thing a phone never does. The island and the home
 * indicator are in the picture, so nothing is drawn over it.
 */
.scr {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--scr-paper);
}

/*
 * The five swatches the revenue ring was read by.
 *
 * Everything else that stood here has gone with the drawn screens: the cards,
 * the rows, the figures, the meters and the read-out were the app rendered a
 * second time in CSS, and the app is photographed now instead. These five stay
 * because `.glyph g-red` on the trade pages, which load this file, is coloured
 * by the one below and by nothing else.
 *
 * `.glyph` needs its own box back. When the drawn screens went, the width, the
 * height and the radius went with them, and a swatch with no box left is a
 * background on a block that is as wide as the card: three orange bars across
 * the top of section 02 on every trade page. The badge is 44px square, and the
 * red is a tint of the accent rather than the accent itself, so the icon reads
 * as an icon rather than as a rule.
 */
.g-ink { background: var(--scr-midnight); }
.g-asagi { background: var(--scr-asagi); }
.g-gold { background: var(--scr-gold); }
.g-red { background: rgba(228, 64, 31, .12); color: var(--red); }
.g-grey { background: var(--scr-stone); }

.feature .glyph {
  width: 44px; height: 44px;
  border-radius: 13px;
  display: flex; align-items: center; justify-content: center;
  flex: none;
}
.feature .glyph .mark { --mark: 22px; }

/* ── 03 · what you keep ───────────────────────────────────────────── */

.keep {
  position: relative;
  background: var(--deep);
  color: var(--paper);
  overflow: hidden;
  padding: 104px var(--pad) 110px;
}
.keep .wash {
  position: absolute;
  inset: -30% -10%;
  background: radial-gradient(ellipse 46% 32% at 74% 30%, rgba(46, 108, 136, .32), transparent 70%);
  animation: koi-shimmer 16s ease-in-out infinite;
  pointer-events: none;
}
.keep-grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 470px;
  gap: 80px;
  align-items: center;
}
.keep .eyebrow { color: rgba(200, 220, 228, .5); }
.keep h2 {
  margin: 16px 0 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(42px, 5.6vw, 72px);
  line-height: 1;
  letter-spacing: -.02em;
}
.keep h2 em { font-style: italic; color: var(--salmon); }
.keep p.lede {
  margin: 22px 0 0;
  max-width: 470px;
  line-height: 1.65;
  color: rgba(200, 220, 228, .78);
}

.keep-slot { position: relative; width: 470px; flex: none; justify-self: center; }
.keep-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: rgba(247, 245, 241, .06);
  border: 1px solid rgba(200, 220, 228, .18);
  border-radius: 20px;
  padding: 10px;
  backdrop-filter: blur(2px);
}
.keep-row {
  display: flex;
  align-items: flex-start;
  gap: 15px;
  padding: 18px;
  border-radius: 14px;
}
.keep-row + .keep-row { border-top: 1px solid rgba(200, 220, 228, .1); }
.keep-row .glyph {
  width: 40px; height: 40px;
  border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  flex: none;
  background: rgba(200, 220, 228, .12);
  color: var(--sky);
}
.keep-row .glyph .mark { --mark: 21px; }
.keep-row .t { font-size: 15.5px; font-weight: 600; }
.keep-row .d {
  font-size: 13px;
  line-height: 1.55;
  color: rgba(200, 220, 228, .68);
  margin-top: 3px;
  text-wrap: pretty;
}

/* ── 04 · pricing ─────────────────────────────────────────────────── */

/* ── 05 · questions ───────────────────────────────────────────────── */

/*
 * The same three-column grid the trade pages use for theirs, so the two look
 * like one site. It sits on `.keep`, which supplies the dark ground.
 */
.asked .wrap { position: relative; }
.faq {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 34px 30px;
  margin-top: 48px;
}
.faq-row h3 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--paper);
}
.faq-row p {
  margin: 10px 0 0;
  font-size: 14.5px;
  line-height: 1.62;
  color: rgba(200, 220, 228, .74);
  text-wrap: pretty;
}
.faq-row a { color: var(--sky); }
.faq-row a:hover { color: var(--paper); }

.pricing { background: var(--paper); padding: 110px var(--pad) 120px; }
.pricing-head { text-align: center; max-width: 680px; margin: 0 auto; }
.pricing-head .eyebrow { justify-content: center; }
.pricing-head p {
  margin: 18px 0 0;
  font-size: 16.5px;
  line-height: 1.6;
  color: rgba(16, 20, 24, .64);
  text-wrap: pretty;
}

/* Red on a grey paragraph shouts; the rule under it is what says "link". */
.pricing-head p a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(16, 20, 24, .28);
}
.pricing-head p a:hover { color: var(--red); text-decoration-color: var(--red); }

.plans {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 430px));
  justify-content: center;
  gap: 24px;
  margin: 52px auto 0;
  align-items: stretch;
}
.plan {
  border-radius: 22px;
  padding: 34px 34px 36px;
  display: flex;
  flex-direction: column;
}
.plan.free { background: var(--card); border: 1px solid rgba(16, 20, 24, .12); }
.plan .save { margin-top: 14px; font-size: 14px; color: rgba(16, 20, 24, .55); }
.plan .kind {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: rgba(16, 20, 24, .5);
}
.plan .price { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin-top: 6px; }
.plan .price .n {
  font-family: var(--mono);
  font-size: 44px;
  font-weight: 500;
  letter-spacing: -.03em;
}
.plan .price .per { font-size: 14px; color: rgba(16, 20, 24, .5); }
.plan ul {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
  font-size: 14.5px;
  line-height: 1.5;
  color: rgba(16, 20, 24, .72);
}
.plan li { display: flex; gap: 11px; }
.plan li::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(16, 20, 24, .3);
  margin-top: 8px;
  flex: none;
}
.plan .filler { flex: 1; min-height: 24px; }
.btn-plan {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  border-radius: 28px;
  border: 1.5px solid rgba(16, 20, 24, .22);
  color: var(--ink) !important;
  font-size: 16px;
  font-weight: 600;
  margin-top: 30px;
}
.btn-plan:hover { border-color: var(--ink); }

.plan.pro {
  position: relative;
  background: var(--deep);
  color: var(--paper);
  overflow: hidden;
  box-shadow: 0 40px 80px -46px rgba(8, 18, 22, .9);
}
.plan.pro .wash {
  position: absolute;
  inset: -40% -20%;
  background: radial-gradient(ellipse 50% 34% at 76% 24%, rgba(46, 108, 136, .4), transparent 70%);
  animation: koi-shimmer 15s ease-in-out infinite;
  pointer-events: none;
}
.plan.pro > *:not(.wash) { position: relative; }
.plan.pro .kind-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.plan.pro .kind { color: rgba(200, 220, 228, .7); }
.plan.pro .best {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  padding: 5px 9px;
  border-radius: 6px;
  background: var(--red);
  color: #fff;
}
.plan.pro .save { color: rgba(200, 220, 228, .62); }
.plan.pro .price .n { line-height: 1.1; }
.plan.pro .price .per { color: rgba(200, 220, 228, .6); }
.plan.pro ul { color: rgba(200, 220, 228, .85); }
.plan.pro li::before { background: var(--red); }
.btn-pro {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  border-radius: 28px;
  background: var(--red);
  color: #fff !important;
  font-size: 16px;
  font-weight: 600;
  margin-top: 30px;
  box-shadow: 0 16px 34px -16px rgba(147, 35, 26, .9), inset 0 1px 0 rgba(255, 255, 255, .3);
}
.btn-pro:hover { background: var(--red-dark); }
.billing { margin: 22px 0 0; padding: 0; border: 0; }
.billing legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.billing > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}
.billing-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 4px;
  border: 1px solid rgba(200, 220, 228, .2);
  border-radius: 14px;
  background: rgba(247, 245, 241, .06);
}
.billing-tabs label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 42px;
  padding: 6px 10px;
  border-radius: 10px;
  color: rgba(200, 220, 228, .72);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.billing-tabs label span { font-size: 9px; letter-spacing: .06em; text-transform: uppercase; }
#billing-weekly:focus-visible ~ .billing-tabs label[for="billing-weekly"],
#billing-annual:focus-visible ~ .billing-tabs label[for="billing-annual"] { outline: 2px solid var(--sky); outline-offset: 2px; }
#billing-weekly:checked ~ .billing-tabs label[for="billing-weekly"],
#billing-annual:checked ~ .billing-tabs label[for="billing-annual"] {
  background: var(--card);
  color: var(--ink);
}
.billing-price { display: none !important; }
#billing-weekly:checked ~ .billing-prices .billing-weekly,
#billing-annual:checked ~ .billing-prices .billing-annual { display: flex !important; }
.billing-prices .price { margin-top: 18px; }

/* ── footer ───────────────────────────────────────────────────────── */

.site-footer { background: var(--ink); color: var(--paper); padding: 72px var(--pad) 56px; }
.footer-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 60px;
  padding-bottom: 44px;
  border-bottom: 1px solid rgba(200, 220, 228, .14);
}
.footer-about { max-width: 400px; }
.footer-about p {
  margin: 16px 0 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: rgba(200, 220, 228, .6);
  text-wrap: pretty;
}
.footer-about .wordmark { font-size: 23px; }
.footer-cols { display: flex; gap: 72px; font-size: 14px; }
.footer-col { display: flex; flex-direction: column; gap: 11px; }
.footer-col .tag { font-size: 10.5px; color: rgba(200, 220, 228, .4); }
.footer-col a { color: rgba(200, 220, 228, .75); }
.footer-col a:hover { color: var(--paper); }
.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-top: 26px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: rgba(200, 220, 228, .45);
}

/* ── narrower than the artboard ───────────────────────────────────── */

@media (max-width: 1200px) {
  :root { --pad: 44px; }
  .forty { grid-template-columns: minmax(0, 1fr) 440px; gap: 48px; }
  .paper-slot { width: 440px; }
  .keep-grid { grid-template-columns: minmax(0, 1fr) 420px; gap: 48px; }
  .keep-slot { width: 420px; }
  .plans { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 1080px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .hero-lede, .stats { max-width: none; }
  .forty { grid-template-columns: minmax(0, 1fr); gap: 56px; }
  .paper-slot, .keep-slot { width: 100%; max-width: 520px; }
  .keep-grid { grid-template-columns: minmax(0, 1fr); gap: 48px; }
  .tpl { grid-column: 1 / -1; }
  .features-head { flex-direction: column; align-items: flex-start; gap: 20px; }
  .plans { grid-template-columns: minmax(0, 1fr); max-width: 460px; }
  .faq { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-top { flex-direction: column; gap: 40px; }
}

/*
 * The slides narrow before the page does. Under a thousand pixels a 300px
 * slide leaves the rail showing three and a sliver, which reads as a row that
 * has been cut off rather than one that carries on.
 */
@media (max-width: 980px) {
  .tpl-copy { max-width: none; }
  .tpl-slide { width: 268px; }
  .tpl-stage { height: 292px; }
}

@media (max-width: 760px) {
  :root { --pad: 22px; }
  .masthead { padding-top: 22px; }
  .masthead nav { gap: 18px; }
  .masthead nav a:not(.nav-cta) { display: none; }
  .hero { padding-bottom: 64px; }
  .hero-grid { padding-top: 52px; }
  .hero-lede { font-size: 16.5px; }
  .evidence-strip .wrap { justify-content: flex-start; gap: 12px 18px; }
  .evidence-strip span + span::before { display: none; }
  .btn-download { height: 56px; padding: 0 24px; font-size: 16px; }
  .stats { flex-wrap: wrap; gap: 20px 24px; }
  .stats .rule { display: none; }
  .stats > div { min-width: 40%; }
  .forty, .features, .pricing, .keep { padding-top: 76px; padding-bottom: 84px; }
  .btn-ghost { height: 56px; padding: 0 22px; font-size: 16px; }
  .btn-download, .btn-ghost { flex: 1 1 auto; justify-content: center; }
  .faq { grid-template-columns: minmax(0, 1fr); gap: 26px; }
  .paper { padding: 26px 22px 30px; min-height: 0; }
  .paper.written { padding-bottom: 30px; }
  /*
   * The band gives up its corner on a phone. There is no width to keep clear
   * for a stamp beside a filename, and the doors want the whole line, so the
   * three parts stack in the order they happen.
   */
  .paper.written .outbox { position: static; margin-top: 28px; }
  .file { padding-right: 0; }
  .ways { gap: 10px; }
  .way { width: 54px; }
  .stamp-slot { position: static; align-self: flex-end; }
  .feature { grid-column: 1 / -1; padding: 18px 18px 24px; }
  /* One slide and the edge of the next, so the rail says it scrolls without
     being told. The bleed follows the card's own padding down with it. */
  .tpl { padding: 18px 18px 22px; }
  .tpl-copy { max-width: none; }
  .tpl h3 { font-size: 22px; }
  .tpl-copy > p { font-size: 15.5px; }
  .tpl-rail { margin: 22px -18px 0; padding: 4px 18px 14px; scroll-padding-inline: 18px; }
  .tpl-track { gap: 16px; }
  .tpl-slide { width: min(72vw, 300px); }
  .tpl-stage { height: 300px; padding: 18px 18px 0; }
  /*
   * Four columns in a row do not fit a 375px phone: the flex line ran 16px
   * past the viewport and took the whole document sideways with it, so the
   * hero scrolled too. They wrap now.
   */
  .footer-cols { flex-wrap: wrap; gap: 30px 40px; }
  .footer-col { min-width: 132px; }
  .footer-bottom { flex-direction: column; align-items: flex-start; gap: 8px; }
  .run { width: 100%; justify-content: center; }
}

/*
 * The phone is a fixed 393px drawing, so it is scaled rather than reflowed. The
 * slot's height is trimmed to match, otherwise the shrunken phone leaves a
 * column of empty hero underneath it.
 */
@media (max-width: 1080px) {
  .phone-slot { width: 100%; height: 660px; margin-top: 44px; }
  .phone-scale { transform: translateX(-50%) scale(.72); }
}
@media (max-width: 460px) {
  .phone-slot { height: 560px; }
  .phone-scale { transform: translateX(-50%) scale(.6); }
}

/*
 * ── shorter than the artboard ──────────────────────────────────────
 *
 * The artboard is 1440 x 1024, and at that size the hero is a screen tall on
 * its own. Every laptop is shorter than that, and `min-height: 100svh` cannot
 * make a 1004px hero fit a 900px screen: it can only stop a short one being
 * short. So the phone comes down with the screen.
 *
 * Four sizes rather than a formula, because the scale has to be a plain
 * number and there is no honest way to divide a viewport by 812 in CSS. Each
 * step is a zoom, the slot that holds the scaled phone plus the room its drop
 * shadow needs, and the two paddings around it. They add up to less than the
 * height they answer, and `min-height` spends the difference above the words.
 *
 * Only above 1080px, where the phone is still beside the words. Below that
 * the width queries own the phone and a short window is a phone held
 * sideways, which wants scrolling rather than shrinking.
 */
@media (min-width: 1081px) {
  .home-hero .phone-slot { height: var(--phone-stack, 760px); }
  .home-hero .phone-scale { transform: translateX(-50%) scale(var(--phone-zoom, .83)); }
  .home-hero .hero-grid { padding-top: var(--hero-lead, 76px); }
  .home-hero { padding-bottom: var(--hero-tail, 96px); }
}
@media (min-width: 1081px) and (max-height: 1010px) {
  .home-hero { --phone-zoom: .74; --phone-stack: 680px; --hero-lead: 44px; --hero-tail: 72px; }
}
@media (min-width: 1081px) and (max-height: 880px) {
  .home-hero { --phone-zoom: .635; --phone-stack: 584px; --hero-lead: 32px; --hero-tail: 56px; }
}
@media (min-width: 1081px) and (max-height: 760px) {
  .home-hero { --phone-zoom: .53; --phone-stack: 488px; --hero-lead: 26px; --hero-tail: 44px; }
}

/*
 * The shoal stops surrounding anything here. Two columns of words cannot sit
 * beside a 338px phone under about a thousand pixels, so the phone goes to the
 * top and the five buttons fall into a grid under it.
 *
 * `display: contents` on the two columns is what lets that grid be one grid of
 * five rather than three beside two: the buttons become children of `.shoal`
 * itself and auto-place in source order, with the phone pulled in front of
 * them by `order`. The hairlines go with the columns, because a rule pointing
 * at nothing is worse than no rule.
 */
@media (max-width: 1080px) {
  .shoal {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: stretch;
    justify-items: stretch;
  }
  .shoal-col { display: contents; }
  .shoal .callout { max-width: none; }
  .callout::after { display: none; }
  .shoal-stage { order: -1; grid-column: 1 / -1; justify-self: center; margin-bottom: 22px; }
}

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

/*
 * Under 420px the phone itself is wider than the page it is on, padding
 * included, so it is scaled again rather than allowed to push the document
 * sideways the way the footer's four columns once did.
 */
@media (max-width: 420px) {
  .shoal-stage { width: 275px; height: 568px; }
  .shoal-phone { transform: translateX(-50%) scale(.7); }
}

/* ── arriving ─────────────────────────────────────────────────────── */

/*
 * One move, used by everything below the hero: up off the page and in.
 *
 * It is deliberately the same move every time and deliberately small. A page
 * where each section arrives differently reads as a demo of a scroll library;
 * sixteen pixels and two thirds of a second, over and over, reads as the page
 * settling. The easing is weighted to the end for the same reason, so things
 * arrive rather than land.
 *
 * `--wait` is the stagger, and `landing.js` sets it per element from its
 * position among its siblings. It is on the transition rather than on an
 * animation so that an element interrupted half way through, by a fast scroll
 * back up, finishes from where it is instead of snapping.
 *
 * Note what is *not* here: no `.rise` in the markup, and no `opacity: 0` that
 * a visitor without JavaScript could ever be left holding. `landing.js` adds
 * the class itself, and only to elements that are off screen when it runs, so
 * with the file blocked the page is simply the page, and with it running there
 * is nothing on screen at load that could flash.
 */
/*
 * Written as the state before rather than the state after, and every from-rule
 * carries `:not(.landed)`.
 *
 * The obvious shape is `.rise { opacity: 0 }` with `.rise.landed` putting it
 * back, and it is wrong. `.rise.row` below is a second class pair at the same
 * specificity as `.rise.landed`, so whichever of the two is written last wins
 * the `transform`, and it was `.row`: fourteen rows arrived, faded correctly
 * in, and stayed ten pixels to the right of where they belonged for ever.
 *
 * Hung off `:not(.landed)` there is nothing to out-specify. Landing removes
 * every from-rule at once and the element goes back to the values the layout
 * gives it, whatever they are and whatever order the rules are in.
 */
.rise:not(.landed) {
  opacity: 0;
  transform: translateY(16px);
}
/* On the class that is added, not the one that is taken away, so hiding an
   element at load is instant and only the arrival is animated. */
.rise.landed {
  transition:
    opacity .66s cubic-bezier(.22, .68, .3, 1) var(--wait, 0ms),
    transform .66s cubic-bezier(.22, .68, .3, 1) var(--wait, 0ms);
}

/*
 * The rows inside a card move less than the card does, and sideways.
 *
 * A row 16 px below its final place inside a card that is itself 16 px below
 * its final place travels 32 px, and the two moves fight. Eight pixels, and
 * along the other axis, reads as the list settling into a card that is already
 * arriving rather than as a second copy of the same animation.
 */
.rise.row:not(.landed) {
  transform: translate(10px, 0);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
