/* =============================================================================
   Nippy Shopper — site stylesheet
   -----------------------------------------------------------------------------
   Hand-authored, self-hosted, zero dependencies. This replaces the previous
   Tailwind-CDN + Alpine-CDN setup so that:
     - the page renders with no third-party request (no FOUC, no CDN outage),
     - a strict `default-src 'self'` CSP is possible (StaticSiteHeadersFilter),
     - the whole visual system lives in one reviewable place.

   Sections
     1. Tokens          6. Header / nav        11. Pricing
     2. Base            7. Hero                12. FAQ
     3. Layout          8. Device mockups      13. Footer
     4. Typography      9. Cards & features    14. Legal / prose pages
     5. Buttons        10. Privacy panel       15. Utilities & motion
   ========================================================================== */

/* 1. Tokens ---------------------------------------------------------------- */

:root {
  color-scheme: light;

  /* Brand — violet is the app's primary, magenta is the logo mark. */
  --brand-050: #f4efff;
  --brand-100: #e7dcff;
  --brand-200: #cdb6ff;
  --brand-400: #8b5cf0;
  --brand-500: #7a45e0;
  --brand-600: #6532cc;
  --brand-700: #5326a8;
  --brand-900: #2a1160;
  --accent-500: #b4259a;
  --accent-600: #97177f;
  --ok-500: #12a06a;
  --ok-050: #e6f7f0;

  /* Neutrals, tinted slightly violet so they sit with the brand. */
  --ink-900: #150c24;
  --ink-800: #241a36;
  --ink-700: #3d3352;
  --ink-500: #635c78;
  --ink-400: #8b849e;
  --bg: #fbfafd;
  --bg-alt: #f4f2f9;
  --surface: #ffffff;
  --surface-2: #ffffff;
  --surface-inset: #f7f5fc;
  --line: #e7e3f0;
  --line-strong: #d8d2e6;
  --overlay: rgba(255, 255, 255, 0.82);
  --badge-bg: #150c24;
  --badge-fg: #ffffff;
  --badge-border: #150c24;

  --grad-brand: linear-gradient(135deg, #6532cc 0%, #b4259a 100%);
  --grad-hero: radial-gradient(
      120% 90% at 78% -10%,
      rgba(180, 37, 154, 0.16) 0%,
      rgba(180, 37, 154, 0) 55%
    ),
    radial-gradient(
      90% 70% at 8% 0%,
      rgba(101, 50, 204, 0.18) 0%,
      rgba(101, 50, 204, 0) 60%
    );

  --shadow-xs: 0 1px 2px rgba(21, 12, 36, 0.06);
  --shadow-sm: 0 2px 10px rgba(21, 12, 36, 0.06);
  --shadow-md: 0 14px 34px -14px rgba(21, 12, 36, 0.22);
  --shadow-lg: 0 40px 70px -32px rgba(21, 12, 36, 0.4);

  --radius-sm: 10px;
  --radius: 16px;
  --radius-lg: 24px;
  --radius-pill: 999px;

  /* The device frame. Tokenised because it is one of the few surfaces that
     cannot simply invert: a frame that is near-black reads as "phone" on a
     light page and as "nothing at all" on a dark one, where it merges into
     --bg. Dark mode gets a lighter frame and a visible outer edge instead. */
  --frame: linear-gradient(160deg, #2a2140 0%, #0f0a1c 100%);
  --frame-rim: rgba(255, 255, 255, 0.06);
  --frame-edge: rgba(21, 12, 36, 0.12);


  /* Screenshot aspect. 600x1233 — the 1440x2960 capture straight down, uncropped,
     which is 9:18.5 and therefore the proportions of the phone it was taken on.
     Cropping the Android navigation bar off squashed this to 9:17.44 and the
     frames read as stubby. Applied to .phone__screen and .shot — never to the
     frame itself, which derives its height from the screen it holds so the two
     can never disagree and the image is never cropped to fit. See
     assets/README.md. */
  --shot-ratio: 600 / 1233;

  --container: 1120px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --section-y: clamp(4rem, 8vw, 7rem);

  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* Dark palette. Declared twice on purpose: once for the OS preference (unless
   the visitor pinned light), once for an explicit toggle, so the toggle wins in
   both directions. Keep the two blocks in sync. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --brand-050: #241a45;
  --brand-100: #2f2159;
  --brand-200: #43307d;
  --brand-400: #a582ff;
  --brand-500: #b295ff;
  --brand-600: #9a74ff;
  --brand-700: #8a5ff5;
  --brand-900: #d9c9ff;
  --accent-500: #f072d4;
  --accent-600: #e058bf;
  --ok-500: #34d399;
  --ok-050: #0d2b21;

  --ink-900: #f6f3fc;
  --ink-800: #e6e0f2;
  --ink-700: #cdc5de;
  --ink-500: #a79fbc;
  --ink-400: #8b83a4;
  --bg: #0c0817;
  --bg-alt: #120c20;
  --surface: #17102a;
  --surface-2: #1d1535;
  --surface-inset: #120c22;
  --line: #2a2140;
  --line-strong: #3a2f55;
  --overlay: rgba(12, 8, 23, 0.78);
  --badge-bg: #ffffff;
  --badge-fg: #0c0817;
  --badge-border: rgba(255, 255, 255, 0.9);
  --frame: linear-gradient(160deg, #40355f 0%, #221a3a 100%);
  --frame-rim: rgba(255, 255, 255, 0.16);
  --frame-edge: rgba(255, 255, 255, 0.14);

  --grad-hero: radial-gradient(
      120% 90% at 78% -10%,
      rgba(240, 114, 212, 0.14) 0%,
      rgba(240, 114, 212, 0) 55%
    ),
    radial-gradient(
      90% 70% at 8% 0%,
      rgba(154, 116, 255, 0.2) 0%,
      rgba(154, 116, 255, 0) 60%
    );

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 14px 34px -14px rgba(0, 0, 0, 0.7);
  --shadow-lg: 0 40px 70px -32px rgba(0, 0, 0, 0.85);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --brand-050: #241a45;
    --brand-100: #2f2159;
    --brand-200: #43307d;
    --brand-400: #a582ff;
    --brand-500: #b295ff;
    --brand-600: #9a74ff;
    --brand-700: #8a5ff5;
    --brand-900: #d9c9ff;
    --accent-500: #f072d4;
    --accent-600: #e058bf;
    --ok-500: #34d399;
    --ok-050: #0d2b21;

    --ink-900: #f6f3fc;
    --ink-800: #e6e0f2;
    --ink-700: #cdc5de;
    --ink-500: #a79fbc;
    --ink-400: #8b83a4;
    --bg: #0c0817;
    --bg-alt: #120c20;
    --surface: #17102a;
    --surface-2: #1d1535;
    --surface-inset: #120c22;
    --line: #2a2140;
    --line-strong: #3a2f55;
    --overlay: rgba(12, 8, 23, 0.78);
  --badge-bg: #ffffff;
  --badge-fg: #0c0817;
  --badge-border: rgba(255, 255, 255, 0.9);
  --frame: linear-gradient(160deg, #40355f 0%, #221a3a 100%);
  --frame-rim: rgba(255, 255, 255, 0.16);
  --frame-edge: rgba(255, 255, 255, 0.14);

    --grad-hero: radial-gradient(
        120% 90% at 78% -10%,
        rgba(240, 114, 212, 0.14) 0%,
        rgba(240, 114, 212, 0) 55%
      ),
      radial-gradient(
        90% 70% at 8% 0%,
        rgba(154, 116, 255, 0.2) 0%,
        rgba(154, 116, 255, 0) 60%
      );

    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.35);
    --shadow-md: 0 14px 34px -14px rgba(0, 0, 0, 0.7);
    --shadow-lg: 0 40px 70px -32px rgba(0, 0, 0, 0.85);
  }
}

/* 2. Base ------------------------------------------------------------------ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink-800);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

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

a {
  color: var(--brand-600);
  text-decoration-color: color-mix(in srgb, var(--brand-600) 35%, transparent);
  text-underline-offset: 3px;
}

a:hover {
  color: var(--brand-700);
}

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 2.5rem 0;
}

:focus-visible {
  outline: 3px solid var(--brand-500);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection {
  background: var(--brand-200);
  color: var(--ink-900);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
}

.skip-link:focus {
  left: 1rem;
  top: 1rem;
  padding: 0.75rem 1.15rem;
  background: var(--brand-600);
  color: #fff;
  border-radius: var(--radius-sm);
  font-weight: 600;
}

/* 3. Layout ---------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow {
  max-width: 780px;
}

.section {
  padding-block: var(--section-y);
}

.section--tight {
  padding-block: clamp(2.5rem, 5vw, 4rem);
}

.section--alt {
  background: var(--bg-alt);
  border-block: 1px solid var(--line);
}

.section__head {
  max-width: 46rem;
  margin-bottom: clamp(2.5rem, 5vw, 3.5rem);
}

.section__head--center {
  margin-inline: auto;
  text-align: center;
}

.grid {
  display: grid;
  gap: clamp(1rem, 2.4vw, 1.5rem);
}

.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 900px) {
  .grid--3,
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

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

/* 4. Typography ------------------------------------------------------------ */

h1, h2, h3, h4 {
  color: var(--ink-900);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.022em;
  margin: 0;
  text-wrap: balance;
}

h1 { font-size: clamp(2.35rem, 5.2vw, 3.9rem); letter-spacing: -0.032em; }
h2 { font-size: clamp(1.85rem, 3.4vw, 2.6rem); letter-spacing: -0.028em; }
h3 { font-size: clamp(1.1rem, 1.6vw, 1.3rem); line-height: 1.25; }
h4 { font-size: 1rem; }

p { margin: 0; }

.lede {
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  line-height: 1.6;
  color: var(--ink-500);
  margin-top: 1.1rem;
  max-width: 40rem;
  text-wrap: pretty;
}

.section__head--center .lede { margin-inline: auto; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.775rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--brand-600);
  margin-bottom: 0.9rem;
}

.eyebrow::before {
  content: "";
  width: 1.5rem;
  height: 2px;
  border-radius: 2px;
  background: var(--grad-brand);
}

.muted { color: var(--ink-500); }
.small { font-size: 0.875rem; }
.tiny { font-size: 0.8rem; }

/* 5. Buttons --------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.8rem 1.4rem;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font: inherit;
  font-size: 0.95rem;
  font-weight: 650;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.16s ease, box-shadow 0.16s ease, background-color 0.16s ease,
    border-color 0.16s ease, color 0.16s ease;
}

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

.btn--primary {
  background: var(--grad-brand);
  color: #fff;
  box-shadow: 0 10px 24px -12px rgba(101, 50, 204, 0.9);
}

.btn--primary:hover {
  color: #fff;
  box-shadow: 0 16px 30px -12px rgba(101, 50, 204, 0.95);
  filter: saturate(1.08);
}

.btn--ghost {
  background: var(--surface);
  color: var(--ink-900);
  border-color: var(--line-strong);
  box-shadow: var(--shadow-xs);
}

.btn--ghost:hover {
  color: var(--ink-900);
  border-color: var(--brand-400);
}

.btn--quiet {
  background: transparent;
  color: var(--ink-700);
  padding-inline: 0.75rem;
}

.btn--quiet:hover { color: var(--ink-900); }

.btn--lg { padding: 1rem 1.75rem; font-size: 1.02rem; }
.btn--sm { padding: 0.55rem 1rem; font-size: 0.875rem; }
.btn--block { width: 100%; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}

/* Store badges — Apple/Google lockups rebuilt as real elements so they scale,
   theme, and stay accessible. Replace with the official artwork before launch
   if legal prefers the exact vendor assets (documentation/WEBSITE.md). */
.store-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 1.15rem 0.65rem;
  min-width: 11.25rem;
  border-radius: 14px;
  background: var(--badge-bg);
  color: var(--badge-fg);
  text-decoration: none;
  border: 1px solid var(--badge-border);
  transition: transform 0.16s ease, box-shadow 0.16s ease, opacity 0.16s ease;
  box-shadow: var(--shadow-sm);
}

