/* ==========================================================================
   Calivora AI — Global Stylesheet
   --------------------------------------------------------------------------
   Pure CSS. No frameworks, no preprocessor, no external requests.

   TABLE OF CONTENTS
   01. Design tokens
   02. Theme: dark mode
   03. Reset & base
   04. Typography
   05. Layout primitives
   06. Aurora background
   07. Glass surfaces
   08. Buttons
   09. Badges & pills
   10. Header / navigation
   11. Mobile drawer
   12. Hero
   13. Scan badge
   14. Trust strip
   15. Screenshots
   16. Features
   17. How it works
   18. Goals
   19. Privacy first
   20. FAQ accordion
   21. Download CTA
   22. Footer
   23. Legal pages (TOC + prose)
   24. Contact page
   25. Delete account page
   26. Utilities & accessibility
   27. Animations
   28. Responsive
   29. Print
   ========================================================================== */


/* ==========================================================================
   01. Design tokens
   ========================================================================== */

:root {
  /* Brand ----------------------------------------------------------------
     Hex values taken from the shipping app's colour system so the site and
     the product are visually identical. See README "Colour system".         */
  --brand-1: #00b796;                 /* brand green — primary               */
  --brand-2: #00876b;                 /* primary dark — link text, hovers    */
  --brand-3: #2fd0ae;                 /* light tint — highlights, aurora     */
  --brand-tint: #d6f3ec;              /* soft fills, icon tiles              */
  --brand-gradient: linear-gradient(118deg, var(--brand-3) 0%, var(--brand-2) 100%);
  --brand-soft: rgba(0, 183, 150, 0.12);
  --brand-soft-2: rgba(0, 135, 107, 0.10);

  /* Gradient for CLIPPED TEXT only ----------------------------------------
     --brand-gradient starts at #2fd0ae, which measures 1.95:1 against white.
     As a fill behind white icons that is fine; as the colour OF text it is
     unreadable — and it was painting the h1, the trust-strip figures and the
     wordmark. This variant runs the same green family through a darker part
     of the ramp: 3.31:1 at the light end and 5.67:1 at the dark end, so every
     point clears the 3:1 large-text floor. Fills are untouched.             */
  --brand-gradient-text: linear-gradient(118deg, #00a082 0%, #00755d 100%);

  /* Goal accents — the app re-themes per goal using three shades of green.  */
  --goal-lose: #2fd0ae;               /* Lose Weight (lighter)               */
  --goal-maintain: #00b796;           /* Maintain Weight (brand)             */
  --goal-muscle: #007a63;             /* Build Muscle (darker)               */

  /* Danger ---------------------------------------------------------------- */
  --danger: #dc3545;

  /* Surfaces ------------------------------------------------------------- */
  --bg: #ffffff;
  --bg-alt: #f4f7f5;
  --surface: #ffffff;
  --surface-2: #f6fbf9;

  /* Glassmorphism ---------------------------------------------------------
     --glass-border (a near-white rim) was retired in favour of --edge: on a
     white section a white border is invisible, so cards were held together
     by shadow alone. --edge is a neutral hairline that reads on both. */
  --glass: rgba(255, 255, 255, 0.62);
  --glass-strong: rgba(255, 255, 255, 0.82);
  --glass-blur: blur(22px) saturate(180%);
  --glass-fallback: #ffffff;

  /* Ink ------------------------------------------------------------------
     --ink-3 was #677d72, which measured 4.42:1 on white and 4.10:1 on
     --bg-alt: below the 4.5:1 WCAG AA floor for body-size text. It carries
     most of the site's secondary copy (card text, captions, footer links),
     so it was darkened to #5b6f66 — 5.37:1 and 4.98:1. Same hue family,
     same visual hierarchy, now compliant.                                   */
  --ink: #111815;                     /* headings, primary text              */
  --ink-2: #4a5e56;                   /* subtitles, secondary copy   6.94:1  */
  --ink-3: #5b6f66;                   /* captions, footnotes         5.37:1  */

  /* Interactive text ------------------------------------------------------
     --brand-2 measured 4.49:1 on white — a hair under AA. --link is a
     slightly deeper cut of the same green used only for text links and
     focus rings, so the brand palette itself is untouched.                   */
  --link: #007a61;                    /* 5.31:1 on --bg, 4.92:1 on --bg-alt  */
  --focus: #007a61;                   /* focus ring, theme-aware             */

  /* Lines ---------------------------------------------------------------- */
  --line: #e3e8e5;
  --line-strong: rgba(17, 24, 21, 0.20);
  /* Hairline that reads on white, where a white glass border cannot. */
  --edge: rgba(17, 24, 21, 0.07);
  --edge-hover: rgba(17, 24, 21, 0.13);
  /* Top-edge light catch. The single biggest "expensive surface" tell:
     a 1px inner highlight makes a card look lit rather than pasted on. */
  --sheen: inset 0 1px 0 rgba(255, 255, 255, 0.7);

  /* Layered soft shadows --------------------------------------------------
     Each step pairs a tight contact shadow with a wide ambient one, the way
     a real object sits on a surface. Low opacities, long blurs.             */
  --shadow-xs: 0 1px 2px rgba(8, 10, 13, 0.04), 0 1px 1px rgba(8, 10, 13, 0.03);
  --shadow-sm: 0 1px 2px rgba(8, 10, 13, 0.04), 0 5px 12px -6px rgba(8, 10, 13, 0.08);
  --shadow-md: 0 2px 4px rgba(8, 10, 13, 0.04), 0 14px 30px -12px rgba(8, 10, 13, 0.15);
  --shadow-lg: 0 4px 10px -4px rgba(8, 10, 13, 0.06), 0 26px 56px -20px rgba(8, 10, 13, 0.20);
  --shadow-xl: 0 8px 18px -8px rgba(8, 10, 13, 0.08), 0 48px 90px -34px rgba(8, 10, 13, 0.28);
  --shadow-brand: 0 16px 40px -16px rgba(0, 183, 150, 0.50);

  /* Typography ----------------------------------------------------------- */
  --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Segoe UI Variable Display", "Segoe UI", Inter, Roboto, "Helvetica Neue",
    Arial, "Noto Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  /* Fluid type scale ----------------------------------------------------- */
  --step--2: clamp(0.72rem, 0.70rem + 0.10vw, 0.78rem);
  --step--1: clamp(0.82rem, 0.79rem + 0.15vw, 0.90rem);
  --step-0:  clamp(1rem, 0.96rem + 0.18vw, 1.08rem);
  --step-1:  clamp(1.14rem, 1.07rem + 0.34vw, 1.34rem);
  --step-2:  clamp(1.38rem, 1.24rem + 0.70vw, 1.85rem);
  --step-3:  clamp(1.72rem, 1.46rem + 1.25vw, 2.5rem);
  --step-4:  clamp(2.1rem, 1.64rem + 2.25vw, 3.3rem);
  /* Capped at 4.05rem, not 4.85rem. At the old size "Know your macros." could
     not fit the hero's left column on any desktop width, so the headline
     always broke to three lines with "macros." orphaned on its own. 64.8px
     still reads as a display headline and lets the line hold together. */
  --step-5:  clamp(2.5rem, 1.8rem + 3.4vw, 4.05rem);

  /* Spacing & shape ------------------------------------------------------ */
  --space-section: clamp(4.5rem, 3rem + 7vw, 9rem);
  --container: 1200px;
  --container-narrow: 800px;
  --gutter: clamp(1.15rem, 4vw, 2.25rem);
  --radius-xs: 8px;
  --radius-sm: 12px;
  --radius: 18px;
  --radius-lg: 24px;
  --radius-xl: 32px;
  --radius-pill: 999px;

  /* Icon tiles ------------------------------------------------------------
     One scale, so every tinted icon square on the site matches. The glyph
     is always 44% of the tile and the corner radius always 29%.             */
  --tile-lg: 48px;
  --tile-md: 44px;
  --tile-sm: 40px;

  /* Motion ----------------------------------------------------------------
     --ease decelerates, for anything entering or lifting. --ease-soft is
     symmetric, for looping ambient motion. Durations are deliberately short:
     --dur-fast for state changes the finger is waiting on, --dur for hover
     and reveal, --dur-slow only for large surfaces.                         */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-soft: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 0.16s;
  --dur: 0.28s;
  --dur-slow: 0.45s;

  /* Chrome --------------------------------------------------------------- */
  --header-h: 70px;

  /* Logo tile ------------------------------------------------------------
     The official artwork (assets/images/logo.png) is portrait and has an
     opaque background, so it sits inside a square tile painted this colour.
     The value below was sampled directly from the artwork by
     tools/generate-icons.ps1, so the tile and the image blend seamlessly.
     If you ever swap the logo, re-run that script and paste the hex it
     prints here.                                                            */
  --logo-bg: #00b796;

  color-scheme: light;
  accent-color: var(--brand-1);
}


/* ==========================================================================
   02. Theme: dark mode
   --------------------------------------------------------------------------
   Follows the OS by default; the header toggle sets data-theme to override.
   The token block is shared by both selectors to avoid drift.
   ========================================================================== */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0d1210;
    --bg-alt: #0a0f0d;
    --surface: #161d1a;
    --surface-2: #1b2320;

    --glass: rgba(255, 255, 255, 0.045);
    --glass-strong: rgba(255, 255, 255, 0.075);
    --glass-fallback: #121a17;

    --ink: #f0f4f1;
    --ink-2: #b8c4bd;
    --ink-3: #8d9b93;

    /* Against #0d1210 the bright ramp measures 9.68:1, so dark mode keeps it. */
    --brand-gradient-text: var(--brand-gradient);
    --link: #2fd0ae;
    --focus: #2fd0ae;

    --line: rgba(255, 255, 255, 0.10);
    --line-strong: rgba(255, 255, 255, 0.20);
    --edge: rgba(255, 255, 255, 0.09);
    --edge-hover: rgba(255, 255, 255, 0.17);
    --sheen: inset 0 1px 0 rgba(255, 255, 255, 0.06);

    --brand-soft: rgba(0, 183, 150, 0.16);
    --brand-soft-2: rgba(0, 135, 107, 0.18);

    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 5px 12px -6px rgba(0, 0, 0, 0.5);
    --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.4), 0 14px 30px -12px rgba(0, 0, 0, 0.65);
    --shadow-lg: 0 4px 10px -4px rgba(0, 0, 0, 0.5), 0 26px 56px -20px rgba(0, 0, 0, 0.75);
    --shadow-xl: 0 8px 18px -8px rgba(0, 0, 0, 0.55), 0 48px 90px -34px rgba(0, 0, 0, 0.85);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg: #0d1210;
  --bg-alt: #0a0f0d;
  --surface: #161d1a;
  --surface-2: #1b2320;

  --glass: rgba(255, 255, 255, 0.045);
  --glass-strong: rgba(255, 255, 255, 0.075);
  --glass-fallback: #121a17;

  --ink: #f0f4f1;
  --ink-2: #b8c4bd;
  --ink-3: #8d9b93;

  /* Against #0d1210 the bright ramp measures 9.68:1, so dark mode keeps it. */
  --brand-gradient-text: var(--brand-gradient);
  --link: #2fd0ae;
  --focus: #2fd0ae;

  --line: rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.20);
  --edge: rgba(255, 255, 255, 0.09);
  --edge-hover: rgba(255, 255, 255, 0.17);
  --sheen: inset 0 1px 0 rgba(255, 255, 255, 0.06);

  --brand-soft: rgba(0, 183, 150, 0.16);
  --brand-soft-2: rgba(0, 135, 107, 0.18);

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 5px 12px -6px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.4), 0 14px 30px -12px rgba(0, 0, 0, 0.65);
  --shadow-lg: 0 4px 10px -4px rgba(0, 0, 0, 0.5), 0 26px 56px -20px rgba(0, 0, 0, 0.75);
  --shadow-xl: 0 8px 18px -8px rgba(0, 0, 0, 0.55), 0 48px 90px -34px rgba(0, 0, 0, 0.85);

  color-scheme: dark;
}


