/* Swippr — marketing & compliance site.
   Brand tokens mirror the app (docs/branding.md): teal seed #0F857B,
   light surface #F7FAF9, keep emerald / delete rose semantics, platform
   system font (deliberate: matches the app, and the app's size pillar),
   radius: buttons 16 / cards 20 / phone shell 46, motion 160/220/320ms
   strong ease-out. One accent family: teal. Light theme only for now.
   Feature storytelling follows the One Goal site's "moments" pattern
   (~/Herd/one-goal-web): verb step, headline, copy, real screenshot in
   a phone bezel. */

:root {
  --bg: #f7faf9;
  --surface: #ffffff;
  --text: #17211f;
  --muted: #566360;
  --faint: #7d8a86;
  --teal: #0f857b;
  --teal-ink: #0a5b53;
  --teal-bright: #16a48f;
  --keep: #1d9e6f;
  --keep-bg: #dcf3e8;
  --keep-ink: #08543a;
  --delete: #db4a54;
  --delete-bg: #fbe4e6;
  --delete-ink: #7a1a20;
  --line: rgba(23, 33, 31, 0.1);
  --btn-bg: #0f857b;
  --btn-text: #ffffff;
  --bezel: #10201d;
  --shadow-tint: rgba(10, 91, 83, 0.16);
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
    Roboto, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
video {
  max-width: 100%;
  display: block;
}

.wrap {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 24px;
}

/* ── Nav ─────────────────────────────────────────────────────────────── */
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 68px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 1.125rem;
  color: var(--text);
  text-decoration: none;
  letter-spacing: -0.01em;
}

.brand img {
  width: 26px;
  height: 26px;
  border-radius: 7px;
}

/* Wider link padding grows the touch target; the tighter gap and negative
   right margin keep the visual rhythm and right-edge alignment unchanged. */
.nav-links {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-right: -10px;
}

.nav-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9375rem;
  padding: 10px;
  transition: color 160ms var(--ease-out);
}

.nav-links a:hover,
.nav-links a:focus-visible {
  color: var(--text);
}

/* ── Buttons ─────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 0 24px;
  border-radius: 16px;
  background: var(--btn-bg);
  color: var(--btn-text);
  font-weight: 600;
  font-size: 1rem;
  white-space: nowrap;
  text-decoration: none;
  border: none;
  transition: transform 160ms var(--ease-out), opacity 160ms var(--ease-out);
}

.btn:hover {
  opacity: 0.92;
}

.btn:active {
  transform: scale(0.97);
}

.btn:focus-visible {
  outline: 2px solid var(--teal-ink);
  outline-offset: 3px;
}

/* ── Phone frame (wraps the real app, never a fake UI) ───────────────── */
/* The aspect ratio lives on the media, not the frame: iOS Safari resolves
   height:100% inside an aspect-ratio box unreliably, letting the screenshot
   overflow the bezel. Sized this way the frame simply wraps the media, and
   the ratio still reserves space before the video/image loads. */
.phone {
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
  background: var(--bezel);
  border-radius: 46px;
  padding: 10px;
  overflow: hidden;
  box-shadow: 0 50px 90px -28px var(--shadow-tint),
    0 0 0 1px rgba(23, 33, 31, 0.05);
}

.phone video,
.phone img {
  width: 100%;
  height: auto;
  aspect-ratio: 610 / 1302;
  object-fit: cover;
  border-radius: 36px;
  background: #f5f8f7;
}

.phone.lg {
  max-width: 320px;
}

/* ── Hero ────────────────────────────────────────────────────────────── */
/* padding-block keeps .wrap's 24px side padding intact; a `padding` shorthand
   here would zero it out (same specificity, later in the sheet) and pin text
   to the screen edge on mobile. Same rule for .wins and .moments below. */
.hero {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 56px;
  align-items: center;
  padding-block: 48px 96px;
}

/* Pre-launch status. Sits above the h1 so availability reads before the pitch.
   Scoped under .hero so it outranks the generic `.hero p` rule below. */