.store-badge:hover {
  color: var(--badge-fg);
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

.store-badge svg { flex: none; }
.store-badge__text { display: grid; text-align: left; line-height: 1.15; }
.store-badge__sup { font-size: 0.66rem; letter-spacing: 0.02em; opacity: 0.82; }
.store-badge__name { font-size: 1.02rem; font-weight: 600; letter-spacing: -0.01em; }

.store-badge[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

.store-badge__soon {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border-radius: var(--radius-pill);
  border: 1px solid currentColor;
  margin-left: 0.15rem;
  align-self: center;
}

/* 6. Header / nav ---------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--overlay);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.site-header[data-stuck="true"] {
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-xs);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.02em;
  color: var(--ink-900);
  text-decoration: none;
}

.brand:hover { color: var(--ink-900); }
/* The brand mark ships twice, like the screenshots: logo-mark.svg for the light
   theme and logo-mark-disc.svg — the same mark on a white disc — for the dark one,
   swapped by .themed--light / .themed--dark in §8.

   The disc is baked into the artwork rather than drawn here with padding and
   border-radius, which is how this was done first and was wrong twice over. A
   circle bounds a full-bleed mark by its DIAGONAL, so the CSS had to reserve far
   more padding than it looked like it needed, and every attempt to tune that by eye
   clipped the bags' bottom corners. Worse, the geometry then lived in the
   stylesheet: anyone holding a cached site.css got a clipped logo and no amount of
   redeploying the image fixed it. In the SVG the margin is computed from the ink's
   measured half-diagonal once and cannot drift. */
.brand img {
  width: 2rem;
  height: 2rem;
}

.nav {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.nav a {
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm);
  font-size: 0.925rem;
  font-weight: 550;
  color: var(--ink-700);
  text-decoration: none;
}

.nav a:hover {
  color: var(--ink-900);
  background: var(--brand-050);
}

.nav a[aria-current="page"] { color: var(--brand-600); }

.site-header__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-700);
  cursor: pointer;
  transition: color 0.16s ease, border-color 0.16s ease;
}