/* ==========================================================================
   03. Reset & base
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 20px);
}

body {
  position: relative;
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.65;
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Prevents background scroll while the mobile drawer is open. */
body.is-locked { overflow: hidden; }

img, svg, picture, video {
  display: block;
  max-width: 100%;
  height: auto;
}

button, input, textarea, select { font: inherit; color: inherit; }

a { color: inherit; text-decoration: none; }

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

::selection { background: var(--brand-1); color: #fff; }


/* ==========================================================================
   04. Typography
   ========================================================================== */

/* Optical rule: as type gets larger, tracking tightens and leading closes up;
   as it gets smaller, both open back out. A single line-height across six
   levels makes small headings feel cramped and large ones feel loose. */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 0.6em;
  font-weight: 700;
  text-wrap: balance;
  color: var(--ink);
}

h1 { font-size: var(--step-5); line-height: 1.04; letter-spacing: -0.045em; margin-bottom: 0.42em; }
h2 { font-size: var(--step-4); line-height: 1.09; letter-spacing: -0.038em; margin-bottom: 0.5em; }
h3 { font-size: var(--step-2); line-height: 1.2;  letter-spacing: -0.03em; }
h4 { font-size: var(--step-1); line-height: 1.3;  letter-spacing: -0.024em; }
h5, h6 { font-size: var(--step-0); line-height: 1.4; letter-spacing: -0.018em; }

p { margin: 0 0 1.15em; color: var(--ink-2); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

strong { color: var(--ink); font-weight: 650; }
small { font-size: var(--step--1); }

/* Lining, equal-width figures so numbers in tables and stats line up. */
table, .stat__value, time, code { font-variant-numeric: tabular-nums lining-nums; }

.gradient-text {
  background: var(--brand-gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* Clipped gradients drop the descender antialiasing on some engines;
     a hair of padding keeps the 'y' and 'p' tails intact. */
  padding-bottom: 0.06em;
}

.lead {
  font-size: var(--step-1);
  line-height: 1.6;
  letter-spacing: -0.016em;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* A lead directly under a heading should sit closer to it than to the
   paragraph that follows — grouping by proximity. */
.section-head .lead { margin-top: -0.2em; }


/* ==========================================================================
   05. Layout primitives
   ========================================================================== */

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

.container--narrow { max-width: var(--container-narrow); }

.section { position: relative; padding-block: var(--space-section); }
.section--tight { padding-block: clamp(3rem, 2rem + 4vw, 5rem); }

/* Alternating bands are only 4% apart in luminance, which reads as a printing
   artefact rather than a decision. A hairline on each edge makes the change
   deliberate and gives the page a crisp horizontal rhythm. */
.section--alt {
  background: var(--bg-alt);
  border-block: 1px solid var(--line);
}

/* Two alt bands in a row would otherwise show a doubled 2px rule. */
.section--alt + .section--alt { border-top: 0; }

.section-head {
  max-width: 720px;
  margin-bottom: clamp(2.5rem, 1.5rem + 3vw, 4rem);
}

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

/* A centred head reads better slightly narrower than a left-aligned one. */
.section-head--center { max-width: 660px; }

.grid { display: grid; gap: clamp(1rem, 0.6rem + 1.2vw, 1.6rem); }
.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)); }

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 1rem + 4vw, 4.5rem);
  align-items: center;
}


/* ==========================================================================
   06. Aurora background
   --------------------------------------------------------------------------
   Fixed, blurred colour fields behind all content. Purely decorative and
   pointer-transparent, so it never intercepts interaction.
   ========================================================================== */

.aurora {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

/* Ambient colour, not a colour wash.
   At 0.42 the three blobs tinted the entire upper half of every light-mode
   page green: the hero copy sat on mint rather than white, the "premium"
   read collapsed into "themed", and body text lost contrast against its own
   background. 0.18 leaves the same hint of brand warmth at the edges while
   the content area stays white. Dark mode keeps more, because there the
   glow is what separates the page from pure black. */
.aurora__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(100px);
  opacity: 0.18;
  will-change: transform;
}

.aurora__blob--1 {
  top: -18vh;
  left: -8vw;
  width: 52vw;
  height: 52vw;
  min-width: 380px;
  min-height: 380px;
  background: radial-gradient(circle, var(--brand-1), transparent 68%);
  animation: drift-a 26s var(--ease-soft) infinite alternate;
}

.aurora__blob--2 {
  top: -12vh;
  right: -12vw;
  width: 48vw;
  height: 48vw;
  min-width: 340px;
  min-height: 340px;
  background: radial-gradient(circle, var(--brand-2), transparent 68%);
  animation: drift-b 32s var(--ease-soft) infinite alternate;
}

.aurora__blob--3 {
  top: 42vh;
  left: 32vw;
  width: 40vw;
  height: 40vw;
  min-width: 300px;
  min-height: 300px;
  opacity: 0.10;
  background: radial-gradient(circle, var(--brand-3), transparent 68%);
  animation: drift-c 38s var(--ease-soft) infinite alternate;
}

:root[data-theme="dark"] .aurora__blob { opacity: 0.28; }
:root[data-theme="dark"] .aurora__blob--3 { opacity: 0.16; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .aurora__blob { opacity: 0.28; }
  :root:not([data-theme="light"]) .aurora__blob--3 { opacity: 0.16; }
}


/* ==========================================================================
   07. Glass surfaces
   ========================================================================== */

/* Every raised surface on the site is built from these three lines: a hairline
   that reads against white, an inner top highlight, and a layered shadow.
   Applied together they are what separates a "div with a shadow" from a
   surface that looks physically lit. */
.glass {
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--edge);
  box-shadow: var(--sheen), var(--shadow-md);
}

/* Browsers without backdrop-filter get a solid, still-legible surface.
   Kept in sync with every element that opts into --glass-blur; a translucent
   panel with no blur behind it is unreadable, not merely less pretty. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass,
  .header.is-scrolled,
  .card,
  .contact-card,
  .team__member,
  .data-card,
  .goal,
  .faq__item,
  .toc,
  .stat,
  .step__body,
  .panel,
  .prose__intro,
  .eyebrow,
  .page-hero__meta > span,
  .icon-btn,
  .to-top,
  .scan-badge,
  .btn--glass { background: var(--glass-fallback); }

  body.is-locked .header { background: var(--glass-fallback); }
}


/* ==========================================================================
   08. Buttons
   ========================================================================== */

/* Buttons lift 1px on hover, not 2. At 2px the label visibly detaches from
   its baseline and the whole control reads as a toy; 1px plus a deeper
   shadow gives the same affordance and stays composed. The press state
   settles below the resting position and shortens to 120ms, because a
   pressed control has to answer instantly to feel physical. */