.hero .badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 18px;
  padding: 7px 14px;
  border-radius: 999px;
  background: var(--keep-bg);
  color: var(--keep-ink);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.hero .badge::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.hero .btn-note {
  margin: 16px 0 0;
  font-size: 0.9375rem;
  color: var(--muted);
  max-width: 34ch;
}

.hero h1 {
  margin: 0 0 16px;
  font-size: clamp(2.375rem, 5vw, 3.5rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.04;
}

.hero p {
  margin: 0 0 28px;
  font-size: 1.1875rem;
  line-height: 1.55;
  color: var(--muted);
  max-width: 36ch;
}

/* ── Swipe carousel (the only moment that needs two frames) ─────── */
/* The copy beside this one promises two outcomes and tags them "Right to keep"
   and "Left to clean". One frame can only ever show one of them, so this
   moment carries both and pages between them. Every other moment stays a
   single phone, which is what keeps this one reading as deliberate.

   Built on scroll-snap rather than a script, so with JavaScript off it stays a
   real horizontally scrollable strip with both cards reachable, rather than
   one card and a dead control. The dots are the enhancement and stay hidden
   until the `.js` class says they will work. Same rule the reveal animation
   follows, and it exists because AI crawlers render CSS without running JS. */
.carousel {
  position: relative;
}

.carousel-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.carousel-track::-webkit-scrollbar {
  display: none;
}

.carousel-slide {
  flex: 0 0 100%;
  display: flex;
  justify-content: center;
  scroll-snap-align: center;
}

.carousel .phone {
  max-width: 260px;
}

/* Hidden without JS: a dot that cannot page is worse than no dot. */
.carousel-dots {
  display: none;
  justify-content: center;
  gap: 4px;
  margin-top: 20px;
}

.js .carousel-dots {
  display: flex;
}

/* The pseudo-element is the visible dot; the button stays 32px so the touch
   target clears the minimum without the dot itself growing. */
.dot {
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: rgba(23, 33, 31, 0.22);
  transition: width 220ms var(--ease-out), background 220ms var(--ease-out);
}

.dot[aria-current="true"]::before {
  width: 22px;
  background: var(--teal);
}

.dot:focus-visible {
  outline: 2px solid var(--teal-ink);
  outline-offset: 2px;
  border-radius: 999px;
}

/* ── Section headings ────────────────────────────────────────────────── */
section h2 {
  font-size: clamp(1.75rem, 3.5vw, 2.375rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 12px;
}

/* ── Moments (the feature story, One Goal style) ─────────────────────── */
.moments {
  padding-block: 8px 32px;
}

.moment {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(40px, 6vw, 80px);
  align-items: center;
}

.moment + .moment {
  margin-top: clamp(64px, 9vw, 112px);
}

.moment.flip .moment-copy {
  order: 2;
}

.moment-copy .step {
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--teal);
  margin: 0 0 12px;
}

.moment-copy h3 {
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 14px;
}

.moment-copy p.body {
  margin: 0;
  color: var(--muted);
  line-height: 1.6;
  max-width: 52ch;
}

.swipe-line {
  display: flex;
  gap: 12px;
  margin-top: 20px;
  font-weight: 600;
  font-size: 0.9375rem;
  flex-wrap: wrap;
}

.tag {
  display: inline-flex;
  align-items: center;
  border-radius: 12px;
  padding: 8px 14px;
}

.tag.keep {
  background: var(--keep-bg);
  color: var(--keep-ink);
}

.tag.clean {
  background: var(--delete-bg);
  color: var(--delete-ink);
}

/* ── Color-block statement (the differentiator) ──────────────────────── */
.statement-band {
  background: linear-gradient(150deg, #10897e, #0a5b53);
  margin: clamp(72px, 10vw, 120px) 0 0;
  padding: clamp(64px, 9vw, 104px) 0;
  text-align: center;
}

.statement-band h2 {
  color: #ffffff;
  margin: 0 auto 14px;
  max-width: 22ch;
}

.statement-band p {
  color: rgba(255, 255, 255, 0.85);
  margin: 0 auto;
  max-width: 52ch;
  font-size: 1.0625rem;
}

/* Inverted button so the mid-page CTA reads against the teal band. */
.statement-band .btn {
  margin-top: 32px;
  background: #ffffff;
  color: var(--teal-ink);
}

.statement-band .btn:focus-visible {
  outline-color: #ffffff;
}

/* ── The wins (asymmetric grid + bordered list) ──────────────────────── */
/* Sits between the hero and the moments zigzag: the hero's own bottom
   padding supplies the gap above, so only the space below is set here. */
.wins {
  padding-block: 8px clamp(72px, 10vw, 112px);
}

.wins-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(40px, 6vw, 88px);
  align-items: center;
}

.wins-list {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
}

.wins-list li {
  padding: 18px 0;
  border-top: 1px solid var(--line);
}

.wins-list li:last-child {
  border-bottom: 1px solid var(--line);
}

.wins-list b {
  font-weight: 600;
}

.wins-list span {
  display: block;
  color: var(--muted);
  font-size: 0.98rem;
  margin-top: 3px;
}

/* ── Tiers (free vs Pro) ─────────────────────────────────────────────── */
/* One bordered panel split by a hairline, not two floating cards. Two cards
   would read as two products competing, and they cannot be balanced anyway:
   free has twice the rows, because free is the product. A single object says
   "here is the difference" instead. */
.tiers {
  /* padding-block, never the padding shorthand: this element is also .wrap,
     and the shorthand wipes out .wrap's 24px gutter, which put the copy hard
     against the viewport edge on a phone. */
  padding-block: clamp(56px, 8vw, 88px);
  border-top: 1px solid var(--line);
}

.tiers h2 {
  margin-bottom: 10px;
}

.tiers .lede {
  color: var(--muted);
  max-width: 54ch;
  margin: 0 0 clamp(28px, 4vw, 40px);
}

.tier-panel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--surface);
  overflow: hidden;
}

