/* Goodbyte home page, v2.
   The concept is in design-v2.md: the app icon is six mint dots narrowing
   3-2-1, which is a sieve, which is also the argument of the page. Every
   Goodbyte screen here is rendered in DOM rather than photographed, so the
   status bar and the safe areas are laid out rather than cropped. */

/* ============================================================ TOKENS ==== */

:root {
  --paper: #eef3f0;
  --paper-2: #e2eae5;
  --paper-ink: #0d1a17;
  --paper-ink-2: #3f5751;
  --paper-line: #c9d6d0;

  --app-red: #f0595e;      /* ErrorRed lifted to clear 4.5:1 on the navy */
  --app-red-solid: #c62828; /* deep enough that white on it clears 4.5:1 */
  --app-violet: #7b5fd4;

  --dev-radius: 34px;
  --fig: 'Space Mono', ui-monospace, 'SF Mono', Menlo, monospace;
}

/* ============================================================ CHROME ==== */

/* .mark and .wordmark-v2 moved to site.css so the legal pages and the 404 get
   the same lockup as this page. Do not redefine them here: home.css loads after
   site.css, so a copy in this file silently wins on the home page only, which
   is the shape the last drift took. */

.soon-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border: 1px solid color-mix(in srgb, var(--mint) 38%, transparent);
  color: var(--mint);
  border-radius: 999px;
  padding: 0.42rem 0.9rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.soon-chip svg { width: 13px; height: 14px; }
@media (max-width: 640px) { .soon-chip span { display: none; } }

/* At 390px the wordmark and the chip fill the bar, and "How it works" was
   wrapping onto three lines. This rule is in home.css rather than site.css
   because only the home page carries the chip: the legal pages have room for
   their links and keep them. The footer carries every link either way. */
@media (max-width: 760px) {
  .site-head .nav a:not(.btn-demo) { display: none; }
}

/* Section eyebrow, restated: a name for the chapter, the way the best
   competitor does it, but in one colour rather than six. */
.chapter {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--fig);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mint);
  margin: 0 0 1.5rem;
}
.chapter::before {
  content: '';
  width: 22px;
  height: 1px;
  background: currentColor;
  opacity: 0.55;
  flex: none;
}

.fig-cap {
  font-family: var(--fig);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-4);
}

h1, h2, h3 { letter-spacing: -0.028em; line-height: 1.02; font-weight: 520; }
.h-xl { font-size: clamp(2.6rem, 1.55rem + 4.4vw, 4.4rem); }
.h-lg { font-size: clamp(2rem, 1.35rem + 2.7vw, 3.3rem); }
.h-md { font-size: clamp(1.5rem, 1.2rem + 1.3vw, 2.1rem); line-height: 1.1; }

.lede-v2 {
  color: var(--ink-2);
  font-size: clamp(1.02rem, 0.97rem + 0.28vw, 1.2rem);
  line-height: 1.6;
  max-width: 46ch;
}

/* ====================================================== DEVICE + APP ==== */
/*
   One component, reused by the hero and by the feature switcher. The frame
   is a hairline, not a bezel. The status bar and the gesture pill are real
   elements with real insets, which is the whole reason this is DOM: there
   is no crop to get wrong.
*/

.dev {
  --dev-w: 300px;
  width: var(--dev-w);
  border: 1px solid var(--line);
  border-radius: var(--dev-radius);
  background: var(--navy);
  padding: 5px;
  flex: none;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.4) inset;
}
.dev-screen {
  border-radius: calc(var(--dev-radius) - 6px);
  background: var(--navy);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: calc(var(--dev-w) * 2.07);
  container-type: inline-size;
  font-size: calc(var(--dev-w) / 300 * 1rem);
}

.sysbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.62em 1.1em 0.24em;
  font-size: 0.68em;
  font-weight: 500;
  color: var(--ink-2);
  letter-spacing: 0.01em;
  flex: none;
}
.sysbar svg { width: 3.4em; height: 0.85em; opacity: 0.85; }

.gesture {
  flex: none;
  width: 34%;
  height: 0.25em;
  border-radius: 999px;
  background: rgb(255 255 255 / 0.32);
  margin: 0.5em auto 0.55em;
}

.app {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  color: #e8fff6;
  font-size: 0.78em;
  line-height: 1.35;
}

.appbar {
  display: flex;
  align-items: flex-start;
  gap: 0.85em;
  padding: 0.75em 1.15em 0.9em;
  flex: none;
}
.appbar .back {
  margin-top: 0.22em;
  width: 1.35em;
  height: 1.35em;
  flex: none;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  opacity: 0.9;
}
.appbar hgroup { flex: 1; min-width: 0; }
.appbar b {
  display: block;
  font-size: 1.16em;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.appbar small {
  display: block;
  font-size: 0.82em;
  color: #9db3c4;
  margin-top: 0.15em;
}
.appbar .act {
  margin-top: 0.18em;
  color: var(--mint);
  font-size: 0.86em;
  font-weight: 500;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
}
.appbar .act svg { width: 1.05em; height: 1.05em; }

.app-body {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  padding: 0 0.85em;
  display: flex;
  flex-direction: column;
  gap: 0.6em;
}
.app-foot {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6em;
  padding: 0.75em 1.1em 0.3em;
  font-size: 0.9em;
  color: #9db3c4;
}

.card {
  background: var(--surface);
  border-radius: 0.95em;
  padding: 0.85em 0.9em;
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  border-radius: 999px;
  padding: 0.5em 1em;
  font-size: 0.92em;
  font-weight: 600;
  background: var(--mint);
  color: var(--on-mint);
  white-space: nowrap;
}
.pill svg { width: 1.05em; height: 1.05em; }
.pill-ghost {
  background: transparent;
  border: 1px solid var(--app-red);
  color: var(--app-red);
}
.pill-violet { background: #6b53bd; color: #fff; }

/* -- duplicates ------------------------------------------------------- */

.dup-head {
  display: flex;
  align-items: center;
  gap: 0.7em;
}
.dup-ico {
  width: 1.85em;
  height: 1.85em;
  flex: none;
  border-radius: 0.45em;
  background: color-mix(in srgb, var(--app-red) 16%, transparent);
  display: grid;
  place-items: center;
}
.dup-ico svg { width: 1em; height: 1em; stroke: var(--app-red); fill: none; stroke-width: 1.7; }
.dup-head b { font-size: 1em; font-weight: 600; display: block; }
.dup-head small { font-size: 0.85em; color: #9db3c4; }
.chev { width: 1em; height: 1em; flex: none; stroke: #9db3c4; fill: none; stroke-width: 2; }

.dup-hint {
  font-size: 0.82em;
  color: #9db3c4;
  margin: 0.7em 0 0.6em;
  line-height: 1.4;
}
.dup-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.55em; }
.dup-thumb {
  display: block;
  position: relative;
  border-radius: 0.5em;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  border: 2px solid transparent;
  transition: border-color 0.45s var(--ease), opacity 0.45s var(--ease),
    filter 0.45s var(--ease);
}
.dup-thumb img { width: 100%; height: 100%; object-fit: cover; }
.dup-thumb .sz {
  position: absolute;
  right: 0.35em;
  bottom: 0.3em;
  font-size: 0.72em;
  font-weight: 600;
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
}
.dup-thumb .tick {
  position: absolute;
  left: 0.35em;
  bottom: 0.3em;
  width: 0.85em;
  height: 0.85em;
  stroke: #fff;
  fill: none;
  stroke-width: 2.6;
  filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.8));
}
.keep-badge {
  position: absolute;
  left: 0.3em;
  top: 0.3em;
  background: var(--mint);
  color: var(--on-mint);
  font-size: 0.66em;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 0.12em 0.5em;
  border-radius: 0.3em;
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}
.dup-act {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.7em;
  opacity: 0;
  transform: translateY(5px);
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
}

/* The one-shot hero resolve. Without JavaScript there is nothing to trigger
   it, so the screen renders in its resolved state rather than half told. */
html:not(.js) .dup-thumb.is-keep { border-color: var(--mint); }
html:not(.js) .dup-thumb.is-keep .keep-badge { opacity: 1; transform: none; }
html:not(.js) .dup-thumb.is-dup { opacity: 0.22; filter: grayscale(0.85); }
html:not(.js) .dup-act { opacity: 1; transform: none; }


.dev[data-resolved] .dup-thumb.is-keep { border-color: var(--mint); }
.dev[data-resolved] .dup-thumb.is-keep .keep-badge { opacity: 1; transform: none; }
.dev[data-resolved] .dup-thumb.is-dup { opacity: 0.22; filter: grayscale(0.85); }
.dev[data-resolved] .dup-act { opacity: 1; transform: none; }

/* -- swipe ------------------------------------------------------------ */

.sw-meter {
  display: flex;
  justify-content: space-between;
  font-size: 0.92em;
  padding: 0 0.3em;
}
.sw-meter .q { color: var(--app-red); }
.sw-bar {
  height: 0.22em;
  border-radius: 999px;
  background: #2a3a52;
  overflow: hidden;
}
.sw-bar i { display: block; width: 8%; height: 100%; background: var(--mint); }
.sw-photo {
  flex: 1;
  min-height: 0;
  border-radius: 0.7em;
  overflow: hidden;
  background: #0b1524;
  display: grid;
  place-items: center;
}
.sw-photo img { width: 100%; height: 100%; object-fit: contain; }
.sw-meta {
  background: #0b1524;
  border-radius: 0.6em;
  padding: 0.6em 0.75em;
  font-size: 0.86em;
}
.sw-meta b { display: block; font-weight: 500; }
.sw-meta small { color: #9db3c4; font-size: 0.88em; }
.sw-acts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.6em; }
.sw-acts .pill { justify-content: center; min-width: 0; overflow: hidden; }

/* -- review bin ------------------------------------------------------- */

.bin-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.5em; }
.bin-item .shot {
  display: block;
  position: relative;
  border-radius: 0.5em;
  overflow: hidden;
  aspect-ratio: 1;
}
.bin-item img { width: 100%; height: 100%; object-fit: cover; }
.bin-item .tag {
  position: absolute;
  right: 0.25em;
  top: 0.25em;
  background: var(--app-red-solid);
  color: #fff;
  font-size: 0.62em;
  font-weight: 600;
  padding: 0.1em 0.4em;
  border-radius: 0.28em;
}
/* The real bin holds two kinds of item and tags them differently: red for one
   the duplicate scan staged, blue for one swiped out of the camera roll. The
   page showed only the red one, which made the bin look like it was for
   duplicates alone. */