.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--bg);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  min-height: 44px;                  /* WCAG 2.5.8 target size */
  padding: 0.82rem 1.6rem;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--step-0);
  font-weight: 620;
  letter-spacing: -0.012em;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background-color var(--dur-fast) ease, border-color var(--dur-fast) ease,
              filter var(--dur-fast) ease, opacity var(--dur-fast) ease;
}

.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }

.btn:active {
  transform: translateY(0.5px);
  box-shadow: var(--shadow-xs);
  transition-duration: 0.12s;
}

/* Solid brand fill. The shadow is tinted with the brand hue rather than
   black, so the glow reads as light coming off the button itself. */
.btn--primary {
  --btn-fg: #fff;
  background: var(--brand-gradient);
  box-shadow: var(--sheen), 0 10px 24px -12px rgba(0, 183, 150, 0.65);
}

.btn--primary:hover {
  box-shadow: var(--sheen), var(--shadow-brand);
  filter: saturate(1.06) brightness(1.03);
}

.btn--primary:active { filter: saturate(1) brightness(0.98); }

.btn--glass {
  --btn-bg: var(--glass-strong);
  --btn-fg: var(--ink);
  border-color: var(--edge);
  box-shadow: var(--sheen), var(--shadow-sm);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}

.btn--glass:hover {
  --btn-bg: var(--surface);
  border-color: var(--edge-hover);
}

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  border-color: var(--line-strong);
  box-shadow: none;
}

.btn--ghost:hover {
  --btn-bg: var(--surface-2);
  border-color: var(--ink-3);
  box-shadow: var(--shadow-sm);
}

.btn--danger {
  --btn-fg: #fff;
  background: linear-gradient(120deg, #e8505f, var(--danger));
  box-shadow: var(--sheen), 0 10px 24px -12px rgba(220, 53, 69, 0.65);
}

.btn--danger:hover { filter: saturate(1.06) brightness(1.03); }

.btn--lg { min-height: 52px; padding: 0.95rem 2.05rem; font-size: var(--step-1); }
.btn--sm { min-height: 40px; padding: 0.5rem 1.1rem; font-size: var(--step--1); }
.btn--block { width: 100%; }

/* The header CTA rendered 41px tall beside two 44px icon buttons, so the three
   controls sat on visibly different optical heights. Matching them squares the
   row up and takes the CTA to the full 44px target. */
.header__actions .btn { min-height: 44px; }

.btn__icon {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  transition: transform var(--dur) var(--ease);
}

.btn:hover .btn__icon { transform: translateX(3px); }
.btn:active .btn__icon { transform: translateX(1px); }


/* ==========================================================================
   09. Badges & pills
   ========================================================================== */

/* Uppercase needs noticeably more tracking than lowercase to stay readable —
   0.02em was set for sentence case and left the caps looking jammed. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.15rem;
  padding: 0.34rem 0.85rem 0.34rem 0.7rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-xs);
  font-size: var(--step--1);
  font-weight: 650;
  letter-spacing: 0.075em;
  color: var(--ink-2);
  text-transform: uppercase;
}

.eyebrow::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--brand-gradient);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.42rem;
  padding: 0.28rem 0.72rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--ink-2);
}

.tag i {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--brand-1);
}

/* Macro dots follow the app's own key. Carbs was #bf5af2, a purple sitting
   one hue-step from protein's #8b5cf6 — at 7px the two chips were
   indistinguishable side by side. Restored to the app's blue. */
.tag--protein i { background: #8b5cf6; }
.tag--carbs i   { background: #0a84ff; }
.tag--fat i     { background: #ff9f0a; }


/* ==========================================================================
   10. Header / navigation
   ========================================================================== */

/* The header starts fully transparent so the hero reads as one uninterrupted
   composition, then materialises into frosted glass once the page moves.
   This is the single most recognisable premium-site behaviour, and it costs
   nothing: the `is-scrolled` class already existed. */
.header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color var(--dur) ease, border-color var(--dur) ease,
              box-shadow var(--dur) ease, backdrop-filter var(--dur) ease;
}

.header.is-scrolled {
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-sm);
}

/* While the drawer is open the header must stay legible over it, whatever
   the scroll position. */
body.is-locked .header {
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom-color: var(--line);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
}

/* Brand lockup ----------------------------------------------------------- */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 700;
  font-size: 1.08rem;
  letter-spacing: -0.032em;
  color: var(--ink);
}

/* Single swap point: replace assets/images/logo.png to rebrand site-wide.
   `contain` guarantees the artwork is never stretched or cropped whatever its
   aspect ratio; the tile behind it is painted --logo-bg so a non-square logo
   reads as a deliberate rounded icon rather than a floating image. */
.brand__logo {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 10px;
  object-fit: contain;
  background: var(--logo-bg);
  box-shadow: var(--sheen), 0 3px 10px -4px rgba(0, 135, 107, 0.55);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

.brand:hover .brand__logo {
  transform: scale(1.04);
  box-shadow: var(--sheen), 0 6px 16px -5px rgba(0, 135, 107, 0.6);
}

.brand--footer .brand__logo {
  width: 38px;
  height: 38px;
  border-radius: 11px;
}

/* The wordmark's "AI" is 17px — under the 18.66px bold threshold for large
   text, so it needs the full 4.5:1. A clipped gradient cannot guarantee that
   across its span, so this one takes the solid link green (5.31:1). It is
   the same hue the gradient ends on, and it appears on every page twice. */
.brand__ai { color: var(--link); }

.brand--footer { font-size: 1.14rem; }

/* Desktop nav ------------------------------------------------------------ */
.nav { display: flex; align-items: center; gap: 0.2rem; }

.nav__link {
  position: relative;
  padding: 0.5rem 0.85rem;
  border-radius: var(--radius-pill);
  font-size: 0.93rem;
  font-weight: 550;
  color: var(--ink-2);
  transition: color var(--dur-fast) ease, background-color var(--dur-fast) ease;
}

.nav__link:hover { color: var(--ink); background: var(--surface-2); }

/* The current page was signalled by weight alone, which is nearly invisible
   next to six other links. A tinted pill plus a brand underline makes it
   unambiguous without shouting. */
.nav__link.is-active {
  color: var(--ink);
  font-weight: 650;
  background: var(--surface-2);
}

.nav__link.is-active::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0.24rem;
  width: 14px;
  height: 2px;
  border-radius: 2px;
  background: var(--brand-gradient);
  transform: translateX(-50%);
}

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

/* Icon buttons -----------------------------------------------------------
   44px, not 40px: WCAG 2.5.8 sets 24px as the floor and Apple's HIG sets
   44pt as the comfortable target. These are the only controls in the header
   on mobile, so they should be the easy ones to hit. */
.icon-btn {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--glass-strong);
  color: var(--ink-2);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  transition: color var(--dur-fast) ease, border-color var(--dur-fast) ease,
              background-color var(--dur-fast) ease, transform var(--dur-fast) var(--ease);
}

.icon-btn:hover {
  color: var(--ink);
  background: var(--surface);
  border-color: var(--edge-hover);
  transform: translateY(-1px);
}

.icon-btn:active { transform: translateY(0.5px) scale(0.96); transition-duration: 0.1s; }

.icon-btn svg { width: 18px; height: 18px; }

/* Show exactly one theme icon, matching the resolved theme. */
.icon-btn .icon-moon { display: none; }
:root[data-theme="dark"] .icon-btn .icon-moon { display: block; }
:root[data-theme="dark"] .icon-btn .icon-sun { display: none; }

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

.nav-toggle { display: none; }


/* ==========================================================================
   11. Mobile drawer
   ========================================================================== */

.mobile-nav {
  position: fixed;
  inset: var(--header-h) 0 0;
  z-index: 99;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  /* env() keeps the last link and the CTA clear of the iOS home indicator. */
  padding: 1.5rem var(--gutter) max(2.5rem, calc(env(safe-area-inset-bottom) + 1.5rem));
  background: var(--bg);
  border-top: 1px solid var(--line);
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility var(--dur);
}

.mobile-nav.is-open { opacity: 1; visibility: visible; transform: translateY(0); }

.mobile-nav__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 52px;
  padding: 0.85rem 0.25rem;
  border-bottom: 1px solid var(--line);
  font-size: var(--step-2);
  font-weight: 650;
  letter-spacing: -0.03em;
  color: var(--ink);
  -webkit-tap-highlight-color: transparent;
  transition: color var(--dur-fast) ease, padding-left var(--dur) var(--ease);
}

/* A small inward nudge on press is the standard mobile-list acknowledgement. */
.mobile-nav__link:active { color: var(--brand-2); padding-left: 0.6rem; }

.mobile-nav__link::after {
  content: "";
  width: 7px;
  height: 7px;
  flex: none;
  border-right: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3);
  transform: rotate(-45deg);
  opacity: 0.55;
}

.mobile-nav .btn { margin-top: 1.75rem; }


/* ==========================================================================
   12. Hero
   ========================================================================== */

/* The bottom pad was as deep as the top one, so the hero and the trust strip
   were separated by ~230px of nothing — they read as unrelated pages rather
   than one opening statement. The strip is the hero's evidence; it should
   sit close enough to feel like part of it. */