.icon-btn:hover { color: var(--ink-900); border-color: var(--brand-400); }
.icon-btn svg { width: 1.15rem; height: 1.15rem; }

/* One button, two glyphs: JS only flips a data attribute. */
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
}

/* Mobile menu is a native <details>, so it opens, closes and is keyboard
   navigable with no JavaScript at all. JS only closes it after an in-page jump. */
.mobile-nav { display: none; }
.mobile-nav > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-700);
  cursor: pointer;
}
.mobile-nav > summary::-webkit-details-marker { display: none; }
.mobile-nav > summary svg { width: 1.15rem; height: 1.15rem; }
.mobile-nav > summary .icon-close,
.mobile-nav[open] > summary .icon-menu { display: none; }
.mobile-nav[open] > summary .icon-close { display: block; }
.mobile-nav[open] > summary { border-color: var(--brand-400); color: var(--brand-600); }

.mobile-nav__panel {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--surface);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-md);
  max-height: calc(100dvh - 4.5rem);
  overflow-y: auto;
}

.mobile-nav__panel ul {
  list-style: none;
  margin: 0;
  padding: 0.75rem 0 1.25rem;
  display: grid;
  gap: 0.15rem;
}

.mobile-nav__panel a {
  display: block;
  padding: 0.75rem 0.5rem;
  border-radius: var(--radius-sm);
  color: var(--ink-800);
  font-weight: 550;
  text-decoration: none;
}