.bin-item .tag[data-kind='photo'] { background: #1565c0; }
.bin-item .undo {
  position: absolute;
  left: 0.25em;
  top: 0.25em;
  width: 1.1em;
  height: 1.1em;
  border-radius: 999px;
  background: rgb(10 20 33 / 0.78);
  display: grid;
  place-items: center;
}
.bin-item .undo svg { width: 0.72em; height: 0.72em; stroke: var(--mint); fill: none; stroke-width: 2.2; }
.bin-item { min-width: 0; }
.bin-item .sz {
  position: absolute;
  right: 0.25em;
  bottom: 0.2em;
  font-size: 0.66em;
  font-weight: 600;
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.85);
}
.bin-item .nm {
  display: block;
  font-size: 0.64em;
  color: #9db3c4;
  margin-top: 0.35em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* -- storage ---------------------------------------------------------- */

.donut { display: grid; place-items: center; padding: 0.6em 0 0.3em; position: relative; }
.donut svg { width: 9.4em; height: 9.4em; transform: rotate(-90deg); }
.donut .t {
  position: absolute;
  text-align: center;
  inset: 0;
  display: grid;
  place-content: center;
}
/* The label has to fit the hole, not the ring. It was set for "6.7 GB of
   14.9 GB"; the real device reads "21.7 GB of 29.8 GB used", which is two
   characters wider and ran under the arc on both lines. */
.donut .t { max-width: 6.1em; margin-inline: auto; }
.donut .t b { font-size: 1.5em; font-weight: 600; letter-spacing: -0.03em; }
.donut .t small { font-size: 0.72em; line-height: 1.25; color: #9db3c4; }
.row-card {
  display: flex;
  align-items: center;
  gap: 0.6em;
  background: var(--surface);
  border-radius: 0.8em;
  padding: 0.7em 0.85em;
  font-size: 0.9em;
}
.row-card svg { width: 1.1em; height: 1.1em; flex: none; stroke: var(--mint); fill: none; stroke-width: 1.8; }
.row-card .go { margin-left: auto; color: var(--mint); font-size: 0.95em; flex: none; }
.quick {
  display: flex;
  align-items: center;
  gap: 0.75em;
  background: var(--surface);
  border-radius: 0.9em;
  padding: 0.9em;
}
.quick .ok {
  width: 1.6em;
  height: 1.6em;
  flex: none;
  border-radius: 999px;
  background: color-mix(in srgb, var(--mint) 20%, transparent);
  display: grid;
  place-items: center;
}
.quick .ok svg { width: 0.95em; height: 0.95em; stroke: var(--mint); fill: none; stroke-width: 2.6; }
.quick b { font-size: 1.15em; font-weight: 600; display: block; }
.quick small { font-size: 0.85em; color: #9db3c4; }
.brk { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5em; }
.brk div { background: var(--surface); border-radius: 0.7em; padding: 0.65em 0.75em; }
.brk i {
  width: 0.45em;
  height: 0.45em;
  border-radius: 999px;
  display: inline-block;
  margin-right: 0.4em;
  vertical-align: 0.15em;
}
.brk span { font-size: 0.85em; color: #cfe0ec; }
.brk b { display: block; font-size: 1.25em; font-weight: 600; letter-spacing: -0.02em; margin-top: 0.15em; }
.brk small { font-size: 0.75em; color: #7e95a8; }

/* -- large files and compress ----------------------------------------- */

.chips { display: flex; gap: 0.4em; overflow: hidden; }
.chips span {
  font-size: 0.82em;
  padding: 0.3em 0.75em;
  border-radius: 999px;
  border: 1px solid #2d4260;
  color: #cfe0ec;
  white-space: nowrap;
}
.chips span[data-on] { background: #4b3f78; border-color: transparent; }
.file-row {
  display: flex;
  align-items: center;
  gap: 0.65em;
  background: var(--surface);
  border-radius: 0.7em;
  padding: 0.6em 0.7em;
}
.bars {
  width: 2.5em;
  height: 1.9em;
  flex: none;
  border-radius: 0.3em;
  background: linear-gradient(90deg,
    #c0c0c0 0 14.2%, #c0c000 0 28.4%, #00c0c0 0 42.6%, #00c000 0 56.8%,
    #c000c0 0 71%, #c00000 0 85.2%, #0000c0 0 100%);
}
.file-row .nm { flex: 1; min-width: 0; }
.file-row .nm b {
  display: block;
  font-size: 0.88em;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-row .nm small { font-size: 0.78em; color: #9db3c4; }
.file-row .nm em { font-style: normal; color: var(--mint); }
.file-row .tagv {
  font-size: 0.62em;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #c9b6ff;
  border: 1px solid #4b3f78;
  background: #2b2450;
  border-radius: 0.25em;
  padding: 0.05em 0.35em;
  margin-right: 0.4em;
}
.file-row .dot {
  width: 1.05em;
  height: 1.05em;
  border-radius: 999px;
  border: 1.5px solid #3a4f6b;
  flex: none;
}
.preset { display: grid; gap: 0.7em; }
.preset > div { display: flex; align-items: flex-start; gap: 0.6em; }
.preset .rad {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  border-radius: 999px;
  border: 1.5px solid #3a4f6b;
  margin-top: 0.15em;
  display: grid;
  place-items: center;
}
.preset .rad[data-on] { background: var(--mint); border-color: var(--mint); }
.preset .rad svg { width: 0.7em; height: 0.7em; stroke: var(--on-mint); fill: none; stroke-width: 3; display: none; }
.preset .rad[data-on] svg { display: block; }
.preset b { display: block; font-size: 0.92em; font-weight: 500; }
.preset small { font-size: 0.8em; color: #9db3c4; }

/* ============================================================== HERO ==== */

.hero-v2 {
  position: relative;
  overflow: hidden;
  padding-top: clamp(2rem, 4.5vw, 4rem);
}
.hero-v2::after {
  content: '';
  position: absolute;
  inset: auto 0 0;
  height: 190px;
  background: linear-gradient(to top, var(--bg), transparent);
  pointer-events: none;
}
.hero-grid-v2 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}
.hero-lead-v2 { padding-bottom: clamp(3rem, 6vw, 5rem); max-width: 40rem; }
.hero-eyebrow {
  font-family: var(--fig);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin: 0 0 1.4rem;
}

.hero-v2 h1 { margin-bottom: 1.6rem; max-width: 15ch; }
.hero-v2 h1 em { font-style: normal; color: var(--ink); }

.trust-v2 {
  list-style: none;
  margin: 2.4rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem 0.5rem;
  font-family: var(--fig);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.trust-v2 li {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.34rem 0.75rem;
  color: var(--ink-3);
}
.trust-v2 li b { color: var(--mint); font-weight: 400; }

/* The device is cut by the bottom of the hero rather than floated in it. */
.hero-dev {
  align-self: end;
  height: clamp(440px, 64vh, 640px);
  overflow: hidden;
}
.hero-dev .dev { --dev-w: 360px; }

@media (max-width: 900px) {
  .hero-grid-v2 { grid-template-columns: 1fr; gap: 1.6rem; display: flex; flex-direction: column; }
  .hero-lead-v2 { padding-bottom: 0; }
  .hero-dev { align-self: center; height: 420px; }
  .hero-dev .dev { --dev-w: 280px; }
  .hero-v2::after { height: 150px; }
}

/* ======================================================= SIEVE / MESS === */

/* The track is the scroll budget for the pinned sequence. Three stages need
   room to land without the reader having to hunt for them. */
.sieve-track {
  position: relative;
  height: 300vh;
  border-top: 1px solid var(--line);
  background: var(--bg-2);
}
@media (max-width: 900px) { .sieve-track { height: 250vh; } }
.sieve-stage {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding-block: clamp(2.5rem, 7vh, 5rem);
  overflow: hidden;
}
.sieve-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-bottom: clamp(1.6rem, 3.5vw, 2.6rem);
}
.sieve-head h2 {
  max-width: 17ch;
  font-size: clamp(1.75rem, 1.2rem + 2.1vw, 2.7rem);
}

.mess {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  gap: clamp(4px, 0.7vw, 9px);
}
@media (max-width: 900px) { .mess { grid-template-columns: repeat(6, 1fr); } }

.tile {
  position: relative;
  aspect-ratio: 1;
  border-radius: 5px;
  background-image: url('/assets/img/mess-atlas.dc5a61928b.webp');
  background-size: 600% 600%;
  background-position: calc(var(--x) * 20%) calc(var(--y) * 20%);
  outline: 0 solid var(--mint);
  outline-offset: -1px;
  will-change: transform, opacity;
  transition:
    transform 0.72s var(--ease),
    opacity 0.55s var(--ease),
    outline-width 0.3s var(--ease),
    outline-color 0.3s var(--ease);
}
/* group numbers, drawn only while the groups are being named */
.tile::after {
  content: attr(data-g);
  position: absolute;
  left: 2px;
  top: 2px;
  font-family: var(--fig);
  font-size: 9px;
  line-height: 1;
  padding: 2px 3px;
  border-radius: 3px;
  background: rgb(10 20 33 / 0.82);
  color: var(--mint);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
.tile::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 5px;
  background: var(--mint);
  opacity: 0;
  mix-blend-mode: screen;
  transition: opacity 0.3s var(--ease);
}

/* stage 1: the repeats are named. The keeper takes a solid mint hairline,
   its repeats take a dimmed one, and every tile shows its group number. */
.mess[data-stage='1'] .tile[data-g] {
  outline-width: 1px;
  outline-color: color-mix(in srgb, var(--mint) 36%, transparent);
}
.mess[data-stage='1'] .tile::after { opacity: 1; }
.mess[data-stage='1'] .tile[data-keep] { outline-width: 1.5px; outline-color: var(--mint); }
.mess[data-stage='1'] .tile[data-keep]::before { opacity: 0.16; }

/* stage 2 and 3: each repeat travels onto its keeper and goes */
.mess[data-stage='2'] .tile[data-dup],
.mess[data-stage='3'] .tile[data-dup] {
  transform: translate(var(--dx, 0px), var(--dy, 0px)) scale(0.62);
  opacity: 0;
  pointer-events: none;
}
.mess[data-stage='2'] .tile[data-keep],
.mess[data-stage='3'] .tile[data-keep] {
  outline-width: 1.5px;
  outline-color: var(--mint);
}
.mess[data-stage='2'] .tile::after,
.mess[data-stage='3'] .tile::after { opacity: 0; }

/* stage 3: the repeats leave the flow and the library closes up, larger,
   which is the first time the surviving photographs are properly legible */
.mess[data-stage='3'] {
  grid-template-columns: repeat(4, 1fr);
  max-width: min(660px, 62vh);
  margin-inline: auto;
  gap: clamp(6px, 1vw, 12px);
}
.mess[data-stage='3'] .tile[data-dup] { display: none; }
.mess[data-stage='3'] .tile[data-keep] { border-radius: 8px; }
.mess { transition: max-width 0.5s var(--ease); max-width: 100%; margin-inline: auto; }
@media (max-width: 900px) {
  .mess[data-stage='3'] { grid-template-columns: repeat(3, 1fr); max-width: min(420px, 52vh); }
}

.sieve-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem 1.6rem;
  margin-top: clamp(1.2rem, 2.6vw, 2rem);
  min-height: 2.6rem;
}
.sieve-read {
  font-family: var(--fig);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  text-transform: uppercase;
}
.sieve-read b { color: var(--mint); font-weight: 400; }
.sieve-note { color: var(--ink-4); font-size: 0.82rem; max-width: 42ch; }

/* ============================================================= DECK ===== */

.deck-sec { border-top: 1px solid var(--line); }
.deck-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
@media (max-width: 900px) { .deck-grid { grid-template-columns: 1fr; } }

.deck-teach {
  margin: 1.8rem 0 0;
  display: grid;
  gap: 0.75rem;
  max-width: 34ch;
}
.deck-teach div {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  color: var(--ink-2);
  font-size: 1.02rem;
}
.deck-teach i {
  font-family: var(--fig);
  font-style: normal;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: var(--mint);
  flex: none;
  width: 4.4em;
}

.deck-wrap { justify-self: center; width: 100%; max-width: 380px; }
.deck-lab {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.8rem;
  font-family: var(--fig);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.deck-clip {
  position: relative;
  aspect-ratio: 3 / 4;
  touch-action: pan-y;
}
.deck-wrap, .deck-clip { min-width: 0; }
.deck-card {
  position: absolute;
  inset: 0;
  border-radius: 20px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: 0 18px 44px -24px rgb(0 0 0 / 0.9);
  transform-origin: 50% 120%;
  transition: transform 0.5s var(--ease), opacity 0.5s var(--ease);
  user-select: none;
  -webkit-user-select: none;
}
.deck-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
.deck-card .meta {
  position: absolute;
  inset: auto 0 0;
  padding: 2.4rem 1rem 0.95rem;
  background: linear-gradient(to top, rgb(6 13 22 / 0.94), transparent);
  font-size: 0.82rem;
  color: var(--ink-2);
}
.deck-card .meta b {
  display: block;
  color: #fff;
  font-weight: 500;
  font-size: 0.94rem;
  letter-spacing: -0.01em;
}
.deck-card .verdict {
  position: absolute;
  top: 1rem;
  left: 1rem;
  font-family: var(--fig);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.3rem 0.65rem;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 0.2s;
}
.deck-card[data-v='keep'] .verdict { background: var(--mint); color: var(--on-mint); }
/* --app-red is tuned for red text on navy. White on it is about 3.2:1, so the
   badge that puts white on a red fill uses the deeper solid instead. */
.deck-card[data-v='queue'] .verdict { background: var(--app-red-solid); color: #fff; }
.deck-card.is-lit .verdict { opacity: 1; }
/* `gone` is set once the exit has actually landed, never on a timer that could
   fire mid flight, so taking the card out of hit testing and out of the
   accessibility tree here is safe. */
.deck-card.gone { opacity: 0; visibility: hidden; pointer-events: none; }

/* ------------------------------------------------- the end of the deck --- */
/* The deck used to go blank once all four cards were dispatched, which read as
   a broken widget rather than as a finished job. This takes its place and says
   what happened, with counts filled in from what the visitor actually did. */
.deck-done {
  position: absolute;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 1.6rem 1.4rem;
  text-align: center;
  border-radius: 20px;
  border: 1px solid color-mix(in srgb, var(--mint) 26%, var(--line));
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--mint) 11%, transparent), transparent 70%),
    var(--surface);
  box-shadow: 0 18px 44px -24px rgb(0 0 0 / 0.9);
  opacity: 0;
  transform: scale(0.94);
}
.deck-done[data-in] {
  opacity: 1;
  transform: none;
  /* The one celebratory beat on the page: a small overshoot on the way in.
     Transform and opacity only, so it composites. */
  transition: opacity 0.34s var(--ease),
    transform 0.52s cubic-bezier(0.22, 1.3, 0.36, 1);
}
.deck-done .done-h {
  font-size: 1.45rem;
  font-weight: 520;
  letter-spacing: -0.03em;
  color: #fff;
}
.deck-done .done-sum {
  font-size: 0.98rem;
  color: var(--ink-2);
  max-width: 22ch;
}
.deck-done .done-safe {
  font-family: var(--fig);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--mint);
}
.done-thumbs {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.5rem 0 0.2rem;
  padding: 0;
  list-style: none;
}
.done-thumb {
  position: relative;
  width: 3.9rem;
  border-radius: 9px;
  overflow: hidden;
  border: 1px solid var(--line);
  opacity: 0;
  transform: translateY(10px) scale(0.94);
}
.deck-done[data-in] .done-thumb {
  opacity: 1;
  transform: none;
  transition: opacity 0.3s var(--ease), transform 0.42s var(--ease);
  transition-delay: calc(180ms + var(--i) * 70ms);
}
.done-thumb img { display: block; width: 100%; height: auto; }
.done-thumb span {
  position: absolute;
  inset: auto 0 0;
  font-family: var(--fig);
  font-size: 0.5rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.18rem 0;
}
.done-thumb[data-v='keep'] span { background: var(--mint); color: var(--on-mint); }
.done-thumb[data-v='queue'] span { background: var(--app-red-solid); color: #fff; }
.done-thumb[data-v='keep'] { border-color: color-mix(in srgb, var(--mint) 55%, transparent); }
/* [hidden] is display:none from the user agent sheet, which any explicit
   display in an author rule beats. Both of these have one, so both need this
   or the deck's controls stay on screen underneath the summary. */
.deck-acts[hidden], .deck-btn[hidden] { display: none; }

.done-acts {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-top: 0.7rem;
  flex-wrap: wrap;
  justify-content: center;
}
.done-link {
  font-size: 0.9rem;
  color: var(--mint);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--mint) 40%, transparent);
  padding-bottom: 1px;
}
.done-link:hover { border-bottom-color: var(--mint); }

/* The summary shows these words, so the live region is taken out of the layout
   without being taken out of the accessibility tree. display:none would stop
   it announcing anything at all. */
.deck-status-off {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Three equal buttons at 380px broke "Queue for review" across two lines and
   left the stack peeking out underneath, so the two decisions get a row of
   their own and Reset sits with the status line. */
.deck-acts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
  margin-top: 2.2rem;
}
.deck-btn {
  min-width: 0;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 0.88rem;
  font-weight: 500;
  padding: 0.68rem 1rem;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s, background 0.2s;
}
.deck-btn:hover { border-color: var(--ink-4); color: #fff; }
.deck-btn[data-do='keep'] { border-color: color-mix(in srgb, var(--mint) 45%, transparent); color: var(--mint); }
.deck-btn[data-do='keep']:hover { background: color-mix(in srgb, var(--mint) 12%, transparent); }
.deck-btn[data-reset] {
  border: 0;
  padding: 0;
  color: var(--ink-4);
  font-size: 0.78rem;
  font-family: var(--fig);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.deck-btn[data-reset]:hover { color: var(--mint); background: none; }
/* Try again shares the reset handler but not its manner: in the summary it is
   the primary action, so it takes the button treatment back off the quiet
   underlined Reset that sits next to the status line. Declared here, after
   [data-reset], because the two selectors otherwise weigh the same. */
.done-acts .deck-btn[data-reset] {
  border: 1px solid color-mix(in srgb, var(--mint) 45%, transparent);
  border-radius: 999px;
  padding: 0.62rem 1.3rem;
  color: var(--mint);
  font-family: inherit;
  font-size: 0.92rem;
  letter-spacing: -0.01em;
  text-transform: none;
  text-decoration: none;
}
.done-acts .deck-btn[data-reset]:hover {
  background: color-mix(in srgb, var(--mint) 12%, transparent);
  border-color: var(--mint);
}
.deck-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.9rem;
}
.deck-status {
  font-family: var(--fig);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  min-height: 1.4em;
}

/* ========================================================== THE GATE ==== */
/* The one inverted chapter. It is the safety section, so the inversion is
   load-bearing: the part of the page that is about not losing anything is
   the part that is lighter. */

.gate {
  background: var(--paper);
  color: var(--paper-ink);
  position: relative;
}
.gate .chapter { color: #0b7a5c; }
.gate h2 { color: var(--paper-ink); }
.gate .lede-v2 { color: var(--paper-ink-2); }
.gate .fig-cap { color: #5a6f69; }

.gate-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
@media (max-width: 900px) {
  .gate-grid { grid-template-columns: 1fr; }
  .gate-dev { justify-self: center; }
}
.gate-dev .dev {
  --dev-w: 290px;
  border-color: #b9c8c2;
  background: #0f1b2d;
  box-shadow: 0 30px 60px -34px rgb(13 26 23 / 0.5);
}

.gate-fig {
  border: 1px solid var(--paper-line);
  border-radius: 14px;
  background: rgb(255 255 255 / 0.55);
  padding: clamp(1.1rem, 2.4vw, 1.7rem);
  margin-top: 2.2rem;
}
.gate-fig .fig-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.35rem 1rem;
  margin-bottom: 1.1rem;
  font-family: var(--fig);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #5a6f69;
}
.gate-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.9rem;
  counter-reset: g;
}
@media (max-width: 680px) { .gate-steps { grid-template-columns: 1fr; } }
.gate-steps li {
  border: 1px solid var(--paper-line);
  border-radius: 10px;
  padding: 0.9rem 1rem;
  background: #fff;
  position: relative;
}
.gate-steps li b {
  display: block;
  font-weight: 600;
  font-size: 0.98rem;
  margin-bottom: 0.3rem;
  letter-spacing: -0.015em;
}
.gate-steps li p { color: var(--paper-ink-2); font-size: 0.87rem; line-height: 1.5; }
.gate-steps li::before {
  counter-increment: g;
  content: counter(g);
  position: absolute;
  right: 0.8rem;
  top: 0.7rem;
  font-family: var(--fig);
  font-size: 0.7rem;
  color: #627670;
}
.gate-steps li:last-child { border-color: #0b7a5c; }
.gate-steps li:last-child b { color: #0b7a5c; }

.gate-note {
  margin-top: 1.1rem;
  font-size: 0.87rem;
  color: var(--paper-ink-2);
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
}
.gate-note svg { width: 1.05rem; height: 1.05rem; flex: none; margin-top: 0.15rem; stroke: #0b7a5c; fill: none; stroke-width: 2; }

/* ========================================================== SWITCHER ==== */

.eng-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
@media (max-width: 900px) {
  .eng-grid { grid-template-columns: 1fr; }
  .eng-dev { justify-self: center; order: -1; }
}
.eng-tabs {
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}
.eng-tabs button {
  width: 100%;
  display: block;
  text-align: left;
  background: var(--bg);
  border: 0;
  color: var(--ink-3);
  font: inherit;
  padding: 1rem 1.15rem;
  cursor: pointer;
  transition: background 0.2s, color 0.2s;
}
.eng-tabs button b {
  display: block;
  color: var(--ink-2);
  font-weight: 500;
  font-size: 1rem;
  letter-spacing: -0.015em;
  transition: color 0.2s;
}
.eng-tabs button span { font-size: 0.86rem; line-height: 1.45; display: block; margin-top: 0.2rem; }
.eng-tabs button:hover { background: var(--surface); }
.eng-tabs button[aria-selected='true'] { background: var(--surface); }
.eng-tabs button[aria-selected='true'] b { color: var(--mint); }
.eng-tabs li { position: relative; }
.eng-tabs button[aria-selected='true']::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--mint);
}

.eng-dev .dev { --dev-w: 300px; }
.eng-dev .app[hidden] { display: none; }
.eng-panels { position: relative; }

/* ========================================================== BOUNDARY ==== */

.bound {
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--bg-2);
  padding: clamp(1.2rem, 3vw, 2rem);
  margin-top: 2.5rem;
}
.bound-head {
  display: flex;
  justify-content: space-between;
  gap: 0.35rem 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.4rem;
}
.wall-path { stroke-dasharray: var(--len); stroke-dashoffset: var(--len); }
.js .bound.in .wall-path {
  transition: stroke-dashoffset 0.9s var(--ease) 0.15s;
  stroke-dashoffset: 0;
}
.bound:not(.in) .blocked { opacity: 0; }
.js .bound .blocked { transition: opacity 0.5s var(--ease) 0.8s; }
.bound.in .blocked { opacity: 1; }
.fig-narrow { display: none; }
@media (max-width: 760px) {
  .fig-narrow { display: block; }
  .fig-wide { display: none; }
}

.absences {
  list-style: none;
  margin: 1.6rem 0 0;
  padding: 1.4rem 0 0;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1.1rem;
  font-family: var(--fig);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.absences b {
  display: block;
  font-family: 'Space Grotesk', system-ui, sans-serif;
  font-size: 1.9rem;
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--mint);
  line-height: 1;
  margin-bottom: 0.35rem;
}
.airplane {
  margin-top: 1.5rem;
  color: var(--ink-2);
  font-size: 0.95rem;
  line-height: 1.6;
}
.airplane span { color: var(--ink-4); }

.props-details {
  border: 1px solid var(--line);
  border-radius: 14px;
  margin-top: 1.6rem;
  background: var(--bg-2);
}
.props-details summary {
  list-style: none;
  cursor: pointer;
  padding: 1.1rem 1.3rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.props-details summary::-webkit-details-marker { display: none; }
.props-details summary h3 { font-size: 1.02rem; font-weight: 520; }
.props-details summary .ind {
  font-family: var(--fig);
  font-size: 0.7rem;
  color: var(--ink-4);
  flex: none;
}
.props-details[open] summary .ind::after { content: ' \2212'; }
.props-details:not([open]) summary .ind::after { content: ' +'; }
.props {
  list-style: none;
  margin: 0;
  padding: 0 1.3rem 1.3rem;
  display: grid;
  gap: 0.8rem;
  color: var(--ink-2);
  font-size: 0.93rem;
  line-height: 1.55;
}
.props li { display: flex; gap: 0.7rem; align-items: flex-start; }
.props svg {
  width: 1.05rem;
  height: 1.05rem;
  flex: none;
  margin-top: 0.26rem;
  stroke: var(--mint);
  fill: none;
  stroke-width: 2.4;
}
.note-v2 {
  margin-top: 1.6rem;
  border-left: 2px solid var(--line);
  padding-left: 1.2rem;
  color: var(--ink-3);
  font-size: 0.9rem;
  line-height: 1.65;
}
.note-v2 strong { color: var(--ink-2); font-weight: 600; }
.note-v2 a { color: var(--mint); text-underline-offset: 3px; }

/* =========================================================== PRICING ==== */

.plans-v2 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
  margin-top: 2.6rem;
}
@media (max-width: 940px) { .plans-v2 { grid-template-columns: 1fr; } }
.plan-v2 {
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 1.6rem;
  background: var(--bg-2);
  display: flex;
  flex-direction: column;
}
.plan-v2.is-pro { border-color: color-mix(in srgb, var(--mint) 42%, transparent); }
.plan-v2 h3 { font-size: 1.2rem; font-weight: 600; }
.plan-sub-v2 { color: var(--ink-3); font-size: 0.9rem; margin-top: 0.5rem; line-height: 1.5; }
.plan-tag {
  align-self: flex-start;
  font-family: var(--fig);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mint);
  border: 1px solid color-mix(in srgb, var(--mint) 38%, transparent);
  border-radius: 999px;
  padding: 0.25rem 0.65rem;
  margin-bottom: 0.9rem;
}
.price-v2 { font-size: 2.6rem; font-weight: 500; letter-spacing: -0.04em; margin-top: 1.2rem; line-height: 1; }
.rows-v2 { margin-top: 1.2rem; border-top: 1px solid var(--line); }
.rows-v2 div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--line);
}
.rows-v2 b { font-size: 1.45rem; font-weight: 500; letter-spacing: -0.03em; }
.rows-v2 span { color: var(--ink-3); font-size: 0.88rem; }
.plan-fine { color: var(--ink-4); font-size: 0.8rem; line-height: 1.55; margin-top: 0.9rem; }
.plan-fine a { color: var(--mint); }
.plan-list {
  list-style: none;
  margin: 1.4rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.7rem;
  font-size: 0.91rem;
  color: var(--ink-2);
  line-height: 1.5;
}
.plan-list li { display: flex; gap: 0.65rem; align-items: flex-start; }
.plan-list svg {
  width: 1rem;
  height: 1rem;
  flex: none;
  margin-top: 0.25rem;
  stroke: var(--mint);
  fill: none;
  stroke-width: 2.4;
}

/* ============================================================= CLOSE ==== */

.close-v2 {
  border-top: 1px solid var(--line);
  padding-block: clamp(5rem, 11vw, 8rem);
  text-align: center;
}
.close-v2 .mark { width: 44px; height: 39.5px; margin: 0 auto 2rem; }
.close-v2 h2 { max-width: 16ch; margin-inline: auto; }
.close-v2 p { color: var(--ink-3); margin-top: 1.3rem; font-size: 1.05rem; }
.close-v2 .soon-chip { margin-top: 2rem; }
.close-v2 .soon-chip span { display: inline; }
.close-mail { display: block; margin-top: 1.6rem; color: var(--ink-3); font-size: 0.9rem; }
.close-mail a { color: var(--mint); text-underline-offset: 3px; }

/* ==================================================== REDUCED MOTION ==== */

@media (prefers-reduced-motion: reduce) {
  /* The page has to make the whole argument standing still. The sieve
     stops sieving and simply names the repeats, which is the same point
     without the travel. */
  .sieve-track { height: auto !important; }
  .sieve-stage { position: static; min-height: 0; }
  .mess .tile[data-dup] { transform: none !important; opacity: 1 !important; }
  .mess .tile[data-g] { outline-width: 1px; }
  .mess .tile[data-keep] { outline-width: 1.5px; outline-color: var(--mint); }
  .mess .tile::after { opacity: 1; }
  .dev .dup-thumb.is-keep { border-color: var(--mint); }
  .dev .dup-thumb.is-keep .keep-badge { opacity: 1; transform: none; }
  .dev .dup-act { opacity: 1; transform: none; }
  .wall-path { stroke-dashoffset: 0 !important; }
  .bound .blocked { opacity: 1 !important; }
  .tile, .deck-card, .dup-thumb { transition: none !important; will-change: auto; }
  /* The end of the deck still arrives, it just arrives without the beat. */
  .deck-done, .deck-done .done-thumb { transition: none !important; }
  .deck-done[data-in], .deck-done[data-in] .done-thumb { opacity: 1; transform: none; }
}

/* Offsets are measured with transitions off, or the rect comes back mid tween. */
.mess.no-tr .tile { transition: none !important; }

/* Panels share one frame. Each fills it, only one is not [hidden]. */
.eng-panels > .app { flex: 1; min-width: 0; }
.eng-panels > .app[hidden] { display: none; }

/* Reduced motion collapses the track, so the sticky child needs its padding back. */
@media (prefers-reduced-motion: reduce) {
  .sieve-stage { padding-block: clamp(5rem, 11vw, 9rem); }
}

/* ===================================================== ASTRA PASS 1 ===== */
/*
   Astra scored the first build 2/10 on CTA against 8s across the category,
   and it was right: "Coming soon" is availability information that had been
   dressed up as a button, so the page gave a visitor nothing to do. The deck
   is a working demo that is already on the page. It becomes the action.
*/

.btn-demo,
.site-head .nav a.btn-demo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  background: var(--mint);
  color: var(--on-mint);
  border-radius: 999px;
  padding: 0.85rem 1.7rem;
  font-weight: 600;
  font-size: 0.98rem;
  letter-spacing: -0.01em;
  text-decoration: none;
  white-space: nowrap;
  transition: transform 0.2s var(--ease), background 0.2s;
}
.btn-demo:hover,
.site-head .nav a.btn-demo:hover { transform: translateY(-2px); background: #3ee9b3; color: var(--on-mint); }
.btn-demo-sm,
.site-head .nav a.btn-demo-sm { padding: 0.5rem 1.05rem; font-size: 0.84rem; }

.hero-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem 1.5rem;
  margin-top: 2.1rem;
}
.soon-line {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--ink-3);
  font-size: 0.88rem;
  white-space: nowrap;
}
.soon-line svg { width: 14px; height: 15px; flex: none; opacity: 0.75; }

/* The trust chips were, in Astra's words, extremely faint. They carry the
   strongest claim on the page, so they now read as a set of zeroes. */
.trust-v2 {
  font-size: 0.74rem;
  margin-top: 2rem;
}
.trust-v2 li {
  border-color: color-mix(in srgb, var(--mint) 24%, var(--line));
  background: color-mix(in srgb, var(--mint) 6%, transparent);
  color: var(--ink-2);
  padding: 0.4rem 0.85rem;
}
.trust-v2 li b { color: var(--mint); font-weight: 700; margin-right: 0.15rem; }

/* On mobile the demo has to arrive before the instructions about it. */
@media (max-width: 900px) {
  .deck-grid { display: flex; flex-direction: column; }
  .deck-wrap { order: 1; }
  .deck-copy { order: 2; }
  .deck-copy .chapter { margin-bottom: 1.1rem; }
}

/* The switcher put a tall list of six descriptions above a phone, so the
   controls and the screen were never on the same mobile screen. Below 900px
   it becomes a horizontal control that sits directly on top of the frame. */
@media (max-width: 900px) {
  .eng-grid { display: flex; flex-direction: column; gap: 1.4rem; }
  .eng-side { display: contents; }
  .eng-tabs {
    order: 1;
    display: flex;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    align-self: stretch;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    gap: 0.45rem;
    background: none;
    border: 0;
    border-radius: 0;
    margin: 0;
    padding: 0 0 0.3rem;
  }
  .eng-tabs::-webkit-scrollbar { display: none; }
  .eng-tabs li { flex: none; }
  .eng-tabs button {
    width: auto;
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 0.5rem 1rem;
    white-space: nowrap;
  }
  .eng-tabs button span { display: none; }
  .eng-tabs button b { font-size: 0.88rem; }
  .eng-tabs button[aria-selected='true'] {
    background: color-mix(in srgb, var(--mint) 14%, transparent);
    border-color: color-mix(in srgb, var(--mint) 45%, transparent);
  }
  .eng-tabs button[aria-selected='true']::before { display: none; }
  .eng-dev { order: 2; justify-self: center; align-self: center; }
  .eng-blurb { order: 3; }
}

/* Privacy led with a diagram that has to be read before it reassures. The
   zeroes land first and the figure is available underneath for anyone who
   wants to check the working. */
.absences-lead {
  border-top: 0;
  margin-top: 2.4rem;
  padding-top: 0;
  gap: 1.4rem;
}
.absences-lead b { font-size: clamp(2.1rem, 1.6rem + 2vw, 3rem); }
.airplane-lead { margin-top: 2rem; max-width: 62ch; }

.bound-details {
  margin-top: 2.2rem;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg);
}
.bound-details > summary {
  list-style: none;
  cursor: pointer;
  padding: 1.1rem 1.3rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.bound-details > summary::-webkit-details-marker { display: none; }
.bound-details summary b { font-weight: 560; font-size: 1.02rem; display: block; }
.bound-details summary small { color: var(--ink-3); font-size: 0.86rem; }
.bound-details summary .ind { font-family: var(--fig); font-size: 0.72rem; color: var(--ink-4); flex: none; }
.bound-details[open] summary .ind::after { content: ' \2212'; }
.bound-details:not([open]) summary .ind::after { content: ' +'; }
.bound-details .bound { margin: 0 1.1rem 1.1rem; }

.close-cta { justify-content: center; margin-top: 2.2rem; }

/* ===================================================== ASTRA PASS 2 ===== */

.cta-note {
  color: var(--ink-3);
  font-size: 0.86rem;
  white-space: nowrap;
}
@media (max-width: 420px) { .cta-note { white-space: normal; } }

.deck-teach-inline {
  display: none;
  color: var(--ink-2);
  font-size: 0.95rem;
  margin-bottom: 0.9rem;
}

/* The retention figure was sitting in a row of zeroes labelled as absences,
   where "what we keep" read as a claim about photographs. It is about the
   usage events, so it is stated separately and says what it covers. */
.retention {
  margin-top: 1.6rem;
  max-width: 62ch;
  color: var(--ink-2);
  font-size: 0.95rem;
  line-height: 1.6;
  border-left: 2px solid color-mix(in srgb, var(--mint) 45%, transparent);
  padding-left: 1.1rem;
}
.retention b { color: var(--mint); font-weight: 600; }
.absences-lead { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

/* The feature frame was small relative to the space around it, so the
   selected screen was not readable at ordinary viewing distance. */
.eng-dev .dev { --dev-w: 372px; }
.eng-side { max-width: 600px; }

@media (max-width: 900px) {
  .eng-side { max-width: none; }
  .eng-dev .dev { --dev-w: 300px; }

  /* The gate explained the safeguard without showing it in the same viewport. */
  .gate-grid { display: flex; flex-direction: column; }
  .gate-grid > div:first-child { display: contents; }
  .gate-grid .chapter { order: 1; }
  .gate-grid h2 { order: 2; }
  .gate-grid .lede-v2 { order: 3; }
  .gate-dev { order: 4; margin-block: 0.6rem 1.4rem; }
  .gate-fig-el { order: 5; margin-top: 0; }

  .deck-teach-inline { display: block; }
}

/* ===================================================== ASTRA PASS 3 ===== */

/* A three row ledger reads at a glance where the retention paragraph had to be
   read. Same facts, same precision, far less work. */
.ledger {
  margin: 1.8rem 0 0;
  max-width: 68ch;
  border-top: 1px solid var(--line);
}
.ledger > div {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr);
  gap: 0.4rem 1.6rem;
  padding: 0.95rem 0;
  border-bottom: 1px solid var(--line);
}
.ledger dt {
  font-family: var(--fig);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mint);
  padding-top: 0.2rem;
}
.ledger dd {
  margin: 0;
  color: var(--ink-2);
  font-size: 0.95rem;
  line-height: 1.55;
}
@media (max-width: 680px) {
  .ledger > div { grid-template-columns: 1fr; gap: 0.35rem; padding: 0.85rem 0; }
}