.hero {
  position: relative;
  padding-block: clamp(3.5rem, 2rem + 8vw, 7.5rem) clamp(2rem, 1.4rem + 2vw, 3.25rem);
}

/* 1.12 / 0.88 rather than 1.06 / 0.94: the copy column needs the room to
   hold the headline on two lines, and the device shot is capped at 300px
   anyway, so the extra width was going to whitespace. */
.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
  align-items: center;
  gap: clamp(2rem, 1rem + 4vw, 4.5rem);
}

.hero__title { margin-bottom: 0.34em; }

.hero__text {
  max-width: 50ch;
  font-size: var(--step-1);
  line-height: 1.62;
  letter-spacing: -0.014em;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-top: 2.25rem;
}

/* Separated from the buttons by a hairline rather than whitespace alone, so
   the trust line reads as a footnote to the CTA instead of a third action. */
.hero__note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem 1.5rem;
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--ink-3);
}

.hero__note span { display: inline-flex; align-items: center; gap: 0.42rem; }

.hero__note svg {
  width: 15px;
  height: 15px;
  flex: none;
  color: var(--brand-1);
}

/* The CTA block reuses .hero__note inside a centred column. Without this it
   stayed left-aligned above 1000px, floating off-axis under centred copy. */
.cta .hero__note {
  justify-content: center;
  max-width: 620px;
  margin-inline: auto;
}

.hero__visual { position: relative; display: grid; place-items: center; }


/* ==========================================================================
   13. Scan badge (floating pill over the hero screenshot)
   ========================================================================== */

/* Floating scan badge ----------------------------------------------------- */
.scan-badge {
  position: absolute;
  right: -16px;
  bottom: 17%;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--glass-strong);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-lg);
  font-size: 0.8rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--ink);
  white-space: nowrap;
  animation: float 7s var(--ease-soft) infinite reverse;
}

.scan-badge i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--brand-1);
  animation: pulse 2s ease-in-out infinite;
}


/* ==========================================================================
   14. Trust strip
   ========================================================================== */

.stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--edge);
  border-radius: var(--radius-lg);
  background: var(--line);
  overflow: hidden;
  box-shadow: var(--sheen), var(--shadow-md);
}

.stat {
  padding: clamp(1.35rem, 1rem + 1vw, 2rem) clamp(0.9rem, 0.6rem + 1vw, 1.6rem);
  background: var(--glass-strong);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  text-align: center;
  transition: background-color var(--dur) ease;
}

.stat:hover { background: var(--surface); }

/* Reserving two lines of height regardless of content is what keeps the four
   labels on one baseline. "Any Language" wraps and the others do not, so
   without it the strip's captions sat at three different heights. */
.stat__value {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.16em;                 /* exactly two lines at line-height 1.08 */
  font-size: var(--step-3);
  font-weight: 700;
  letter-spacing: -0.042em;
  line-height: 1.08;
  text-wrap: balance;
  background: var(--brand-gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.stat__label {
  display: block;
  margin-top: 0.5rem;
  font-size: var(--step--1);
  line-height: 1.45;
  text-wrap: balance;
  color: var(--ink-3);
}


/* ==========================================================================
   15. Screenshots
   --------------------------------------------------------------------------
   Each .shot holds a placeholder that is swapped for a real <img> later.
   See README → "Adding your screenshots".
   ========================================================================== */

/* The exported screenshots already include a device frame and have had their
   studio background removed, so they are placed directly with no CSS bezel.
   The drop shadow lives here rather than in the image so it adapts to theme. */

.shot__img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 26px 34px rgba(8, 10, 13, 0.22));
  transition: transform 0.45s var(--ease), filter 0.45s var(--ease);
}

:root[data-theme="dark"] .shot__img { filter: drop-shadow(0 26px 34px rgba(0, 0, 0, 0.65)); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .shot__img {
    filter: drop-shadow(0 26px 34px rgba(0, 0, 0, 0.65));
  }
}

/* Horizontal snap rail — shows 8 shots without adding 1,100px of page height,
   and swiping is the natural gesture for a phone gallery on mobile. */
.shots {
  display: flex;
  gap: clamp(1.25rem, 0.8rem + 1.5vw, 2.5rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Bleed to the viewport edges so the rail reads as scrollable. */
  margin-inline: calc(var(--gutter) * -1);
  padding: 0.5rem var(--gutter) 2rem;
  /* Snapped cards would otherwise sit flush against the viewport edge. */
  scroll-padding-inline: var(--gutter);
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
  -webkit-overflow-scrolling: touch;
  transition: scrollbar-color var(--dur) ease;
}

/* The scrollbar is a utility, not decoration: invisible until the rail is
   actually being used, then a soft thumb. */
.shots:hover,
.shots:focus-visible,
.shots:focus-within { scrollbar-color: var(--line-strong) transparent; }

.shots::-webkit-scrollbar { height: 6px; }
.shots::-webkit-scrollbar-track { background: transparent; }

.shots::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: var(--radius-pill);
  transition: background-color var(--dur) ease;
}

.shots:hover::-webkit-scrollbar-thumb,
.shots:focus-within::-webkit-scrollbar-thumb { background: var(--line-strong); }

.shot {
  flex: 0 0 auto;
  width: min(228px, 62vw);
  margin: 0;
  scroll-snap-align: center;
  text-align: center;
}

.shot:hover .shot__img { transform: translateY(-6px) scale(1.01); }

.shot__caption {
  margin: 1.15rem 0 0;
  font-size: 0.95rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1.35;
  text-wrap: balance;
  color: var(--ink);
}

.shot__text {
  margin: 0.3rem 0 0;
  font-size: 0.86rem;
  color: var(--ink-3);
  line-height: 1.5;
  text-wrap: pretty;
}

/* Hint that the rail scrolls; hidden once the user has scrolled it. */
.shots-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.25rem 0 0;
  font-size: var(--step--1);
  color: var(--ink-3);
}

.shots-hint svg { width: 16px; height: 16px; flex: none; }

/* Hero device shot ------------------------------------------------------- */
.hero__shot {
  width: min(300px, 76vw);
  height: auto;
  filter: drop-shadow(0 40px 50px rgba(8, 10, 13, 0.26));
  animation: float 9s var(--ease-soft) infinite;
}

:root[data-theme="dark"] .hero__shot { filter: drop-shadow(0 40px 50px rgba(0, 0, 0, 0.7)); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero__shot {
    filter: drop-shadow(0 40px 50px rgba(0, 0, 0, 0.7));
  }
}

/* Step device shot ------------------------------------------------------- */
.step__shot {
  width: 100%;
  max-width: 190px;
  height: auto;
  margin: 1.4rem auto 0;
  display: block;
  filter: drop-shadow(0 18px 26px rgba(8, 10, 13, 0.2));
}

:root[data-theme="dark"] .step__shot { filter: drop-shadow(0 18px 26px rgba(0, 0, 0, 0.6)); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .step__shot {
    filter: drop-shadow(0 18px 26px rgba(0, 0, 0, 0.6));
  }
}


/* ==========================================================================
   16. Features
   ========================================================================== */

.features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 285px), 1fr));
  gap: clamp(1rem, 0.6rem + 1vw, 1.5rem);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.7rem, 1.25rem + 0.9vw, 2.15rem);
  border: 1px solid var(--edge);
  border-radius: var(--radius-lg);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-sm);
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--dur-slow) var(--ease), border-color var(--dur-slow) ease,
              box-shadow var(--dur-slow) ease;
}

.card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background: linear-gradient(158deg, var(--brand-soft), transparent 58%);
  transition: opacity var(--dur-slow) ease;
}

/* 6px was enough travel to read as a jump. 4px plus a deeper shadow reads as
   the card rising toward the cursor, which is the intended illusion. */
.card:hover {
  transform: translateY(-4px);
  border-color: var(--edge-hover);
  box-shadow: var(--sheen), var(--shadow-lg);
}

.card:hover::after { opacity: 1; }

/* ---------------------------------------------------------------------------
   Icon tiles — one treatment, used everywhere
   ---------------------------------------------------------------------------
   The site previously mixed two idioms: feature cards used a solid gradient
   tile, while contact cards and goals used a soft tint. Twelve saturated
   green squares in one grid also flattened the hierarchy — everything shouted
   equally. Now every tile rests as a soft tint with a brand-coloured glyph and
   fills with the gradient on hover, so the colour becomes a response rather
   than a constant.
   --------------------------------------------------------------------------- */
.card__icon,
.contact-card__icon,
.goal__icon {
  position: relative;
  display: grid;
  place-items: center;
  flex: none;
  border: 1px solid var(--edge);
  background: var(--brand-soft);
  color: var(--brand-2);
  box-shadow: var(--sheen);
  transition: background var(--dur-slow) var(--ease), color var(--dur-slow) ease,
              box-shadow var(--dur-slow) ease, transform var(--dur-slow) var(--ease);
}

.card__icon {
  width: var(--tile-lg);
  height: var(--tile-lg);
  margin-bottom: 1.35rem;
  border-radius: 14px;
}

.card__icon svg { width: 22px; height: 22px; }

.card:hover .card__icon {
  background: var(--brand-gradient);
  color: #fff;
  border-color: transparent;
  box-shadow: var(--sheen), 0 10px 22px -12px rgba(0, 183, 150, 0.85);
  transform: translateY(-1px);
}

.card__title {
  margin: 0 0 0.5rem;
  font-size: var(--step-1);
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.028em;
  text-wrap: balance;
}