.tier {
  padding: clamp(24px, 3vw, 32px) clamp(22px, 2.6vw, 30px);
}

/* The divider is the panel's own hairline continued, so the two halves read as
   one comparison rather than two boxes that happen to touch. */
.tier + .tier {
  border-left: 1px solid var(--line);
}

/* The paid half carries the tint, never the free half: the wash marks which
   side costs money and must not read as the recommended one. */
.tier-pro {
  background: color-mix(in srgb, var(--teal) 4%, var(--surface));
}

.tier-name {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  margin: 0;
}

.tier-pro .tier-name {
  color: var(--teal-ink);
}

.tier-price {
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.45;
  margin: 6px 0 22px;
}

.tier-price b {
  color: var(--text);
  font-weight: 600;
}

.tier ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Rows, with the same hairline rhythm the wins list uses, so this section
   belongs to the page rather than arriving from a pricing template. */
.tier li {
  color: var(--muted);
  font-size: 0.96rem;
  line-height: 1.5;
  padding: 11px 0 11px 26px;
  border-top: 1px solid var(--line);
  position: relative;
}

.tier li:first-child {
  border-top: none;
  padding-top: 0;
}

.tier li:first-child::before {
  top: 6px;
}

/* A drawn tick rather than a glyph: it inherits the brand colour, stays
   crisp at any zoom, and never depends on an emoji font. */
.tier li::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 17px;
  width: 9px;
  height: 5px;
  border-left: 2px solid var(--teal);
  border-bottom: 2px solid var(--teal);
  border-radius: 1px;
  transform: rotate(-45deg);
}

.tier-note {
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.6;
  margin: 24px 0 0;
  max-width: 64ch;
}

@media (max-width: 760px) {
  .tier-panel {
    grid-template-columns: 1fr;
  }

  /* The divider follows the stacking direction, or the two halves lose the
     edge that separated them. */
  .tier + .tier {
    border-left: none;
    border-top: 1px solid var(--line);
  }
}

/* ── Trust columns ───────────────────────────────────────────────────── */
/* Last section on the page, so it carries the closing bottom space. */
.trust {
  padding: clamp(56px, 8vw, 88px) 0 clamp(72px, 10vw, 104px);
  border-top: 1px solid var(--line);
}

/* The color band already separates; a hairline against it reads as a stray line. */
.statement-band + .trust {
  border-top: none;
}

.trust h2 {
  margin-bottom: 28px;
}

.trust-cols {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
}