/* The mobile hero stacked a button, a note, a status line and two rows of
   chips before the phone, which pushed the first duplicate comparison off the
   bottom of the screen. Below 900px the supporting text runs inline. */
@media (max-width: 900px) {
  .hero-cta { gap: 0.7rem 1rem; margin-top: 1.6rem; }
  .hero-cta .cta-note,
  .hero-cta .soon-line { font-size: 0.82rem; }
  /* The chips are reassurance, not the first thing to see. They move below the
     phone so the first duplicate comparison lands inside the first screen.
     The privacy chapter carries the same claim in full further down. */
  .hero-lead-v2 { display: contents; }
  .hero-grid-v2 { row-gap: 1.6rem; }
  .hero-eyebrow { order: 1; }
  .hero-v2 h1 { order: 2; margin-bottom: 1.2rem; }
  .hero-lead-v2 > .lede-v2 { order: 3; }
  .hero-cta { order: 4; margin-top: 0; }
  .hero-dev { order: 5; margin-top: 0.4rem; align-self: center; }
  .trust-v2 {
    order: 6;
    margin-top: 0;
    gap: 0.4rem;
    font-size: 0.68rem;
  }
  .trust-v2 li { padding: 0.28rem 0.6rem; border-radius: 6px; }
}

/* ===================================================== ASTRA PASS 4 ===== */