.mobile-nav__panel a:hover { background: var(--brand-050); }
.mobile-nav__panel .btn { margin-top: 0.75rem; }

@media (max-width: 860px) {
  .nav,
  .site-header__actions .btn--primary { display: none; }
  .mobile-nav { display: block; }
}

/* 7. Hero ------------------------------------------------------------------ */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: clamp(3rem, 6vw, 5.5rem) clamp(3.5rem, 7vw, 6rem);
  background: var(--grad-hero);
}

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

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

.hero h1 { margin-top: 0.35rem; }

.hero .lede { font-size: clamp(1.1rem, 1.7vw, 1.3rem); }

.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.85rem 0.4rem 0.5rem;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-xs);
  font-size: 0.825rem;
  font-weight: 600;
  color: var(--ink-700);
}

.tag__dot {
  width: 1.35rem;
  height: 1.35rem;
  border-radius: var(--radius-pill);
  background: var(--grad-brand);
  display: inline-grid;
  place-items: center;
  color: #fff;
}

.tag__dot svg { width: 0.85rem; height: 0.85rem; }

.trust-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 1.35rem;
  margin-top: 1.9rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  list-style: none;
  padding-inline: 0;
}

.trust-row li {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.875rem;
  font-weight: 550;
  color: var(--ink-500);
}

.trust-row svg {
  width: 1.05rem;
  height: 1.05rem;
  color: var(--ok-500);
  flex: none;
}

/* 8. Device mockups -------------------------------------------------------- */
/* Real captures from the app, framed in markup. The frame is CSS (so it themes
   with the page and stays crisp at any density) and only the screen is an
   image. Two frames: Android and iPhone, because both ship at launch and the
   hero is where that has to be obvious without reading anything.

   Screens are 600x1267 JPEGs — a 9/19 crop of a 1080x2400 capture with the
   system nav bar removed. Keep that aspect if you replace them, or the frame's
   aspect-ratio will letterbox them. See assets/README.md. */

.mock {
  position: relative;
  padding-block: 2rem 3.25rem;   /* room under the frames for .phone__label */
}

.mock__phones {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: clamp(0.5rem, 1.8vw, 1.15rem);
}