.trust-cols h3 {
  font-size: 1.0625rem;
  font-weight: 600;
  margin: 0 0 8px;
}

.trust-cols p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9675rem;
  line-height: 1.6;
}

/* Scoped to the columns so it can't outrank .btn on the closing CTA below. */
.trust-cols a {
  color: var(--teal);
  text-decoration: none;
  font-weight: 500;
}

.trust-cols a:hover {
  text-decoration: underline;
}

/* Terminal CTA, folded into .trust so the page ends on one closing beat. */
.trust-cta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px 20px;
  margin-top: clamp(40px, 6vw, 56px);
}

.trust-cta p {
  margin: 0;
  color: var(--muted);
  font-size: 1.0625rem;
}

/* ── Reveal on scroll (JS adds .in; reduced motion opts out in JS) ─────
   Scoped to .js (set by an inline script in <head>) so that without
   JavaScript every block renders visible instead of stuck at opacity 0.
   AI crawlers do not execute JS, and this wraps all of <main>. */
.js .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 480ms var(--ease-out), transform 480ms var(--ease-out);
}

.js .reveal.in {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .js .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .hero > * {
    animation: rise 480ms var(--ease-out) both;
  }

  .hero > *:nth-child(2) {
    animation-delay: 90ms;
  }

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

/* ── Article pages (privacy, support) ────────────────────────────────── */
.article {
  max-width: 680px;
  margin: 0 auto;
  padding: 48px 0 96px;
}

.article h1 {
  font-size: clamp(2rem, 4vw, 2.75rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: 0 0 8px;
}

.article .updated {
  color: var(--muted);
  font-size: 0.9375rem;
  margin: 0 0 40px;
}

.article h2 {
  font-size: 1.375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 40px 0 12px;
}

.article h3 {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  margin: 28px 0 8px;
}

.article p,
.article li {
  color: var(--muted);
  line-height: 1.65;
}

.article strong {
  color: var(--text);
  font-weight: 600;
}

.article a {
  color: var(--teal);
  text-decoration: none;
  font-weight: 500;
}

.article a:hover {
  text-decoration: underline;
}

.article .callout {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 20px 24px;
  margin: 24px 0;
}

.article .callout p {
  margin: 0;
}

/* FAQ details */
details {
  border-bottom: 1px solid var(--line);
  padding: 4px 0;
}

details summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--text);
  padding: 16px 0;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
}

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

details summary::after {
  content: "+";
  font-size: 1.25rem;
  color: var(--muted);
  flex-shrink: 0;
  transition: transform 220ms var(--ease-out);
}

details[open] summary::after {
  transform: rotate(45deg);
}

details p {
  margin: 0 0 16px;
}

/* ── Footer ──────────────────────────────────────────────────────────── */
footer {
  border-top: 1px solid var(--line);
  padding: 40px 0 56px;
}

.foot {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
}

.foot .brand {
  font-size: 1rem;
}

.foot-note {
  color: var(--muted);
  font-size: 0.875rem;
  margin: 10px 0 0;
  max-width: 40ch;
}

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

.foot-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9375rem;
}

.foot-links a:hover {
  color: var(--text);
}

/* ── Responsive ──────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  .hero {
    grid-template-columns: 1fr;
    gap: 44px;
    padding-block: 32px 64px;
  }

  .hero p {
    max-width: none;
  }

  .moment,
  .moment.flip {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .moment .moment-copy,
  .moment.flip .moment-copy {
    order: 1;
  }

  .moment .moment-art,
  .moment.flip .moment-art {
    order: 2;
  }

  .moment .phone {
    max-width: 260px;
  }

  .wins-grid {
    grid-template-columns: 1fr;
    gap: 36px;
  }

  .wins-art {
    order: 2;
  }

  .wins-art .phone {
    max-width: 260px;
  }

  .trust-cols {
    grid-template-columns: 1fr;
    gap: 24px;
  }
}

/* Phones: full-width CTAs for thumb reach, and drop the wins screenshot,
   which repeats the payoff shot the Clean moment already shows below. */
@media (max-width: 560px) {
  .btn {
    width: 100%;
  }

  .wins-art {
    display: none;
  }
}