/* A compression outcome that does not need the tab to be found first. The
   provenance sentence is not optional: these are numbers from one run on one
   test device with a tiny library, and they must not read as a typical saving. */
.eng-example {
  margin-top: 1.4rem;
  padding: 0.95rem 1.1rem;
  border: 1px solid var(--line);
  border-left: 2px solid color-mix(in srgb, var(--mint) 45%, transparent);
  border-radius: 10px;
  background: var(--bg-2);
  color: var(--ink-3);
  font-size: 0.88rem;
  line-height: 1.55;
  max-width: none;
}
.eng-example b { color: var(--ink-2); font-weight: 600; }

/* On mobile the concrete disclosure arrived after most of a viewport of
   assertions. The intro is lighter and the zeroes take two rows, not three. */
@media (max-width: 680px) {
  #privacy > .wrap > .lede-v2 { font-size: 1rem; }
  .absences-lead {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem 0.8rem;
    margin-top: 1.8rem;
  }
  .absences-lead b { font-size: 1.9rem; margin-bottom: 0.2rem; }
  .absences-lead li { font-size: 0.64rem; letter-spacing: 0.04em; }
  .ledger { margin-top: 1.4rem; }
}

/* ==================================================== HERO, REBUILT ===== */
/*
   The first screen was still the v1 composition: a band of type on the left,
   a phone floated on the right, both finishing well above the fold, with the
   same mint pill in the hero body that the header already carries. It read as
   a dark SaaS template regardless of what the rest of the page did.

   design-v2.md asks for three specific things that were written but never
   built: hard-left type in the top third, no button in the hero body because
   the header holds the only CTA, and the device cut by the bottom edge of the
   viewport rather than parked inside a box. This block builds them.

   The result is a first screen with a real structure: the six-dot mark and the
   display type top left, the absence counters on a hairline at the bottom left,
   and the Duplicates screen running its resolve in the bottom right, sliced off
   by the edge of the screen. Nothing else on the web looks like that, and none
   of it needs a colour the app does not already own.
*/