.phone {
  position: relative;
  flex: none;
  width: min(230px, 45vw);
  aspect-ratio: var(--shot-ratio);
  /* The bezel is proportional, not uniform, and that is the whole trick: taking an
     equal number of pixels off both axes of a 600:1233 box leaves an inner box that
     is *wider* than 600:1233, so a uniformly padded frame can match the image on its
     outside or on its inside but never on both. Scaling the vertical bezel by the
     same 1233/600 keeps the padding box at the image's ratio too, so the frame, the
     screen and the JPEG are all one shape and nothing is cropped or letterboxed.
     It also looks right: the extra height lands where a phone's forehead and chin
     are, which is exactly where .phone::after draws the punch-hole and the pill. */
  --bezel: 0.6rem;
  padding: calc(var(--bezel) * 1233 / 600) var(--bezel);
  border-radius: 2.5rem;
  background: var(--frame);
  /* Three layers, and the third is the one that matters in dark mode: an outer
     1px edge. Without it the frame and the page background are both very dark
     and the iPhone in particular — which has no bright screenshot bleeding to
     its corners — reads as a smudge rather than as a device. */
  box-shadow: var(--shadow-lg), 0 0 0 1px var(--frame-rim) inset,
    0 0 0 1px var(--frame-edge);
}

/* A slight fan, so the pair reads as two devices rather than one wide block. */
.phone--android { transform: translateY(-1rem) rotate(-2deg); z-index: 2; }
.phone--ios { transform: translateY(1rem) rotate(2deg); }

.phone__screen {
  position: relative;
  /* No aspect-ratio of its own: the padding box is already at --shot-ratio, so
     filling it is both simpler and impossible to get out of step with the frame. */
  height: 100%;
  border-radius: 2rem;
  overflow: hidden;
  background: var(--surface-inset);
}

.phone__screen img {
  display: block;
  width: 100%;
  height: 100%;
  /* contain, not cover: the box is already exactly --shot-ratio, so there is
     nothing to crop, and contain means a recrop that misses the ratio letterboxes
     visibly instead of silently eating the edge of the screen. */
  object-fit: contain;
}

/* Android: a punch-hole camera. iOS: the pill. Drawn rather than cropped from
   the capture, so the frame matches the platform it claims to be. */
.phone::after {
  content: "";
  position: absolute;
  top: 1.15rem;
  left: 50%;
  transform: translateX(-50%);
  background: #0b0714;
  border-radius: var(--radius-pill);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.07);
}

.phone--android::after { width: 0.5rem; height: 0.5rem; }
.phone--ios::after { width: 30%; height: 1.05rem; top: 1rem; }

.phone__label {
  position: absolute;
  bottom: -1.9rem;
  left: 0;
  right: 0;
  text-align: center;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-400);
}

/* Floating cards around the phones. */
.mock__card {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.7rem 0.9rem;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--ink-800);
  max-width: 14rem;
  /* Above both frames: .phone--android sets z-index 2 to sit in front of the
     iPhone, which would otherwise clip the card that overlaps it. */
  z-index: 3;
}

.mock__card small {
  display: block;
  font-weight: 500;
  color: var(--ink-500);
  font-size: 0.72rem;
}

.mock__card--live { top: 0; left: max(-3.5rem, -6vw); }
/* Clear of .phone__label, which sits 1.9rem below its frame. */
.mock__card--scan { bottom: 1.75rem; right: max(-3.5rem, -6vw); }

.mock__icon {
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 10px;
  display: grid;
  place-items: center;
  flex: none;
  background: var(--brand-050);
  color: var(--brand-600);
}

.mock__icon--ok { background: var(--ok-050); color: var(--ok-500); }
.mock__icon svg { width: 1.15rem; height: 1.15rem; }

@media (max-width: 1080px) {
  .mock__card--live { left: 0; }
  .mock__card--scan { right: 0; }
}

/* Below this the pair is too small to read, so the second frame goes rather
   than shrinking both into illegibility. The iPhone is the one dropped: the
   shopping list is the screen that has to survive, and the App Store badge in
   the button row above already says iOS exists. */
@media (max-width: 620px) {
  .phone--ios { display: none; }
  .phone--android { width: min(258px, 68vw); transform: none; }
}

@media (max-width: 480px) {
  .mock__card { position: static; max-width: none; margin-top: 0.75rem; }
  /* Once the cards stop floating they follow the frame in normal flow, and
     .phone__label is absolutely positioned 1.9rem *below* that frame — so the
     first card has to clear the label rather than the frame. */
  .mock__card--live { margin-top: 2.9rem; }
  .mock { padding-bottom: 0; }
}