.card__text {
  margin: 0;
  font-size: 0.96rem;
  color: var(--ink-3);
  line-height: 1.62;
  text-wrap: pretty;
}

/* Pushes the tag row to the bottom so cards of unequal copy length still
   align their chips along one line. */
.card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: auto 0 0;
  padding: 1.35rem 0 0;
  list-style: none;
}


/* ==========================================================================
   17. How it works
   ========================================================================== */

.steps { display: grid; gap: clamp(1.25rem, 0.8rem + 1.5vw, 2rem); counter-reset: step; }

.step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(1.25rem, 0.8rem + 1.5vw, 2rem);
  align-items: start;
  counter-increment: step;
}

.step__num {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  flex: none;
  border-radius: 50%;
  background: var(--brand-gradient);
  color: #fff;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  /* A soft brand halo separates the marker from the card behind it. */
  box-shadow: var(--sheen), 0 0 0 5px var(--brand-soft),
              0 12px 26px -14px rgba(0, 183, 150, 0.85);
}

.step__num::before { content: counter(step, decimal-leading-zero); }

.step__body {
  padding: clamp(1.4rem, 1.1rem + 0.8vw, 1.9rem);
  border: 1px solid var(--edge);
  border-radius: var(--radius-lg);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-sm);
  transition: border-color var(--dur-slow) ease, box-shadow var(--dur-slow) ease;
}

.step:hover .step__body {
  border-color: var(--edge-hover);
  box-shadow: var(--sheen), var(--shadow-md);
}

.step__title {
  margin: 0 0 0.45rem;
  font-size: var(--step-1);
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.028em;
}

.step__text { margin: 0; color: var(--ink-3); font-size: 0.97rem; line-height: 1.62; }


/* ==========================================================================
   18. Goals
   ========================================================================== */

.goal-list { list-style: none; display: grid; gap: 0.8rem; margin: 0; padding: 0; }

.goal {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.95rem;
  padding: 1.15rem 1.3rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-xs);
  overflow: hidden;
  transition: transform var(--dur) var(--ease), border-color var(--dur) ease,
              box-shadow var(--dur) ease;
}

/* An accent rail that wipes in from the left, rather than the whole row
   sliding sideways. Same read, none of the jitter. */
.goal::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--goal-accent, var(--brand-1));
  transform: scaleY(0);
  transform-origin: 50% 50%;
  transition: transform var(--dur) var(--ease);
}

.goal:hover {
  transform: translateX(3px);
  border-color: var(--edge-hover);
  box-shadow: var(--sheen), var(--shadow-md);
}

.goal:hover::before { transform: scaleY(1); }

.goal__icon {
  width: var(--tile-sm);
  height: var(--tile-sm);
  border-radius: 12px;
}

.goal__icon svg { width: 19px; height: 19px; }

.goal__title {
  margin: 0;
  font-size: var(--step-0);
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -0.022em;
  color: var(--ink);
}

.goal__desc {
  margin: 0.22rem 0 0;
  font-size: var(--step--1);
  color: var(--ink-3);
  line-height: 1.55;
  text-wrap: pretty;
}

/* Per-goal accents. The app re-themes itself with these same three greens. */
.goal--lose     { --goal-accent: var(--goal-lose); }
.goal--maintain { --goal-accent: var(--goal-maintain); }
.goal--muscle   { --goal-accent: var(--goal-muscle); }

.goal--lose .goal__icon     { background: rgba(47, 208, 174, 0.16);  color: #00806a; }
.goal--maintain .goal__icon { background: rgba(0, 183, 150, 0.16);   color: var(--brand-2); }
.goal--muscle .goal__icon   { background: rgba(0, 122, 99, 0.16);    color: var(--goal-muscle); }

:root[data-theme="dark"] .goal--lose .goal__icon     { color: var(--goal-lose); }
:root[data-theme="dark"] .goal--maintain .goal__icon { color: var(--goal-maintain); }
:root[data-theme="dark"] .goal--muscle .goal__icon   { color: var(--brand-3); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .goal--lose .goal__icon     { color: var(--goal-lose); }
  :root:not([data-theme="light"]) .goal--maintain .goal__icon { color: var(--goal-maintain); }
  :root:not([data-theme="light"]) .goal--muscle .goal__icon   { color: var(--brand-3); }
}


/* ==========================================================================
   19. Privacy first
   ========================================================================== */

.panel {
  padding: clamp(1.85rem, 1.3rem + 3vw, 3.5rem);
  border: 1px solid var(--edge);
  border-radius: var(--radius-xl);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-lg);
}

/* Concentric brand rings give the disc depth and stop it reading as a flat
   sticker. Pure box-shadow, so it costs no extra element and no image. */
.shield {
  position: relative;
  width: min(210px, 62%);
  margin-inline: auto;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--brand-gradient);
  color: #fff;
  box-shadow: var(--sheen),
              0 0 0 10px var(--brand-soft),
              0 0 0 22px var(--brand-soft-2),
              var(--shadow-brand);
  animation: float 8s var(--ease-soft) infinite;
}

.shield svg { width: 44%; height: 44%; }

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

.check-list li {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  font-size: 0.97rem;
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* The tick sits in its own tinted disc so the list reads as a set of
   confirmations rather than loose glyphs beside text. */
.check-list svg {
  width: 22px;
  height: 22px;
  flex: none;
  margin-top: 0.1rem;
  padding: 4px;
  border-radius: 50%;
  background: var(--brand-soft);
  color: var(--brand-2);
}

:root[data-theme="dark"] .check-list svg { color: var(--brand-3); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .check-list svg { color: var(--brand-3); }
}


/* ==========================================================================
   20. FAQ accordion
   ========================================================================== */

.faq { max-width: 860px; margin-inline: auto; display: grid; gap: 0.7rem; }

.faq__item {
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-xs);
  overflow: hidden;
  transition: border-color var(--dur) ease, box-shadow var(--dur) ease,
              background-color var(--dur) ease;
}

.faq__item:hover { border-color: var(--edge-hover); }

/* An open panel was previously indistinguishable from a closed one apart
   from the 24px sign. It now lifts onto its own surface with a brand
   border, so the reader can see at a glance which question is answered. */
@supports selector(:has(*)) {
  .faq__item:has([aria-expanded="true"]) {
    background: var(--surface);
    border-color: var(--brand-1);
    box-shadow: var(--sheen), var(--shadow-md);
  }
}

.faq__heading { margin: 0; }

.faq__question {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  min-height: 60px;
  padding: 1.25rem 1.4rem;
  border: 0;
  background: none;
  text-align: left;
  font-size: var(--step-1);
  font-weight: 620;
  line-height: 1.4;
  letter-spacing: -0.026em;
  text-wrap: pretty;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--dur-fast) ease;
}

.faq__question:hover { color: var(--brand-2); }
:root[data-theme="dark"] .faq__question:hover { color: var(--brand-3); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .faq__question:hover { color: var(--brand-3); }
}

.faq__sign {
  position: relative;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  color: var(--ink-2);
  transition: transform var(--dur) var(--ease), background-color var(--dur) ease,
              border-color var(--dur) ease, color var(--dur) ease;
}

.faq__question:hover .faq__sign { border-color: var(--brand-1); color: var(--brand-2); }

.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  inset: 50% 27%;
  height: 1.5px;
  border-radius: 2px;
  background: currentColor;
  transform: translateY(-50%);
  transition: transform var(--dur) var(--ease), opacity var(--dur-fast) ease;
}

.faq__sign::after { transform: translateY(-50%) rotate(90deg); }

/* Plus to minus: the container turns a quarter turn while the vertical
   stroke collapses into the horizontal one. A 180 degree turn — the old
   value — is visually identical to no turn at all on a symmetric plus. */
.faq__question[aria-expanded="true"] .faq__sign {
  transform: rotate(90deg);
  background: var(--brand-soft);
  border-color: transparent;
  color: var(--brand-2);
}

.faq__question[aria-expanded="true"] .faq__sign::after {
  opacity: 0;
  transform: translateY(-50%) rotate(0deg) scaleX(0);
}

/* Height is tweened inline by script.js. */
.faq__answer { height: 0; overflow: hidden; transition: height var(--dur) var(--ease); }

.faq__answer p {
  margin: 0;
  padding: 0 3.2rem 1.4rem 1.4rem;
  color: var(--ink-2);
  font-size: 1rem;
  line-height: 1.68;
  text-wrap: pretty;
}


/* ==========================================================================
   21. Download CTA
   ========================================================================== */

.cta { text-align: center; }
.cta__inner { max-width: 760px; margin-inline: auto; }

.cta__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 2.1rem;
}

/* Google Play style button ------------------------------------------------ */
.store-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  min-height: 52px;
  padding: 0.65rem 1.5rem 0.67rem 1.25rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--bg);
  box-shadow: var(--shadow-sm);
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              filter var(--dur-fast) ease;
}

.store-btn:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-lg);
  filter: brightness(1.12);
}

.store-btn:active {
  transform: translateY(0.5px);
  box-shadow: var(--shadow-xs);
  transition-duration: 0.12s;
}

.store-btn svg { width: 26px; height: 26px; flex: none; }