/* 66px is .site-head .wrap min-height. The header is sticky and therefore in
   flow, so the hero has to subtract it to end exactly at the fold. */
.hero-v2 {
  position: relative;
  overflow: hidden;
  min-height: calc(100svh - 66px);
  display: flex;
  flex-direction: column;
  padding-top: clamp(1.2rem, 3vh, 2.4rem);
}
/* The cut is the point. A fade would soften the one edge that has to be hard. */
.hero-v2::after { content: none; }

.hero-inner { flex: 1; display: flex; }
.hero-grid-v2 {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: 1fr;
  gap: clamp(2rem, 4.5vw, 4.5rem);
  align-items: stretch;
}

.hero-lead-v2 {
  display: flex;
  flex-direction: column;
  max-width: 41rem;
  padding-bottom: 0;
}
.hero-top { flex: none; }

/* The six dot mark used to appear twice on the first screen: once in the
   header lockup and again at display size above the headline. Two of the same
   glyph within 100px of each other reads as a rendering fault rather than as
   identity, so only the lockup keeps it. */

.hero-v2 h1 { max-width: 13ch; margin-bottom: 1.4rem; }
.hero-v2 .lede-v2 { max-width: 40ch; }

/* Bottom left, on the same baseline as the cut. Mono counters, not chips:
   chips are what every SaaS page puts under a headline. */