/* A single framed screen, used inline in the "how it works" steps. Lighter than
   .phone — a bezel at that size is noise, not realism. */
.shot {
  display: block;
  width: 100%;
  max-width: 172px;
  /* height:auto is load-bearing, not tidiness. The <img> carries width/height
     attributes (they reserve layout space and stop the section reflowing on
     load), and those map to presentational CSS width/height. With both
     dimensions definite, aspect-ratio is ignored and the image renders at its
     full 1267px intrinsic height — a one-pixel-wide slice of a screenshot.
     Setting height:auto makes the ratio the thing that resolves it. */
  height: auto;
  aspect-ratio: var(--shot-ratio);
  object-fit: contain;
  margin-bottom: 1.15rem;
  border-radius: 1.1rem;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  background: var(--surface-inset);
}

/* The steps go one-per-row below 800px, so the constraint stops being "three of
   these have to fit side by side" and becomes "this is the only thing on the
   line". A 160px screenshot on a 390px phone reads as a stamp rather than as a
   screen, so it gets wider as the grid gets narrower, not narrower with it. */
@media (max-width: 800px) { .shot { max-width: 180px; } }
@media (max-width: 620px) { .shot { max-width: 220px; margin-inline: auto; } }

/* Theme-matched screenshots.
   Every capture ships twice, light and dark, and the pair is swapped with
   display rather than with <picture>/prefers-color-scheme. That is deliberate:
   the header's theme toggle sets data-theme on <html>, which a <source media>
   query cannot see, so a visitor who pinned dark would get a blinding white
   screenshot inside a dark frame. The rules below mirror the token blocks —
   OS preference unless the visitor pinned light, and an explicit toggle wins.
   Keep all three in step. */
.themed--dark { display: none; }

:root[data-theme="dark"] .themed--light { display: none; }
:root[data-theme="dark"] .themed--dark { display: block; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .themed--light { display: none; }
  :root:not([data-theme="light"]) .themed--dark { display: block; }
}

/* 9. Cards & features ------------------------------------------------------ */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.35rem, 2.4vw, 1.85rem);
  box-shadow: var(--shadow-xs);
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.card--hover:hover {
  border-color: var(--brand-200);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.card h3 { margin-bottom: 0.5rem; }
.card p { color: var(--ink-500); font-size: 0.95rem; }

.icon-tile {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 14px;
  display: grid;
  place-items: center;
  margin-bottom: 1.1rem;
  background: var(--brand-050);
  color: var(--brand-600);
  border: 1px solid var(--brand-100);
}

.icon-tile svg { width: 1.4rem; height: 1.4rem; }
.icon-tile--accent { background: color-mix(in srgb, var(--accent-500) 12%, transparent); color: var(--accent-500); border-color: color-mix(in srgb, var(--accent-500) 22%, transparent); }
.icon-tile--ok { background: var(--ok-050); color: var(--ok-500); border-color: color-mix(in srgb, var(--ok-500) 25%, transparent); }

/* Numbered "how it works" steps. */
.steps {
  counter-reset: step;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2.5vw, 2rem);
}

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

.step { position: relative; padding-top: 3.25rem; }

.step::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  top: 0;
  left: 0;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: var(--radius-pill);
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 0.95rem;
  color: #fff;
  background: var(--grad-brand);
}

.step h3 { margin-bottom: 0.4rem; }
.step p { color: var(--ink-500); font-size: 0.95rem; }

/* Split feature blocks. */
.split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

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

.check-list {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.85rem;
}

.check-list li {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  font-size: 0.97rem;
  color: var(--ink-700);
}

.check-list svg {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
  margin-top: 0.15rem;
  color: var(--ok-500);
}

.check-list strong { color: var(--ink-900); }

/* 10. Privacy panel -------------------------------------------------------- */

.panel {
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  overflow: hidden;
}