.store-btn__label { display: flex; flex-direction: column; line-height: 1.18; text-align: left; }
.store-btn__small { font-size: 0.68rem; letter-spacing: 0.07em; text-transform: uppercase; opacity: 0.78; }
.store-btn__big { font-size: 1.06rem; font-weight: 650; letter-spacing: -0.02em; }


/* ==========================================================================
   22. Footer
   ========================================================================== */

.footer {
  padding-block: clamp(3rem, 2rem + 3vw, 4.5rem) 2rem;
  border-top: 1px solid var(--line);
  background: var(--bg-alt);
}

.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  gap: clamp(2rem, 1rem + 3vw, 3.5rem);
}

.footer__about { max-width: 36ch; margin: 1rem 0 0; font-size: 0.94rem; color: var(--ink-3); }

.footer__address {
  margin: 1.15rem 0 0;
  font-size: 0.88rem;
  font-style: normal;
  line-height: 1.65;
  color: var(--ink-3);
}

.footer__title {
  margin: 0 0 1rem;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  color: var(--ink);
}

.footer__list { list-style: none; display: grid; gap: 0.55rem; margin: 0; padding: 0; }

/* Inline-block plus a little vertical padding gives each link a real hit
   area without changing the visual rhythm of the column. */
.footer__list a {
  display: inline-block;
  padding-block: 0.15rem;
  font-size: 0.94rem;
  color: var(--ink-3);
  transition: color var(--dur-fast) ease, transform var(--dur-fast) var(--ease);
}

.footer__list a:hover { color: var(--brand-2); transform: translateX(2px); }

:root[data-theme="dark"] .footer__list a:hover { color: var(--brand-3); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .footer__list a:hover { color: var(--brand-3); }
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: clamp(2.5rem, 2rem + 2vw, 3.5rem);
  padding-top: 1.75rem;
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--ink-3);
}

.footer__bottom p { margin: 0; color: inherit; }

.footer__legal { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.footer__legal a { transition: color 0.2s ease; }
.footer__legal a:hover { color: var(--ink); }


/* ==========================================================================
   23. Legal pages (TOC + prose)
   ========================================================================== */

.page-hero {
  position: relative;
  padding-block: clamp(3rem, 2rem + 4vw, 5rem) clamp(2.25rem, 1.5rem + 2vw, 3.25rem);
  border-bottom: 1px solid var(--line);
}

/* A barely-there brand wash that fades out downward, so the top of a legal
   page still feels part of the product rather than a bare document. Painted
   as the element's own background rather than a negative-z-index layer, so
   it cannot interact with the fixed aurora's stacking context. */
.page-hero {
  background-image: linear-gradient(180deg, var(--brand-soft), rgba(0, 183, 150, 0) 78%);
}

.page-hero__title { margin-bottom: 0.42em; font-size: var(--step-4); }

/* Each fact becomes its own chip. Relying on gap alone made "Last updated",
   "Applies to" and "Contact" read as one run-on line, and a border-based
   separator would leave a stray rule whenever the row wrapped. */
.page-hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: var(--step--1);
  color: var(--ink-3);
}

.page-hero__meta > span {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.34rem 0.8rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen);
  line-height: 1.5;
}

.page-hero__meta strong { color: var(--ink-2); font-weight: 620; }
.page-hero__meta code { padding: 0.05em 0.35em; font-size: 0.92em; }
.page-hero__meta a { color: var(--link); }

/* Breadcrumbs ------------------------------------------------------------- */
.breadcrumbs { margin-bottom: 1.6rem; font-size: var(--step--1); color: var(--ink-3); }

.breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A chevron reads as direction; a slash reads as a date. */
.breadcrumbs li + li::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-right: 0.5rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg) translateY(-1px);
  opacity: 0.45;
}

.breadcrumbs a { transition: color var(--dur-fast) ease; }
.breadcrumbs a:hover { color: var(--brand-2); }
.breadcrumbs [aria-current="page"] { color: var(--ink-2); font-weight: 600; }

:root[data-theme="dark"] .breadcrumbs a:hover { color: var(--brand-3); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .breadcrumbs a:hover { color: var(--brand-3); }
}

/* Two-column layout ------------------------------------------------------- */
.legal-layout {
  display: grid;
  grid-template-columns: 258px minmax(0, 1fr);
  gap: clamp(2rem, 1rem + 3vw, 4rem);
  align-items: start;
}

.toc {
  position: sticky;
  top: calc(var(--header-h) + 24px);
  max-height: calc(100vh - var(--header-h) - 48px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1.4rem 1.1rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-sm);
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}

.toc::-webkit-scrollbar { width: 6px; }
.toc::-webkit-scrollbar-track { background: transparent; }
.toc::-webkit-scrollbar-thumb { background: var(--line); border-radius: var(--radius-pill); }
.toc:hover::-webkit-scrollbar-thumb { background: var(--line-strong); }

.toc__title {
  margin: 0 0 0.9rem;
  padding-inline: 0.55rem;
  font-size: 0.76rem;                 /* 12.2px — stays above the 12px floor */
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.toc ol { display: grid; gap: 0.1rem; margin: 0; padding: 0; list-style: none; }

.toc a {
  position: relative;
  display: block;
  padding: 0.4rem 0.55rem 0.4rem 0.75rem;
  border-radius: 8px;
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--ink-3);
  transition: color var(--dur-fast) ease, background-color var(--dur-fast) ease;
}

.toc a:hover { color: var(--ink); background: var(--surface-2); }

/* A left rail marks position in the document far more legibly than a tint
   alone, especially in a 29-entry list where several rows can be tinted by
   the scroll-spy's rootMargin at once. */
.toc a::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 2px;
  height: 0;
  border-radius: 2px;
  background: var(--brand-gradient);
  transform: translateY(-50%);
  transition: height var(--dur) var(--ease);
}

.toc a.is-current {
  color: var(--brand-2);
  background: var(--brand-soft);
  font-weight: 620;
}

.toc a.is-current::before { height: 62%; }

:root[data-theme="dark"] .toc a.is-current { color: var(--brand-3); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .toc a.is-current { color: var(--brand-3); }
}

/* Prose -------------------------------------------------------------------
   76ch was past the comfortable measure; 68–72 characters is where the eye
   reliably finds the next line without a guide. Slightly looser leading to
   match, because legal copy is read slowly and in long runs. */
.prose { max-width: 70ch; line-height: 1.72; }

.prose > section { scroll-margin-top: calc(var(--header-h) + 24px); }

.prose h2 {
  margin: 3.25rem 0 1.1rem;
  padding-top: 1.85rem;
  border-top: 1px solid var(--line);
  font-size: var(--step-2);
  line-height: 1.25;
  letter-spacing: -0.032em;
}

.prose > section:first-child h2 { margin-top: 0; padding-top: 0; border-top: 0; }

.prose h3 { margin: 2.1rem 0 0.65rem; font-size: var(--step-1); font-weight: 650; line-height: 1.35; }

.prose p, .prose li { color: var(--ink-2); }

.prose ul, .prose ol {
  margin: 0 0 1.15em;
  padding-left: 1.4rem;
  display: grid;
  gap: 0.55rem;
}

.prose li { padding-left: 0.15rem; }
.prose li::marker { color: var(--brand-1); font-weight: 700; }

/* --link, not --brand-2: at 4.49:1 the old link colour sat just under the
   AA floor, and legal pages are almost entirely links and body copy. */
.prose a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--link) 40%, transparent);
  transition: text-decoration-color var(--dur-fast) ease;
}

.prose a:hover {
  text-decoration-thickness: 2px;
  text-decoration-color: currentColor;
}

.prose code {
  padding: 0.15em 0.45em;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: 0.86em;
  color: var(--ink);
  word-break: break-word;
}

.prose__intro {
  padding: 1.35rem 1.5rem;
  margin-bottom: 2.6rem;
  border: 1px solid var(--edge);
  border-left: 3px solid var(--brand-1);
  border-radius: var(--radius-sm);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-xs);
}

.prose__intro p { margin: 0; font-size: 0.97rem; line-height: 1.68; }

/* Tables ------------------------------------------------------------------
   The wrapper paints its own scroll shadows: the two `local` gradients ride
   with the content and mask the `scroll` ones at each end, so a soft edge
   shadow appears only on the side that still has content off-screen. It is
   the clearest way to say "this scrolls" without adding an element or a
   line of JavaScript. */
.table-wrap {
  overflow-x: auto;
  margin: 1.7rem 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background-color: var(--surface);
  background-image:
    linear-gradient(to right, var(--surface) 40%, rgba(255, 255, 255, 0)),
    linear-gradient(to left,  var(--surface) 40%, rgba(255, 255, 255, 0)),
    radial-gradient(farthest-side at 0 50%, rgba(8, 10, 13, 0.13), rgba(8, 10, 13, 0)),
    radial-gradient(farthest-side at 100% 50%, rgba(8, 10, 13, 0.13), rgba(8, 10, 13, 0));
  background-position: left center, right center, left center, right center;
  background-repeat: no-repeat;
  background-size: 44px 100%, 44px 100%, 15px 100%, 15px 100%;
  background-attachment: local, local, scroll, scroll;
  -webkit-overflow-scrolling: touch;
}

/* A three-column comparison genuinely needs the width. A two-column facts
   table does not, and forcing 540px on it made every phone scroll a table
   that would have fitted. `:has` scopes the floor to tables that have a
   header row; without `:has` support the old behaviour is kept. */