.hero-foot {
  margin-top: auto;
  padding-bottom: clamp(1.4rem, 3.6vh, 2.4rem);
}
.absence-row {
  list-style: none;
  margin: 0;
  padding: 1.05rem 0 0;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem clamp(1.5rem, 3.2vw, 2.9rem);
}
.absence-row li { display: flex; align-items: baseline; gap: 0.5rem; }
.absence-row b {
  font-size: 1.55rem;
  font-weight: 400;
  line-height: 1;
  color: var(--mint);
  letter-spacing: -0.02em;
}
.absence-row span {
  font-family: var(--fig);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.hero-foot .soon-line {
  margin-top: 1rem;
  font-family: var(--fig);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.hero-foot .soon-line svg { width: 12px; height: 13px; }

/* The device is sliced by the fold. It is not in a box with a height: the
   section clips it, which is why the cut lands on the edge of the screen. */
.hero-dev {
  align-self: end;
  height: auto;
  overflow: visible;
  margin-bottom: clamp(-330px, -28vh, -150px);
}
.hero-dev .dev { --dev-w: clamp(310px, 29vw, 428px); }

/* The action, directly under the sentence that earns it. The header pill is
   the only other one on the first screen and it scrolls away with the header
   on a phone, so the body needs its own. The note sits beside it on desktop
   and under it on a phone, where there is no room for both on one line. */
.hero-body-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.7rem 1.2rem;
  margin-top: clamp(1.4rem, 2.6vh, 2.1rem);
}
.hero-body-cta .cta-note {
  font-size: 0.88rem;
  color: var(--ink-3);
}

/* Below 900px the column stacks and the device is not bled off the screen:
   the first duplicate comparison has to land inside the first screen, which it
   cannot do if a third of the frame is under the fold. The counters follow it
   rather than pushing it down, the way they did before this rebuild. */
@media (max-width: 900px) {
  .hero-v2 { min-height: 0; padding-top: 1.4rem; }
  .hero-inner { display: block; }
  .hero-grid-v2 { display: flex; flex-direction: column; row-gap: 0; }
  .hero-lead-v2 { display: contents; }
  .hero-top { order: 1; }
  /* The button and its note stack, and the whole group is kept tight: every
     pixel it spends is a pixel the Duplicates screen loses off the fold. */
  .hero-body-cta { margin-top: 1.1rem; gap: 0.5rem 1rem; }
  .hero-body-cta .btn-demo { padding: 0.75rem 1.5rem; font-size: 0.94rem; }
  .hero-body-cta .cta-note { font-size: 0.82rem; }
  .hero-dev {
    order: 2;
    align-self: center;
    margin: 1.4rem auto 0;
  }
  .hero-dev .dev { --dev-w: min(284px, 76vw); }
  .hero-foot { order: 4; margin-top: 1.8rem; padding-bottom: 0; }
  .absence-row { gap: 0.6rem 1.4rem; }
  .absence-row b { font-size: 1.3rem; }
  .absence-row span { font-size: 0.63rem; letter-spacing: 0.08em; }
}

/* ==================================================== THE FIRST SCREEN === */
/*
   The hero was navy with a mint accent, which is where every dark SaaS page
   starts and ends. The benchmark is blunt about what beats it: Clever Cleaner
   wins on mobile because each chapter is its own saturated ground, so scroll
   depth reads as chapters even when the copy is dense. Its cost is that a
   rainbow leaves it with no brand colour at all.

   So the page takes the structure and refuses the rainbow. It now has three
   grounds, in order, and each one is a colour the app already owns:

     the brand field   --mint, the app's Primary, the first screen
     the work          --navy, every chapter that explains the product
     the gate          --paper, the Review Bin, the one inversion mid scroll

   Flooding the first screen in Primary does three things at once. It is
   unmistakably Goodbyte rather than unmistakably a template, because the colour is
   taken from the app rather than chosen for the page. It puts near black type
   on a bright field at better than 10:1, which is the most legible the page
   ever gets, where the most important sentence is. And it makes the product
   the darkest object on the screen instead of one more navy rectangle on
   navy, so the phone stops competing with its own background and reads large.
*/

.hero-v2 {
  /* Slight, not a showpiece. A steep gradient would drop the small mono type
     below 4.5:1 at the bottom of the field. */
  background:
    radial-gradient(120% 80% at 8% 0%, #2BE5AC 0%, transparent 58%),
    linear-gradient(168deg, var(--mint) 0%, #18CC95 100%);
  color: var(--on-mint);
  --on-mint-2: #05402e;   /* body on the field, about 6.4:1 */
  --on-mint-3: #0a5240;   /* mono labels on the field, about 5:1 */
}

.hero-v2 h1 { color: var(--on-mint); }
.hero-v2 .lede-v2 { color: var(--on-mint-2); }

/* A mint button on a mint field is invisible, so the body CTA inverts exactly
   the way the header pill does above the fold: the app's navy carrying the
   app's brighter mint. That is #06d89f on #0f1b2d, 9.3:1, and the pill itself
   sits on the field at 9.4:1, so both the label and the control's own edge
   clear AA with room to spare. */
.hero-v2 .hero-body-cta .btn-demo {
  background: var(--navy);
  color: var(--mint-bright);
}
.hero-v2 .hero-body-cta .btn-demo:hover {
  background: #071726;
  color: var(--mint-bright);
}
/* #05402e on the field, about 6.4:1. */
.hero-v2 .hero-body-cta .cta-note { color: var(--on-mint-2); }

.hero-v2 .absence-row { border-top-color: color-mix(in srgb, var(--on-mint) 26%, transparent); }
.hero-v2 .absence-row b { color: var(--on-mint); font-weight: 500; }
.hero-v2 .absence-row span { color: var(--on-mint-3); }
.hero-v2 .soon-line { color: var(--on-mint-3); }

/* On a light field the phone is an object sitting on a surface, so it gets the
   shadow that would have been invisible on navy. The hairline stays: it is
   still not a bezel. */
.hero-v2 .dev {
  border-color: rgb(0 0 0 / 0.42);
  box-shadow:
    0 2px 6px rgb(0 37 26 / 0.18),
    0 34px 70px -28px rgb(0 37 26 / 0.55);
}

/* The chapter break. Navy starting hard against mint is the whole point, so
   the hairline that used to separate two navy sections is removed here. */
.sieve-track { border-top: 0; }

/* ---- the header, over the field and after it --------------------------- */
/*
   One class toggle already exists for this: data-stuck flips at 24px of
   scroll. Above the fold the header sits on mint and inverts; past it, it is
   the blurred navy bar it always was. No new script.
*/
.site-head[data-stuck='false'] {
  /* Opaque mint, not transparent. A transparent bar is fine at the very top,
     where there is nothing behind it, but the hero is taller than the viewport
     and a transparent header lets the counters, the wordmark and the navy phone
     scroll straight through it. On a phone the lockup ended up sitting on the
     device screenshot and neither could be read. This is the same flat mint as
     the field, so at rest the seam is invisible. */
  background: var(--mint);
  backdrop-filter: none;
  color: var(--on-mint);
}
.site-head[data-stuck='false'] .wordmark-v2 { color: var(--on-mint); }
/* The mark paints with fill, not color, so setting color alone left six mint
   dots on a mint field. */
.site-head[data-stuck='false'] .wordmark-v2 .mark { fill: var(--on-mint); }
.site-head[data-stuck='false'] .nav a:not(.btn-demo) { color: var(--on-mint-2); }
.site-head[data-stuck='false'] .nav a:not(.btn-demo):hover { color: var(--on-mint); }
/* A mint button on a mint field is invisible, so above the fold the call to
   action is the inverse: the app's navy, with the app's brighter mint on it. */
.site-head[data-stuck='false'] .nav a.btn-demo {
  background: var(--navy);
  color: var(--mint-bright);
}
.site-head[data-stuck='false'] .nav a.btn-demo:hover {
  background: #071726;
  color: var(--mint-bright);
}

@media (max-width: 900px) {
  /* The field has to reach the bottom of the first screen on a phone, or the
     chapter break lands halfway up and reads as a stripe rather than a ground.
     The device sits inside it, which is also what makes the first duplicate
     comparison land above the fold. */
  .hero-v2 { padding-bottom: clamp(2rem, 6vh, 3.4rem); }
}

/* The field has to start at the top of the page, not under the header. The
   header is sticky and therefore in flow, so without this the first 66px of
   the page is the body's navy, the header sits on it as a dark bar, and the
   inverted wordmark and nav render near black on near black. The hero is
   pulled up under it and pads itself back out. */
.hero-v2 {
  margin-top: calc(var(--head-h) * -1);
  padding-top: calc(var(--head-h) + clamp(1.2rem, 3vh, 2.4rem));
  min-height: 100svh;
}
:root { --head-h: 66px; }

@media (max-width: 900px) {
  /* No bleed off the fold on a phone, so no full height either. */
  .hero-v2 { min-height: 0; padding-top: calc(var(--head-h) + 1.2rem); }
}

/* Once the deck is finished the cards no longer drag, so the two prompts that
   teach dragging have to go with them. They sit above .deck-clip in the DOM,
   which is why a sibling selector could not reach them and they stayed on
   screen over the summary. */
.deck-wrap[data-done] .deck-teach-inline,
.deck-wrap[data-done] .deck-lab span:last-child { visibility: hidden; }