.panel__head {
  padding: 1.25rem 1.5rem;
  border-bottom: 1px solid var(--line);
  background: var(--surface-inset);
  font-weight: 700;
  color: var(--ink-900);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.panel__head svg { width: 1.2rem; height: 1.2rem; }
.panel__head--ok { color: var(--ok-500); }
.panel__head--ok span { color: var(--ink-900); }

.perm-list { list-style: none; margin: 0; padding: 0.5rem 1.5rem 1.5rem; display: grid; gap: 1.1rem; }
.perm-list li { display: grid; gap: 0.15rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.perm-list li:first-child { border-top: 0; }
.perm-list strong { color: var(--ink-900); font-size: 0.97rem; }
.perm-list span { font-size: 0.9rem; color: var(--ink-500); }

.deny-list { list-style: none; margin: 0; padding: 1.25rem 1.5rem 1.5rem; display: grid; gap: 0.7rem; }
.deny-list li { display: flex; align-items: center; gap: 0.7rem; font-size: 0.95rem; color: var(--ink-700); }
.deny-list svg { width: 1.15rem; height: 1.15rem; flex: none; color: var(--ink-400); }

/* 11. Pricing -------------------------------------------------------------- */

.plans {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  align-items: start;
}

@media (max-width: 940px) { .plans { grid-template-columns: minmax(0, 1fr); max-width: 32rem; margin-inline: auto; } }

.plan {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.75rem 1.5rem;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.plan--featured {
  border-color: transparent;
  box-shadow: var(--shadow-md), 0 0 0 2px var(--brand-500);
}

.plan__ribbon {
  position: absolute;
  top: -0.85rem;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.3rem 0.85rem;
  border-radius: var(--radius-pill);
  background: var(--grad-brand);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.plan__name { font-size: 1.15rem; font-weight: 700; color: var(--ink-900); }
.plan__for { font-size: 0.85rem; color: var(--ink-500); margin-top: 0.15rem; }

.plan__price {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  margin: 1.25rem 0 0.25rem;
}

.plan__amount {
  font-size: clamp(2rem, 3.5vw, 2.5rem);
  font-weight: 700;
  color: var(--ink-900);
  letter-spacing: -0.03em;
  line-height: 1;
}

.plan__period { font-size: 0.9rem; color: var(--ink-500); font-weight: 600; }
.plan__note { font-size: 0.82rem; color: var(--ink-500); min-height: 2.4em; }
.plan__note strong { color: var(--brand-600); }

.plan .btn { margin-top: 1.25rem; }

.plan__features {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 1.35rem 0 0;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 0.7rem;
  font-size: 0.92rem;
  color: var(--ink-700);
}

.plan__features li { display: flex; gap: 0.6rem; align-items: flex-start; }
.plan__features svg { width: 1.1rem; height: 1.1rem; flex: none; margin-top: 0.15rem; color: var(--ok-500); }
.plan__features li[data-off] { color: var(--ink-400); }
.plan__features li[data-off] svg { color: var(--ink-400); }

.price-legal {
  margin-top: 1.75rem;
  font-size: 0.82rem;
  color: var(--ink-500);
  max-width: 46rem;
}

/* Comparison table. */
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }

table.compare {
  width: 100%;
  min-width: 22rem;
  border-collapse: collapse;
  font-size: 0.92rem;
}

table.compare th,
table.compare td {
  padding: 0.9rem 1.1rem;
  text-align: left;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

table.compare thead th {
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-500);
  background: var(--surface-inset);
}

table.compare tbody th { font-weight: 600; color: var(--ink-800); }
table.compare td { color: var(--ink-700); }
table.compare tr:last-child th,
table.compare tr:last-child td { border-bottom: 0; }

/* 12. FAQ ------------------------------------------------------------------ */

.faq { display: grid; gap: 0.75rem; max-width: 48rem; }

.faq details {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.faq details[open] { border-color: var(--brand-200); }

.faq summary {
  cursor: pointer;
  padding: 1.1rem 1.35rem;
  font-weight: 650;
  color: var(--ink-900);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  list-style: none;
}

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

.faq summary::after {
  content: "";
  width: 0.6rem;
  height: 0.6rem;
  flex: none;
  border-right: 2px solid var(--ink-400);
  border-bottom: 2px solid var(--ink-400);
  transform: rotate(45deg);
  transition: transform 0.2s ease;
  margin-top: -0.3rem;
}

.faq details[open] summary::after { transform: rotate(-135deg); margin-top: 0.2rem; }

.faq summary:hover { background: var(--surface-inset); }

.faq__body {
  padding: 0 1.35rem 1.25rem;
  color: var(--ink-500);
  font-size: 0.95rem;
}

.faq__body a { font-weight: 600; }

/* 13. CTA & footer --------------------------------------------------------- */

.cta {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  padding: clamp(2.25rem, 5vw, 3.5rem);
  background: var(--grad-brand);
  color: #fff;
  box-shadow: var(--shadow-md);
}

.cta::after {
  content: "";
  position: absolute;
  inset: auto -10% -60% auto;
  width: 26rem;
  height: 26rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  pointer-events: none;
}

.cta h2 { color: #fff; position: relative; }
.cta p { color: rgba(255, 255, 255, 0.88); position: relative; max-width: 34rem; }
.cta .btn-row { position: relative; }

.cta .btn--ghost {
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.4);
  box-shadow: none;
}

.cta .btn--ghost:hover { background: rgba(255, 255, 255, 0.24); color: #fff; }

.site-footer {
  border-top: 1px solid var(--line);
  background: var(--bg-alt);
  padding-block: clamp(2.5rem, 5vw, 4rem) 2rem;
  margin-top: var(--section-y);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

@media (max-width: 860px) { .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: minmax(0, 1fr); } }

.footer-grid h4 {
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: 0.9rem;
}

.footer-grid ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }
.footer-grid a { color: var(--ink-700); text-decoration: none; font-size: 0.92rem; }
.footer-grid a:hover { color: var(--brand-600); text-decoration: underline; }

.footer-bottom {
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  justify-content: space-between;
  align-items: center;
  font-size: 0.85rem;
  color: var(--ink-500);
}

/* 14. Legal / prose pages -------------------------------------------------- */

.page-head {
  padding-block: clamp(2.5rem, 5vw, 4rem) clamp(1.5rem, 3vw, 2.5rem);
  background: var(--grad-hero);
  border-bottom: 1px solid var(--line);
}

.page-head .lede { margin-top: 0.75rem; }

.updated {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  padding: 0.35rem 0.8rem;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--ink-500);
}

.legal-layout {
  display: grid;
  grid-template-columns: 15rem minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
  padding-block: clamp(2.5rem, 5vw, 4rem);
}

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

.toc {
  position: sticky;
  top: 6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 1.25rem;
}

@media (max-width: 900px) { .toc { position: static; } }

.toc h2 {
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: 0.85rem;
}

.toc ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.45rem; counter-reset: toc; }
.toc a { font-size: 0.875rem; color: var(--ink-700); text-decoration: none; }
.toc a:hover { color: var(--brand-600); }

.prose { max-width: 46rem; color: var(--ink-700); }
.prose > * + * { margin-top: 1.05rem; }
.prose h2 {
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  margin-top: 2.75rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--line);
  scroll-margin-top: 6rem;
}
.prose h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.prose h3 { font-size: 1.03rem; margin-top: 1.75rem; }
.prose ul, .prose ol { margin: 1rem 0 0; padding-left: 1.35rem; display: grid; gap: 0.5rem; }
.prose li { padding-left: 0.2rem; }
.prose strong { color: var(--ink-900); }
.prose code {
  font-family: var(--font-mono);
  font-size: 0.875em;
  background: var(--surface-inset);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.1em 0.35em;
}

.callout {
  border: 1px solid var(--brand-200);
  background: var(--brand-050);
  border-radius: var(--radius);
  padding: 1.15rem 1.35rem;
  color: var(--ink-800);
  font-size: 0.95rem;
}

.callout strong { color: var(--ink-900); }
.callout--plain { border-color: var(--line); background: var(--surface-inset); }

/* 15. Utilities & motion --------------------------------------------------- */

.stack > * + * { margin-top: 1rem; }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.5rem; }
.mt-4 { margin-top: 2rem; }
.mt-5 { margin-top: 2.75rem; }
.center { text-align: center; }
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

[hidden] { display: none !important; }

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

@media print {
  .site-header, .site-footer, .btn-row, .toc, .theme-toggle { display: none !important; }
  body { background: #fff; color: #000; }
  .prose { max-width: none; }
}

/* Utility classes used in place of inline style attributes — the site's CSP is
   `style-src 'self'`, which blocks inline styles including style="" on an element. */
.u-measure { max-width: 22rem; }
.u-center-inline { margin-inline: auto; }
.u-row-center { justify-content: center; }
.u-on-brand { color: #fff; }
.u-on-brand:hover { color: #fff; }
.u-flush { padding: 1rem 0 0; }
/* An ordered list of steps: the check icons in the markup give way to numbers. */
.num-list { counter-reset: nippy-step; }
.num-list > li { align-items: center; }
.num-list > li svg { display: none; }
.num-list > li::before {
  counter-increment: nippy-step;
  content: counter(nippy-step);
  flex: none;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: var(--radius-pill);
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  font-weight: 700;
  color: #fff;
  background: var(--grad-brand);
}
.u-hero-center {
  min-height: 52vh;
  display: grid;
  place-items: center;
  text-align: center;
}