table { width: 100%; min-width: 540px; border-collapse: collapse; font-size: 0.92rem; }

@supports selector(:has(*)) {
  table:not(:has(thead)) { min-width: 0; }
}

th, td {
  padding: 0.85rem 1rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
  line-height: 1.6;
}

thead th {
  background: var(--surface-2);
  font-weight: 650;
  font-size: 0.76rem;
  letter-spacing: 0.075em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  border-bottom-color: var(--line-strong);
}

tbody tr { transition: background-color var(--dur-fast) ease; }
tbody tr:hover { background: var(--surface-2); }

tbody tr:last-child td,
tbody tr:last-child th { border-bottom: 0; }

td { color: var(--ink-2); }

tbody th[scope="row"] {
  width: 34%;
  font-weight: 650;
  color: var(--ink);
  background: var(--surface-2);
}

/* Callout -----------------------------------------------------------------
   A 3px accent edge makes the callout scannable at a glance and tells you
   which kind it is before you read a word. */
.callout {
  display: flex;
  gap: 0.9rem;
  padding: 1.25rem 1.4rem;
  margin: 1.9rem 0;
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand-1);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  box-shadow: var(--shadow-xs);
}

.callout svg { width: 20px; height: 20px; flex: none; margin-top: 0.25rem; color: var(--brand-2); }
.callout p { margin: 0; font-size: 0.95rem; line-height: 1.65; text-wrap: pretty; }

.callout--warn {
  border-color: rgba(220, 53, 69, 0.3);
  border-left-color: var(--danger);
  background: rgba(220, 53, 69, 0.06);
}

.callout--warn svg { color: var(--danger); }

:root[data-theme="dark"] .callout svg { color: var(--brand-3); }
:root[data-theme="dark"] .callout--warn svg { color: #ff6b78; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .callout svg { color: var(--brand-3); }
  :root:not([data-theme="light"]) .callout--warn svg { color: #ff6b78; }
}


/* ==========================================================================
   24. Contact page
   ========================================================================== */

.contact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: clamp(1rem, 0.6rem + 1vw, 1.5rem);
}

.contact-card {
  display: flex;
  flex-direction: column;
  padding: clamp(1.7rem, 1.25rem + 0.9vw, 2.15rem);
  border: 1px solid var(--edge);
  border-radius: var(--radius-lg);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-sm);
  transition: transform var(--dur-slow) var(--ease), box-shadow var(--dur-slow) ease,
              border-color var(--dur-slow) ease;
}

.contact-card:hover {
  transform: translateY(-4px);
  border-color: var(--edge-hover);
  box-shadow: var(--sheen), var(--shadow-lg);
}

/* Geometry only — the shared tile treatment lives with .card__icon. */
.contact-card__icon {
  width: var(--tile-md);
  height: var(--tile-md);
  margin-bottom: 1.2rem;
  border-radius: 13px;
}

.contact-card__icon svg { width: 20px; height: 20px; }

.contact-card:hover .contact-card__icon {
  background: var(--brand-gradient);
  color: #fff;
  border-color: transparent;
  box-shadow: var(--sheen), 0 10px 22px -12px rgba(0, 183, 150, 0.85);
  transform: translateY(-1px);
}

.contact-card__title {
  margin: 0 0 0.5rem;
  font-size: var(--step-1);
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.028em;
}

.contact-card__text {
  margin: 0 0 1.5rem;
  font-size: 0.95rem;
  color: var(--ink-3);
  line-height: 1.62;
  text-wrap: pretty;
}

.contact-card__link {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-weight: 620;
  font-size: 0.95rem;
  color: var(--link);
  word-break: break-word;
  transition: gap var(--dur) var(--ease);
}

.contact-card__link svg { width: 15px; height: 15px; flex: none; transition: transform var(--dur) var(--ease); }
.contact-card__link:hover svg { transform: translateX(3px); }

/* Key/value rows ---------------------------------------------------------- */
.info-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.info-list li {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: 1rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--ink-2);
  transition: background-color var(--dur-fast) ease;
}

.info-list li:hover { background: var(--surface-2); }
.info-list li:last-child { border-bottom: 0; }
.info-list b { font-weight: 650; color: var(--ink); }

/* Team -------------------------------------------------------------------- */
.team { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); gap: 1rem; }

.team__member {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 1.15rem 1.3rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-xs);
  transition: transform var(--dur) var(--ease), border-color var(--dur) ease,
              box-shadow var(--dur) ease;
}

.team__member:hover {
  transform: translateY(-3px);
  border-color: var(--edge-hover);
  box-shadow: var(--sheen), var(--shadow-md);
}

.team__avatar {
  width: var(--tile-md);
  height: var(--tile-md);
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--brand-gradient);
  color: #fff;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: -0.02em;
  box-shadow: var(--sheen), 0 0 0 4px var(--brand-soft);
}

.team__name { margin: 0; font-size: 0.97rem; font-weight: 650; color: var(--ink); letter-spacing: -0.02em; }
.team__role { margin: 0; font-size: 0.82rem; color: var(--ink-3); }


/* ==========================================================================
   25. Delete account page
   ========================================================================== */

.delete-hero__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }

.data-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: clamp(1rem, 0.6rem + 1vw, 1.5rem); }

.data-card {
  padding: clamp(1.55rem, 1.2rem + 0.8vw, 2.05rem);
  border: 1px solid var(--edge);
  border-radius: var(--radius-lg);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--sheen), var(--shadow-sm);
}

/* A top accent bar states the card's meaning before the heading is read —
   red for what goes, amber for what stays. */
.data-card--danger {
  border-color: rgba(220, 53, 69, 0.28);
  border-top: 3px solid var(--danger);
}

.data-card--keep {
  border-color: rgba(255, 159, 10, 0.3);
  border-top: 3px solid #ff9f0a;
}

.data-card__title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 1.15rem;
  font-size: var(--step-1);
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.026em;
}

.data-card__title svg { width: 21px; height: 21px; flex: none; }
.data-card--danger .data-card__title svg { color: var(--danger); }
.data-card--keep .data-card__title svg { color: #ff9f0a; }

.data-list { list-style: none; display: grid; gap: 0.75rem; margin: 0; padding: 0; }

.data-list li {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}

.data-list svg { width: 17px; height: 17px; flex: none; margin-top: 0.3rem; }
.data-card--danger .data-list svg { color: var(--danger); }
.data-card--keep .data-list svg { color: #ff9f0a; }

/* Timeline ---------------------------------------------------------------- */
.timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }

.timeline li {
  position: relative;
  display: grid;
  grid-template-columns: 130px minmax(0, 1fr);
  gap: 1.25rem;
  padding: 0 0 2rem 0;
}

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

.timeline__when {
  justify-self: end;
  padding: 0.34rem 0.85rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--brand-soft);
  color: var(--brand-2);
  font-size: 0.82rem;
  font-weight: 650;
  white-space: nowrap;
  height: max-content;
}

:root[data-theme="dark"] .timeline__when { color: var(--brand-3); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .timeline__when { color: var(--brand-3); }
}

.timeline__body { position: relative; padding-left: 1.9rem; }

.timeline__body::before {
  content: "";
  position: absolute;
  top: 0.46rem;
  left: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--brand-gradient);
  box-shadow: var(--sheen), 0 0 0 4px var(--brand-soft);
}

/* Connecting rail between markers.
   This was previously drawn on the <li> at a hard-coded left:139px, but the
   dot lands at 150px + 6px = 156px once the 130px label column and the 20px
   gap are counted — the line ran 17px to the left of every marker it was
   meant to join. Anchoring it to .timeline__body instead makes it track the
   dot automatically, whatever the column width. */
.timeline li:not(:last-child) .timeline__body::after {
  content: "";
  position: absolute;
  top: 1.65rem;
  left: 5px;
  bottom: -2.5rem;              /* clears the li's 2rem gap to the next dot */
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--brand-soft), var(--line) 45%);
}

.timeline__title {
  margin: 0 0 0.28rem;
  font-size: 1.02rem;
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -0.022em;
  color: var(--ink);
}

.timeline__text { margin: 0; font-size: 0.94rem; color: var(--ink-3); line-height: 1.6; text-wrap: pretty; }


/* ==========================================================================
   26. Utilities & accessibility
   ========================================================================== */

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 200;
  transform: translate(-50%, -140%);
  padding: 0.7rem 1.25rem;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  background: var(--ink);
  color: var(--bg);
  font-weight: 620;
  transition: transform 0.2s var(--ease);
}

.skip-link:focus-visible { transform: translate(-50%, 0); }

/* One consistent focus ring everywhere.
   -------------------------------------------------------------------------
   The previous rule also set `border-radius: 6px`. Because :where() adds no
   specificity, the whole selector weighed the same as `.btn` — but sat later
   in the file, so it won. Every pill button, icon button and avatar visibly
   snapped from its own radius to a 6px rectangle the instant it took keyboard
   focus. Dropping the radius declaration lets the outline follow whatever
   shape the element already has.

   The colour is now --focus, which resolves to a deep green on light and a
   bright mint on dark; the old --brand-2 measured 4.2:1 against the dark
   background, which is a weak indicator on the theme where it matters most.
   The white halo underneath guarantees the ring stays visible even when the
   element sits on a brand-coloured or photographic surface. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--focus) 22%, transparent);
}

/* Keyboard focus inside the screenshot rail should frame the rail itself. */
.shots:focus-visible { outline-offset: -2px; border-radius: var(--radius); }

.text-center { text-align: center; }
.mt-lg { margin-top: clamp(2rem, 1.5rem + 2vw, 3rem); }
.mt-md { margin-top: 1.5rem; }
.mb-0 { margin-bottom: 0; }
.nowrap { white-space: nowrap; }

/* Back to top ------------------------------------------------------------- */
.to-top {
  position: fixed;
  right: clamp(1rem, 2vw, 1.75rem);
  /* Clears the iOS home indicator and Android gesture bar. */
  bottom: max(clamp(1rem, 2vw, 1.75rem), calc(env(safe-area-inset-bottom) + 0.75rem));
  z-index: 90;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid var(--edge);
  border-radius: 50%;
  background: var(--glass-strong);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  color: var(--ink);
  box-shadow: var(--sheen), var(--shadow-md);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px) scale(0.9);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
              visibility var(--dur), box-shadow var(--dur) ease, border-color var(--dur) ease;
}

.to-top.is-visible { opacity: 1; visibility: visible; transform: none; }

.to-top:hover {
  border-color: var(--edge-hover);
  box-shadow: var(--sheen), var(--shadow-lg);
  transform: translateY(-2px);
}

.to-top:active { transform: translateY(0) scale(0.94); transition-duration: 0.12s; }
.to-top svg { width: 18px; height: 18px; }


/* ==========================================================================
   27. Animations
   ========================================================================== */

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.8); }
}

@keyframes drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(8vw, 6vh, 0) scale(1.12); }
}

@keyframes drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(-7vw, 9vh, 0) scale(1); }
}

@keyframes drift-c {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-10vw, -7vh, 0) scale(1.15); }
}

/* Scroll reveal — `is-visible` is added by the IntersectionObserver.
   -------------------------------------------------------------------------
   22px over 700ms was far enough and slow enough to be perceived as motion
   in its own right; content that is merely arriving should be felt, not
   watched. 14px over 560ms lands before the eye finishes travelling to it.

   `will-change: opacity, transform` was declared on every .reveal element.
   The homepage has 48 of them, so the compositor was asked to promote 48
   layers at parse time and hold them for the life of the page — a real cost
   on mobile, in exchange for nothing, since opacity and transform are
   already GPU-accelerated properties. Removed. */
/* Scoped to .js, which theme.js sets in <head> before the first paint. With
   scripting blocked the rule never matches, so the page renders normally
   instead of being a blank white column waiting for an observer that will
   never run. */
.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.56s var(--ease), transform 0.56s var(--ease);
}

.js .reveal.is-visible { opacity: 1; transform: none; }

/* Screenshots inside the horizontal rail opt out of the reveal.
   The IntersectionObserver watches the viewport, and shots 6-8 start scrolled
   off the right-hand edge of the rail, so they never intersect and stay at
   opacity 0. The user then swipes and watches blank slots fade in one by one,
   which reads as the gallery failing to load. The rail's own section header
   still animates; the cards inside it are simply present. */
.js .shots .reveal { opacity: 1; transform: none; transition: none; }

.reveal[data-delay="1"] { transition-delay: 0.07s; }
.reveal[data-delay="2"] { transition-delay: 0.14s; }
.reveal[data-delay="3"] { transition-delay: 0.21s; }
.reveal[data-delay="4"] { transition-delay: 0.28s; }
.reveal[data-delay="5"] { transition-delay: 0.35s; }


/* ==========================================================================
   28. Responsive
   ========================================================================== */

/* ---- 1600px and up ------------------------------------------------------
   On a 1920px display a 1200px column leaves 360px of empty margin either
   side. A modest widening keeps the composition generous without letting
   line lengths run past a comfortable measure. */
@media (min-width: 1600px) {
  :root { --container: 1280px; }
  .shot { width: 244px; }
}

/* ---- Tablet and below --------------------------------------------------- */
@media (max-width: 1000px) {
  .hero__inner { grid-template-columns: minmax(0, 1fr); text-align: center; }
  .hero__text, .hero__title { margin-inline: auto; }
  .hero__actions, .hero__note { justify-content: center; }
  .hero__visual { order: -1; }

  /* The trust rule spanning the full column looked arbitrary once the hero
     centred; a fixed measure keeps it tied to the copy above it. */
  .hero__note { max-width: 34rem; margin-inline: auto; }

  .split { grid-template-columns: minmax(0, 1fr); }
  .legal-layout { grid-template-columns: minmax(0, 1fr); }
  .toc { position: static; max-height: none; }

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

@media (max-width: 880px) {
  .nav { display: none; }
  .nav-toggle { display: grid; }

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

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

  .footer__grid { grid-template-columns: minmax(0, 1fr); }
  .footer__bottom { flex-direction: column; align-items: flex-start; }

  .hero__actions .btn, .cta__actions .btn { flex: 1 1 auto; }
  .cta__actions .store-btn { justify-content: center; flex: 1 1 auto; }

  .info-list li { grid-template-columns: minmax(0, 1fr); gap: 0.25rem; }

  .step { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .step__num { width: 48px; height: 48px; font-size: 0.95rem; }

  /* Single column: the label pill now sits above the body, so a vertical
     rail between markers would have to jump over it. */
  .timeline li { grid-template-columns: minmax(0, 1fr); gap: 0.6rem; padding-bottom: 1.75rem; }
  .timeline li:not(:last-child) .timeline__body::after { display: none; }
  .timeline__when { justify-self: start; }
  .timeline__body { padding-left: 1.6rem; }

  .scan-badge { right: -4px; font-size: 0.72rem; }

  .faq__question { padding: 1.1rem; gap: 0.9rem; }
  .faq__answer p { padding: 0 1.1rem 1.2rem; }

  .prose { max-width: none; }
  .panel { border-radius: var(--radius-lg); }
}

/* ---- 560px and below ----------------------------------------------------
   Header overflow fix. At 320px the brand lockup (~109px), the theme toggle,
   the "Get the app" pill (~116px) and the hamburger totalled roughly 337px
   inside a 283px content box, so the row overflowed and the CTA was clipped.
   The drawer already carries a full-width "Get the app" button and the hero
   repeats it immediately below the fold, so the header copy is redundant
   here — dropping it is what most product sites do at this width, and it
   leaves the brand and both controls comfortable. */
@media (max-width: 560px) {
  .header__actions > .btn { display: none; }
  .header__inner { gap: 0.5rem; }
}

/* ---- 520px and below ----------------------------------------------------
   The trust strip is two columns here, roughly 141px per cell. "Any Language"
   at --step-3 (27.5px minimum) could not fit and broke mid-word. */
@media (max-width: 520px) {
  .stat { padding: 1.15rem 0.85rem; }
  .stat__value { font-size: var(--step-2); letter-spacing: -0.03em; }
  /* The label deliberately keeps --step--1 (13px). Shrinking it to --step--2
     dropped four captions to 11.5px, and the smaller figure above already
     buys back the room they needed. */

  .shots { scroll-snap-type: x proximity; }
}

/* ---- 400px and below ----------------------------------------------------
   Small-phone breathing room: tighter gutters buy back horizontal space,
   and full-width actions stop buttons from sitting in ragged pairs. */
@media (max-width: 400px) {
  :root { --gutter: 1rem; }

  .brand { font-size: 1rem; gap: 0.5rem; }
  .brand__logo { width: 32px; height: 32px; }

  .hero__actions .btn,
  .cta__actions .btn,
  .cta__actions .store-btn,
  .delete-hero__actions .btn { width: 100%; }

  .hero__note { gap: 0.5rem 1rem; }
  .card, .contact-card, .data-card { border-radius: var(--radius); }
  .faq__answer p { padding-right: 1.1rem; }

  /* At 17% the badge landed across the screenshot's macro row and hid the
     Carbs figure. Dropping it over the tab bar keeps the real UI readable. */
  .scan-badge { bottom: 7%; right: 0; }
}

/* Respect the visitor's motion preference.
   Colour and shadow feedback is kept — removing motion should not remove the
   ability to tell that something is hoverable — but every translation,
   scale and looping animation is dropped. */
@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;
    scroll-behavior: auto !important;
  }

  /* Must out-specify `.js .reveal`, or reduced-motion visitors would still
     start every block at opacity 0. */
  .js .reveal { opacity: 1; transform: none; }
  .aurora__blob { animation: none; }
  .hero__shot, .shield, .scan-badge { animation: none; }

  .btn:hover,
  .card:hover,
  .contact-card:hover,
  .team__member:hover,
  .goal:hover,
  .icon-btn:hover,
  .to-top:hover,
  .store-btn:hover,
  .shot:hover .shot__img,
  .brand:hover .brand__logo,
  .footer__list a:hover { transform: none; }

  .goal:hover::before { transform: scaleY(1); }
}


/* ==========================================================================
   29. Print
   ========================================================================== */

@media print {
  .header, .mobile-nav, .to-top, .footer, .aurora, .breadcrumbs, .toc,
  .skip-link { display: none !important; }

  body { background: #fff; color: #000; font-size: 11pt; }

  .legal-layout { grid-template-columns: 1fr; }
  .prose { max-width: none; }
  .section { padding-block: 1rem; }

  .prose a { text-decoration: none; color: #000; }
  .prose a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    color: #555;
  }
}
