/* =========================================================================
   Protelino marketing site - design system
   Ported directly from the app's own ThemeData (lib/core/theme/app_theme.dart)
   and shared widgets: deep teal primary, warm gold secondary, periwinkle
   indigo tertiary, Outfit everywhere (the app's one UI typeface), the
   app's real per-condition molecule-icon colors, and the app's
   BackgroundWash treatment (lib/core/widgets/background_wash.dart).
   Icons are Flaticon UIcons (Bold Rounded) - the same webfont the app
   itself ships at assets/fonts/uicons-bold-rounded.ttf.
   ========================================================================= */

/* Both fonts are self-hosted, not loaded from Google's CDN - no request
   ever leaves this domain for typography, so no visitor IP is shared with
   a third party just to render text. See the Website Privacy Policy for
   why that matters (it's the whole reason this site needs no cookie
   banner: nothing here requires consent in the first place). */
@font-face {
  font-family: 'Outfit';
  src: url('/assets/fonts/outfit-variable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'UIconsBold';
  src: url('/assets/fonts/uicons-bold-rounded.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: block;
}

:root {
  /* --- brand: light --- */
  --primary: #0d9488;
  --primary-strong: #0f766e;
  --primary-light: #2dd4bf;
  --on-primary: #ffffff;
  --primary-container: #ccfbf1;
  --on-primary-container: #042f2b;

  --secondary: #d97706;
  --on-secondary: #ffffff;
  --secondary-container: #fef3c7;
  --on-secondary-container: #451a03;

  --tertiary: #6366f1;
  --on-tertiary: #ffffff;
  --tertiary-container: #e0e7ff;
  --on-tertiary-container: #1e1b4b;

  --error: #dc2626;
  --error-container: #fee2e2;
  --on-error-container: #450a0a;

  /* categorical / nutrient-identity accents (never reused for meaning) -
     slot 0 = Phe/Leu, slot 1 = protein, slot 2 = calories, matching
     nutrient_colors.dart's fixed-slot assignment. */
  --id-berry: #db2777;
  --id-sky: #0284c7;
  --id-violet: #7c3aed;
  --id-emerald: #059669;
  --id-orange: #ea580c;
  --id-cyan: #0891b2;

  /* --- the app's real per-condition colors (metabolic_svgs.dart) - fixed,
     identical in light and dark, exactly like in the app itself. --- */
  --cond-pku: #2563eb;
  --cond-msud: #d97706;
  --cond-tyr1: #7c3aed;
  --cond-hcu: #0d9488;
  --cond-iva: #16a34a;
  --cond-general: #f97316;

  /* --- surfaces: light --- */
  --bg: #f6fbfa;
  --surface: #ffffff;
  --surface-2: #e7f5f2;
  --border: #e3e9e7;
  --text: #10201c;
  --text-muted: #5b6b67;
  --shadow: 16, 32, 28;

  /* --- layout --- */
  --content-w: 1180px;
  --radius-sm: 12px;
  --radius: 20px;
  --radius-lg: 28px;
  --space-section: clamp(64px, 9vw, 128px);

  /* The phone mockups' own corner radius, so a box-shadow can trace the
     handset instead of its bounding rectangle -- see "phone shadows" below
     for why they are box-shadows and not drop-shadows.

     Measured off the assets rather than guessed: every screenshot under
     assets/img/screenshots is 625x1299 with the handset spanning 617px
     and a 108px corner radius (checked across all 7 screens and all 3
     locales -- they are identical). Two percentages, not one: a single
     percentage resolves against width and height separately, which on a
     625x1299 box would give badly stretched elliptical corners. 108/625
     and 108/1299 restore a circular 108px corner, and because the images
     keep their aspect ratio it stays circular at every rendered size. */
  --phone-radius: 17.36% / 8.35%;

  --font-body: 'Outfit', ui-sans-serif, system-ui, -apple-system, sans-serif;

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --primary: #2dd4bf;
    --primary-strong: #5eead4;
    --primary-light: #99f6e4;
    --on-primary: #042f2b;
    --primary-container: #115e59;
    --on-primary-container: #99f6e4;

    --secondary: #fbbf24;
    --on-secondary: #451a03;
    --secondary-container: #78350f;
    --on-secondary-container: #fde68a;

    --tertiary: #a5b4fc;
    --on-tertiary: #1e1b4b;
    --tertiary-container: #3730a3;
    --on-tertiary-container: #e0e7ff;

    --error: #f87171;
    --error-container: #7f1d1d;
    --on-error-container: #fecaca;

    --id-berry: #f472b6;
    --id-sky: #38bdf8;
    --id-violet: #a78bfa;
    --id-emerald: #34d399;
    --id-orange: #fb923c;
    --id-cyan: #22d3ee;

    --bg: #0b1615;
    --surface: #132420;
    --surface-2: #1b2f2b;
    --border: #22403a;
    --text: #f3fbf9;
    --text-muted: #9fb4ae;
    --shadow: 0, 0, 0;
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --primary: #2dd4bf;
  --primary-strong: #5eead4;
  --primary-light: #99f6e4;
  --on-primary: #042f2b;
  --primary-container: #115e59;
  --on-primary-container: #99f6e4;

  --secondary: #fbbf24;
  --on-secondary: #451a03;
  --secondary-container: #78350f;
  --on-secondary-container: #fde68a;

  --tertiary: #a5b4fc;
  --on-tertiary: #1e1b4b;
  --tertiary-container: #3730a3;
  --on-tertiary-container: #e0e7ff;

  --error: #f87171;
  --error-container: #7f1d1d;
  --on-error-container: #fecaca;

  --id-berry: #f472b6;
  --id-sky: #38bdf8;
  --id-violet: #a78bfa;
  --id-emerald: #34d399;
  --id-orange: #fb923c;
  --id-cyan: #22d3ee;

  --bg: #0b1615;
  --surface: #132420;
  --surface-2: #1b2f2b;
  --border: #22403a;
  --text: #f3fbf9;
  --text-muted: #9fb4ae;
  --shadow: 0, 0, 0;
  color-scheme: dark;
}

/* --------------------------------- reset -------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@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; }
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* No overflow-x here on purpose. `.bg-wash` below already clips its own
     negative-offset blobs with its own `overflow: hidden` (it's the
     positioned container those blobs are relative to), so body never
     actually needs to clip anything itself. That matters because ANY
     non-visible overflow value on body - hidden, clip, scroll, all of
     them - forces the paired overflow-y to compute as `auto`, which turns
     <body> into its own scroll container and makes the sticky header
     stick to THAT box instead of the viewport: it holds for a few pixels
     then vanishes as soon as body's own box scrolls past. Leaving body's
     overflow untouched keeps the viewport itself as the header's sticky
     containing block, which is the only way it reliably stays put in
     every browser.
  */
  position: relative;
}
img { max-width: 100%; display: block; }
svg { width: 20px; height: 20px; flex-shrink: 0; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -0.01em; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
:focus-visible {
  outline: 2.5px solid var(--tertiary);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------------------------------- icons -------------------------------- */
.uic {
  font-family: 'UIconsBold', sans-serif;
  font-style: normal;
  font-weight: normal;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 20px;
  flex-shrink: 0;
}

/* -------------------------------- helpers ------------------------------- */
.wrap {
  max-width: var(--content-w);
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 40px);
  position: relative;
}
.section { padding-block: var(--space-section); position: relative; }
/* Alternating section tint so the page reads in bands instead of one flat
   color top to bottom - every other section gets the app's own
   surface-2 tone as a full-bleed backdrop. */
main > .section:nth-of-type(even) { background: var(--surface-2); }
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--primary-strong);
}
.eyebrow .ring-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--primary); box-shadow: 0 0 0 3px var(--primary-container); flex-shrink: 0; }

.display-xl { font-weight: 800; font-size: clamp(2.7rem, 6vw, 4.8rem); line-height: 1.02; letter-spacing: -0.03em; }
.display-lg { font-weight: 800; font-size: clamp(1.9rem, 3.2vw, 2.7rem); line-height: 1.12; letter-spacing: -0.02em; }
.display-md { font-weight: 700; font-size: clamp(1.4rem, 2.1vw, 1.8rem); line-height: 1.2; letter-spacing: -0.01em; }
.accent-text {
  background: linear-gradient(120deg, var(--primary-strong), var(--primary), var(--tertiary));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.lede { font-size: clamp(1.05rem, 1.4vw, 1.2rem); color: var(--text-muted); max-width: 46ch; line-height: 1.6; }
.center { text-align: center; margin-inline: auto; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 26px;
  border-radius: 16px;
  font-weight: 700;
  font-size: 0.98rem;
  white-space: nowrap;
  transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease, border-color .18s ease;
}
.btn-primary {
  background: linear-gradient(135deg, var(--primary-light), var(--primary));
  color: var(--on-primary);
  box-shadow: 0 10px 24px -10px rgba(13, 148, 136, 0.55);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 28px -10px rgba(13, 148, 136, 0.6); }
.btn-ghost {
  background: var(--surface);
  border: 1.5px solid var(--border);
  color: var(--text);
}
.btn-ghost:hover { border-color: var(--primary); color: var(--primary-strong); }
.btn-sm { padding: 10px 18px; font-size: 0.88rem; border-radius: 12px; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
  background: var(--surface-2);
  color: var(--text-muted);
  border: 1px solid var(--border);
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 1px 2px rgba(var(--shadow), 0.04), 0 12px 28px -18px rgba(var(--shadow), 0.18);
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 12px; top: -60px;
  background: var(--primary); color: var(--on-primary);
  padding: 10px 16px; border-radius: 10px; font-weight: 700; z-index: 999;
  transition: top .2s ease;
}
.skip-link:focus { top: 12px; }

/* ------------------------------ background wash --------------------------
   Port of lib/core/widgets/background_wash.dart: radial blobs in the app's
   own nutrient-identity colors (teal primary, violet/berry/sky from the
   calories/Phe/protein slots) smeared behind the top of the screen. The
   app's version is a thin 180dp strip meant to just clear the status bar;
   a web page has far more room and sits much further from the eye, so this
   is scaled up and brightened accordingly - a literal 180px band at normal
   web viewing distance would be nearly imperceptible. Lives at the top of
   `<body>`, in normal flow (not fixed), sized to reach past the hero so it
   scrolls away with the page exactly like the app's version scrolls away
   with its screen content, rather than staying pinned like a viewport
   overlay would. */
.bg-wash {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 900px;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}
.bg-wash i {
  position: absolute;
  border-radius: 50%;
  filter: blur(10px);
}
.bg-wash .b1 { background: radial-gradient(circle, color-mix(in srgb, var(--primary) 55%, transparent), transparent 70%); width: 900px; height: 900px; left: -320px; top: -420px; }
.bg-wash .b2 { background: radial-gradient(circle, color-mix(in srgb, var(--id-violet) 48%, transparent), transparent 70%); width: 760px; height: 760px; right: -260px; top: -360px; }
.bg-wash .b3 { background: radial-gradient(circle, color-mix(in srgb, var(--id-berry) 42%, transparent), transparent 70%); width: 560px; height: 560px; left: 24%; top: -300px; }
.bg-wash .b4 { background: radial-gradient(circle, color-mix(in srgb, var(--id-sky) 46%, transparent), transparent 70%); width: 620px; height: 620px; left: 46%; top: 60px; }
@media (max-width: 760px) {
  .bg-wash { height: 700px; }
  .bg-wash .b1, .bg-wash .b2, .bg-wash .b3, .bg-wash .b4 { width: 480px; height: 480px; }
  .bg-wash .b2 { right: -200px; }
  .bg-wash .b3 { left: -120px; }
  .bg-wash .b4 { left: 30%; }
}

/* --------------------------------- header ------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom: 1px solid transparent;
  transition: border-color .25s ease, background .25s ease;
}
.site-header.is-scrolled { border-bottom-color: var(--border); }
.site-header .wrap { display: flex; align-items: center; justify-content: space-between; padding-block: 14px; gap: 16px; }
.scroll-progress { position: absolute; left: 0; bottom: -1px; height: 2px; width: 0%; background: linear-gradient(90deg, var(--tertiary), var(--primary)); transition: width .1s linear; }

.brand { display: flex; align-items: center; gap: 10px; font-weight: 800; font-size: 1.15rem; flex-shrink: 0; }
.brand img { width: 34px; height: 34px; border-radius: 9px; }

.nav-links { display: flex; align-items: center; gap: 30px; }
.nav-links a { font-weight: 600; font-size: 0.95rem; color: var(--text-muted); transition: color .15s ease; }
.nav-links a:hover, .nav-links a.is-active { color: var(--text); }

.nav-right { display: flex; align-items: center; gap: 10px; }

/* 44px, not 40px: this is the minimum comfortable touch target on iOS
   (Apple HIG) and WCAG 2.5.5. 40px cleared the AA floor but sat under the
   guidance, and the header controls (theme, language, menu) are the ones
   most likely to be tapped one-handed on a phone -- worth the 4px. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text);
}
.icon-btn:hover { border-color: var(--primary); color: var(--primary-strong); }
.icon-btn .uic { font-size: 18px; }
.theme-toggle .uic-dark { display: none; }
.theme-toggle .uic-light { display: inline-flex; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .uic-dark { display: inline-flex; }
  :root:not([data-theme="light"]) .theme-toggle .uic-light { display: none; }
}
:root[data-theme="dark"] .theme-toggle .uic-dark { display: inline-flex; }
:root[data-theme="dark"] .theme-toggle .uic-light { display: none; }

.lang-switch { position: relative; }
.lang-switch button {
  display: flex; align-items: center; gap: 6px;
  /* min-height matches .icon-btn's 44px so the three header controls line
     up on one baseline height instead of the language pill sitting 5px
     shorter than the icons beside it. */
  min-height: 44px;
  padding: 8px 12px; border-radius: 10px; border: 1px solid var(--border);
  font-weight: 700; font-size: 0.85rem; color: var(--text);
  background: var(--surface);
}
.lang-switch button:hover { border-color: var(--primary); }
.lang-switch .uic { font-size: 16px; }
.lang-menu {
  position: absolute; right: 0; top: calc(100% + 8px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 16px 32px -12px rgba(var(--shadow), 0.28);
  min-width: 160px; padding: 6px; display: none; flex-direction: column;
}
.lang-switch.is-open .lang-menu { display: flex; }
.lang-menu a { padding: 9px 12px; border-radius: 8px; font-weight: 600; font-size: 0.9rem; display: flex; justify-content: space-between; }
.lang-menu a:hover { background: var(--surface-2); }
.lang-menu a.is-active { color: var(--primary-strong); }

.nav-toggle { display: none; }

@media (max-width: 920px) {
  .nav-links { display: none; }
  /* Only `display` needs setting here -- the element already carries
     .icon-btn, which supplies the box, border and background. This block
     used to restate all of them, which is how it silently kept its own
     40px size when .icon-btn moved to the 44px touch-target minimum. */
  .nav-toggle { display: inline-flex; }
  body.nav-open .nav-links {
    display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
    position: fixed; inset: 64px 12px auto 12px; background: var(--surface);
    border: 1px solid var(--border); border-radius: var(--radius);
    padding: 14px; box-shadow: 0 20px 40px -16px rgba(var(--shadow), 0.3); z-index: 99;
  }
  body.nav-open .nav-links a { width: 100%; padding: 10px 8px; border-radius: 8px; }
  body.nav-open .nav-links a:hover { background: var(--surface-2); }
}

/* ---------------------------------- hero -------------------------------- */
.hero { padding-block: clamp(48px, 8vw, 88px) clamp(40px, 6vw, 64px); }
.hero-grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: clamp(32px, 5vw, 64px); align-items: center; }
.hero-copy .eyebrow { margin-bottom: 18px; }
.hero-copy h1 { margin-bottom: 20px; }
.hero-copy .lede { margin-bottom: 32px; max-width: 50ch; }
.store-badges { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 20px; align-items: center; }
/* Real official Apple/Google artwork - both bake their own black rounded
   badge shape directly into the SVG, so no extra background card is
   needed on either a light or dark section; just size it up and add a
   hover lift. */
.store-badge-link { display: inline-flex; align-items: center; transition: transform .18s ease, filter .18s ease; }
.store-badge-link:hover { transform: translateY(-2px); filter: brightness(1.08); }
.store-badge-img { height: 52px; width: auto; display: block; }

.hero-art { position: relative; display: flex; align-items: center; justify-content: center; min-height: 420px; }

/* HeroSummaryCard recreation (see hero_summary_card.dart): diagonal
   gradient card, faint molecule watermark, cycling condition chip, big
   hero number + status pill, ring gauge with small current/target
   center text. */
.hero-card {
  position: relative; width: 100%; max-width: 430px; overflow: hidden;
  border-radius: var(--radius-lg);
  /* Real formula from _StatusTones/HeroSummaryCard: a diagonal gradient
     from the full status-container color to that SAME color blended 35%
     toward the neutral card surface (not toward the raw accent) - a
     subtle lightening, not a second saturated color. */
  background: linear-gradient(135deg, var(--primary-container), color-mix(in srgb, var(--primary-container) 65%, var(--surface) 35%));
  padding: 20px;
  box-shadow: 0 30px 60px -30px rgba(var(--shadow), 0.4);
  animation: floatY 7s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .hero-card { animation: none; } }
@keyframes floatY { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }

.hero-card-watermark {
  position: absolute; top: -40px; right: -40px; width: 260px; height: 260px;
  opacity: 0.08; pointer-events: none; transition: opacity .4s ease;
  color: var(--on-primary-container);
}
.hero-card-watermark svg { width: 100%; height: 100%; }

.hero-card-top { position: relative; display: flex; align-items: center; justify-content: space-between; margin-bottom: 22px; gap: 10px; }
.hero-cond-chip {
  display: inline-flex; align-items: center; gap: 8px;
  background: rgba(255,255,255,0.55); backdrop-filter: blur(6px);
  padding: 7px 14px 7px 8px; border-radius: 999px;
}
:root[data-theme="dark"] .hero-cond-chip { background: rgba(0,0,0,0.28); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .hero-cond-chip { background: rgba(0,0,0,0.28); } }
.hero-cond-icon { width: 22px; height: 22px; flex-shrink: 0; color: var(--on-primary-container); }
.hero-cond-icon svg { width: 100%; height: 100%; }
/* The app's real hero card renders this icon (and the ring) in one
   consistent ink color for whichever profile/condition is active, never a
   rainbow cycling through each condition's own identity hue (that
   distinction is real -- see the condition picker) -- so force every path/
   circle in the injected per-condition SVG to the card's neutral text
   color instead of the hardcoded per-condition hex baked into each icon's
   markup. !important beats the SVG's own fill/stroke presentation
   attributes, which a plain specificity match would not. */
.hero-cond-icon svg *, .hero-card-watermark svg * { fill: currentColor !important; stroke: currentColor !important; }
.hero-cond-label { font-size: 0.8rem; font-weight: 700; color: var(--on-primary-container); white-space: nowrap; }
.hero-view-trends {
  display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0;
  font-size: 0.76rem; font-weight: 700; color: var(--on-primary-container); opacity: 0.75;
}
.hero-view-trends .uic { font-size: 12px; }

.hero-card-body { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.hero-figure { display: flex; flex-direction: column; gap: 8px; }
.hero-figure .ring-value { color: var(--on-primary-container); }
.hero-status-pill {
  display: inline-flex; align-items: center; gap: 6px; width: fit-content;
  padding: 6px 13px; border-radius: 999px; font-size: 0.78rem; font-weight: 700;
  background: rgba(255,255,255,0.6); color: var(--on-primary-container);
}
:root[data-theme="dark"] .hero-status-pill { background: rgba(0,0,0,0.3); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .hero-status-pill { background: rgba(0,0,0,0.3); } }
.hero-status-pill .uic { font-size: 14px; }

/* Ring gauge: a 290°-arc path with a 70° gap centered at the bottom,
   matching _GaugePainter's _gapDegrees exactly (a full circle was a v2
   simplification the user asked to make truer to the real widget). Track
   and fill share the identical `d` (computed for r=62 in a 160x160 box);
   the fill reveals via stroke-dashoffset against its own fixed path
   length (~313.8), the same reveal technique as before, just on an arc
   instead of a full circle. */
.ring-wrap { position: relative; width: 148px; height: 148px; flex-shrink: 0; }
.ring-wrap > svg { width: 100%; height: 100%; }
.ring-track { fill: none; stroke: rgba(255,255,255,0.4); stroke-width: 11; stroke-linecap: round; }
:root[data-theme="dark"] .ring-track { stroke: rgba(0,0,0,0.22); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .ring-track { stroke: rgba(0,0,0,0.22); } }
.ring-fill {
  fill: none; stroke: var(--primary); stroke-width: 15; stroke-linecap: round;
  stroke-dasharray: 313.8; stroke-dashoffset: 313.8;
  transition: stroke-dashoffset 1.4s cubic-bezier(.16,.84,.44,1);
}
.ring-wrap.in-view .ring-fill { stroke-dashoffset: var(--ring-offset, 313.8); }
.ring-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 0; }
.ring-current { font-size: 1.25rem; font-weight: 800; color: var(--on-primary-container); }
.ring-target { font-size: 0.85rem; font-weight: 700; color: var(--on-primary-container); opacity: 0.85; }

/* Secondary nutrient mini-table, ported from _NutrientTable: a divider,
   an uppercase section label, then dot + label + value rows each with a
   thin colored progress bar underneath. */
.hero-nutrient-table { position: relative; margin-top: 18px; padding-top: 14px; border-top: 1px solid rgba(255,255,255,0.35); }
:root[data-theme="dark"] .hero-nutrient-table { border-top-color: rgba(0,0,0,0.25); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .hero-nutrient-table { border-top-color: rgba(0,0,0,0.25); } }
.hero-nutrient-table .overview-label { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.05em; color: var(--on-primary-container); opacity: 0.7; text-transform: uppercase; margin-bottom: 10px; display: block; }
.hero-nutrient-row { margin-bottom: 10px; }
.hero-nutrient-row:last-child { margin-bottom: 0; }
.hero-nutrient-row .row-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 5px; }
.hero-nutrient-row .row-label { display: flex; align-items: center; gap: 8px; font-size: 0.82rem; font-weight: 600; color: var(--on-primary-container); }
.hero-nutrient-row .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.hero-nutrient-row .row-value { font-size: 0.78rem; font-weight: 700; color: var(--on-primary-container); }
.hero-nutrient-row .bar-track { height: 6px; border-radius: 6px; background: rgba(255,255,255,0.35); overflow: hidden; margin-left: 16px; }
:root[data-theme="dark"] .hero-nutrient-row .bar-track { background: rgba(0,0,0,0.25); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .hero-nutrient-row .bar-track { background: rgba(0,0,0,0.25); } }
.hero-nutrient-row .bar-fill { height: 100%; border-radius: 6px; }
/* Formula/amino-acid-mixture row: the real app shows this one as discrete
   per-serving bottle icons (see hero_summary_card.dart's
   `fiBrPrescriptionBottle` / `fiSrPrescriptionBottle` pair -- filled vs
   outline per serving), not a continuous bar like Protein/Calories --
   approximated here with opacity since the site only ships the bold-
   rounded icon font, not a separate solid weight. */
.hero-nutrient-row .formula-icons { display: flex; gap: 6px; margin-left: 16px; }
.hero-nutrient-row .formula-icons .uic { font-size: 15px; }

/* Positioned beside the ring rather than at the card's bottom edge - the
   nutrient table below the gauge means the bottom corner is no longer
   empty space now that this mockup is closer to the real card's actual
   height. */
/* No drop-shadow: irregular cutout, and drop-shadow is what iOS Safari
   mis-rasterizes -- see the phone-shadows note further down. */
.hero-panda { position: absolute; top: 34%; right: -13%; transform: translateY(-50%); width: clamp(95px, 14vw, 145px); }

@media (max-width: 860px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-art { min-height: 320px; order: -1; margin-bottom: 12px; }
  .hero-panda { display: none; }
}

.trust-strip { border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); background: var(--surface); }
.trust-list { display: flex; flex-wrap: wrap; gap: clamp(20px, 4vw, 48px); justify-content: center; padding-block: 22px; }
.trust-item { display: flex; align-items: center; gap: 10px; font-size: 0.88rem; font-weight: 600; color: var(--text-muted); }
.trust-item .uic { font-size: 19px; color: var(--primary); }

/* ------------------------------- why protelino ---------------------------
   Deliberately NOT another bordered-card grid - the conditions grid, the
   steps grid, and the "everything else" grid three sections down already
   own that pattern. This one is a single colored band (same device as
   founder-band/cta-band) with a plain icon+text list inside it, so it
   reads as a distinct callout rather than a fourth repeat of the card
   grid. */
.why-band {
  border-radius: var(--radius-lg); padding: clamp(32px, 5vw, 56px);
  background: linear-gradient(135deg, var(--primary-container), color-mix(in srgb, var(--tertiary-container) 65%, var(--primary-container)));
  position: relative; overflow: hidden;
}
.why-band .eyebrow, .why-band h2 { color: var(--on-primary-container); }
.why-band .lede { color: color-mix(in srgb, var(--on-primary-container) 78%, transparent); }
.why-head { display: flex; align-items: center; gap: 20px; text-align: left; margin-bottom: 36px; }
.why-mascot {
  width: 64px; height: 64px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
  background: rgba(255,255,255,0.5); border: 3px solid rgba(255,255,255,0.6);
}
.why-list { display: grid; grid-template-columns: 1fr 1fr; gap: 24px 44px; }
.why-row { display: flex; gap: 14px; align-items: flex-start; }
.why-icon {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.55); color: var(--on-primary-container);
}
:root[data-theme="dark"] .why-icon { background: rgba(0,0,0,0.28); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .why-icon { background: rgba(0,0,0,0.28); } }
.why-icon .uic { font-size: 18px; }
.why-row h4 { font-size: 0.98rem; margin-bottom: 4px; color: var(--on-primary-container); }
.why-row p { font-size: 0.85rem; color: color-mix(in srgb, var(--on-primary-container) 82%, transparent); line-height: 1.5; }
@media (max-width: 700px) { .why-head { flex-direction: column; text-align: center; } .why-list { grid-template-columns: 1fr; } }

/* ------------------------------- feature rows ---------------------------- */
.feature-row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 6vw, 80px); align-items: center; }
.feature-row + .feature-row { margin-top: var(--space-section); }
/* order:-1, not 2 -- .feature-art is already the second (last) child in
   every row's markup, so `order: 2` left it exactly where it was and the
   desktop zig-zag silently did nothing: all four screenshots stacked up in
   the same right-hand column. Pulling the art before the copy is what
   actually alternates the sides, and it also means a row's screenshot no
   longer sits directly above the next row's. */
.feature-row.is-reverse .feature-art { order: -1; }
.feature-row .eyebrow { margin-bottom: 16px; }
.feature-row h3 { margin-bottom: 16px; }
.feature-row .lede { max-width: none; margin-bottom: 22px; }
.feature-list { display: flex; flex-direction: column; gap: 12px; }
.feature-list li { display: flex; align-items: flex-start; gap: 10px; font-size: 0.96rem; color: var(--text); }
.feature-list .uic { font-size: 18px; color: var(--primary); margin-top: 1px; }
.feature-art { position: relative; display: flex; align-items: center; justify-content: center; }
.feature-art .art-plate {
  position: relative; width: 100%; max-width: 380px; aspect-ratio: 1/1.05;
  background: radial-gradient(120% 120% at 30% 20%, var(--surface-2), var(--surface) 70%);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  display: flex; align-items: center; justify-content: center; overflow: visible;
}
/* No drop-shadow here either -- every image this covers is a phone
   mockup that gets its own box-shadow below. See the phone-shadows note. */
.feature-art img { width: 62%; height: auto; }

/* Real device screenshot + mascot companion, added 2026-09-02. The
   mascot shrinks and moves to a bottom-left peek so the real screenshot
   can take the lead role the plain illustration used to have -- the
   screenshot is left to run taller than the plate itself (the plate's
   own overflow:visible already allows this) rather than shrunk down to
   fit inside a square frame, since a real device breaking out of its
   card reads as more convincing than one apologetically boxed in. */
/* No hard-edged card here -- the base .art-plate's bordered square (below)
   made sense behind one centered illustration, but a tall phone pushed to
   one side leaves half of that square empty, reading as a stray rectangle
   rather than a frame. A borderless glow, biased toward where the content
   actually sits and faded to fully transparent (never resolving to a flat
   color), has no edge to look lost -- it just softens the content itself. */
.feature-art .art-plate.has-shot {
  justify-content: flex-end; padding-right: 4%;
  border: none;
  background: radial-gradient(70% 70% at 68% 58%, var(--surface-2), transparent 75%);
  /* Height must come from the screenshot, not from the square-ish ratio the
     base .art-plate inherited from its illustration days. A screenshot is
     2.08x as tall as it is wide, so at 70% of a 380px plate it needs ~553px
     while `aspect-ratio: 1/1.05` only grants 399px. Chrome hid that by
     stretching the plate anyway (it's a flex item, so min-height:auto floors
     it at its content size); Safari on iPadOS honours the declared ratio
     instead and lets the screenshot overflow ~77px past the plate's top AND
     bottom. Two neighbouring rows each contribute 77px into a gap that is
     only 106px at iPad-landscape widths, so consecutive rows' screenshots
     overlapped by ~48px. Found on a real iPad Air in landscape (1180px wide,
     i.e. above the 1024px stacking breakpoint, which is why the smaller
     iPads that stack were unaffected); reproduced in Chrome by pinning the
     plate to its ratio height. Letting the height be content-driven renders
     identically in Chrome and removes the overflow everywhere. */
  aspect-ratio: auto;
}
/* ---- phone shadows: box-shadow, never filter: drop-shadow ----------------
   iOS Safari rasterizes a long page in tiles, and it gets `filter:
   drop-shadow()` on these large images wrong depending on where the tile
   boundaries happen to fall. Two symptoms, same cause, both shipped: the
   shadow rendered cut off along a hard rectangle, or the image's own box
   showed as a faint outline. Both appeared only at particular scroll
   offsets, both healed themselves on any repaint -- scrolling away and
   back, or any style change that forced a re-raster -- and neither ever
   reproduced in Chrome.

   That self-healing is the tell: nothing about the layout is wrong, the
   raster is. So it cannot be fixed by rearranging what gets composited;
   an earlier attempt to do exactly that (moving the scroll-reveal off
   these rows) changed which symptom appeared and fixed neither.

   box-shadow is painted as ordinary box decoration -- no filter region,
   no stacking context, no layer of its own -- so it is not subject to any
   of this. Paired with --phone-radius it traces the handset's real
   corners, making it indistinguishable from the old drop-shadow. Blur
   values carry over unchanged: both properties take a blur *radius* with
   the same meaning.

   The two panda cutouts are irregular shapes a box-shadow cannot follow,
   so they lose their shadow rather than keep a filter. To get it back,
   bake it into the .webp itself -- that stays bulletproof.

   Note the negative spread on each of these. A box-shadow is cast by the
   border box, and these images are 625px wide because that is where the
   *side buttons* reach (volume at rows 269-598, power at 408-564) -- the
   handset body itself only spans x 4..620, 4px narrower on each side. So
   the shadow's silhouette lined up with the button tips rather than the
   body, and its edge showed as a faint outline running down the sides,
   visibly skirting the buttons. Rounding the corners hid it at the
   corners and nowhere else.

   Pulling the silhouette in by more than that 4px (~2px once the image is
   scaled to its rendered ~250px) tucks the edge behind the opaque handset,
   leaving only the soft tail of the blur outside it. That is the whole
   shadow anyone was ever meant to see. Keep any spread here comfortably
   larger than the body inset; going the other way brings the outline back.

   Each of these is two layers, for a reason worth keeping. The first is
   the deep one (-32px spread against a 42px blur): its edge ends up ~30px
   inside the handset while the blur only reaches ~21px back out, so it
   contributes nothing at the sides at all and only darkens the strip
   below. Raising its alpha alone therefore stops buying presence very
   quickly -- the shadow reads as flat no matter how dark you make it.

   The second layer is what you actually see around the phone: a shallower
   spread (-20px, -10px on the smaller secondary) so the blur does clear
   the handset, at a lower alpha so it stays soft. Both spreads are still
   far beyond the ~2px body inset, so neither puts a defined edge outside
   the phone and the button outline stays gone.

   Tuning: alpha on either layer is always safe. For more presence than
   alpha can give, ease the *second* layer's spread toward zero (anything
   past roughly -4px stays hidden) and leave the first alone.
   -------------------------------------------------------------------- */
.feature-art .art-plate .art-phone {
  position: relative; z-index: 2; width: 70%; height: auto;
  border-radius: var(--phone-radius);
  box-shadow: 0 30px 42px -32px rgba(var(--shadow), 0.5),
              0 30px 44px -20px rgba(var(--shadow), 0.34);
}
/* A companion detail, not a second focal point -- but still overlapping
   the screenshot's own left edge (not parked entirely beside it), so it
   reads as tucked in front of the scene rather than floating next to
   it. z-index above .art-phone deliberately -- the panda sits ON the
   screenshot, not the other way around. */
.feature-art .art-plate .art-mascot {
  position: absolute; z-index: 3; left: 8%; bottom: 1%;
  width: 30%; height: auto;
  /* No shadow: an irregular cutout, so a box-shadow would trace a
     rectangle rather than the panda. See the phone-shadows note above. */
}
/* Two-screenshot rows (no mascot -- see .art-plate markup for which
   rows use this): a real fanned-photos stack, not two phones parked
   side by side -- the secondary is nearly as large as the primary, sat
   mostly beside it with only its right side tucked behind, offset up
   and left from the primary's own base and counter-rotated, the same
   way you'd overlap two physical photos of comparable size on a desk. */
.feature-art .art-plate .art-phone-secondary {
  position: absolute; z-index: 1; left: -6%; bottom: 4%;
  width: 62%; height: auto; transform: rotate(-7deg);
  border-radius: var(--phone-radius);
  box-shadow: 0 18px 26px -16px rgba(var(--shadow), 0.42),
              0 18px 28px -10px rgba(var(--shadow), 0.3);
}
/* Breakpoint raised 780px -> 1024px (2026-09-03, found on a real iPad).
   The two-column feature row stopped working well long before 780px: at
   iPad-portrait widths (768/820/834px) the row was still two columns, so
   each one came out ~296-344px, squeezing .art-plate under its 380px
   design size. Measured at 834px-equivalent geometry, that made the
   fanned second screenshot cover 103px of the 199px primary (52% of it,
   vs. the ~43% the desktop layout was designed around) and hang 41px
   past the plate's left edge -- and since the page's own side padding at
   that width is also ~41px, the overhang landed exactly at the viewport
   boundary, which is what clipped its drop-shadow. 1024px covers every
   iPad in portrait; real laptops (1280px+) keep the two-column design
   untouched.
   Correction (2026-09-03): this note used to claim 1024px also covered
   iPad LANDSCAPE. It does not -- only the old 9.7" iPad is 768x1024. Every
   current iPad is 1080-1366px wide in landscape (iPad Air 11" is 1180,
   iPad Pro 11" 1194, the 13" models 1366), so they all get the two-column
   layout, which is exactly where the overlapping-screenshots bug fixed in
   .art-plate.has-shot showed up. */
@media (max-width: 1024px) {
  .feature-art .art-plate .art-phone { width: 60%; }
  /* left: 22%, not 6% -- with the phone at 60% and 4% right padding its
     left edge sits at 36% of the plate, so a 24%-wide mascot at left:6%
     ends at 30% and leaves a visible GAP instead of tucking in front. The
     desktop layout overlaps by 12% of the plate (17% of the phone's own
     width); (22 + 24) - 36 = 10% reproduces that same proportion here, so
     the panda keeps reading as sitting ON the screenshot at every width
     rather than floating beside it. */
  .feature-art .art-plate .art-mascot { width: 24%; left: 22%; }
  /* left: 0, not negative -- once the row is a single centered column
     there's no reason for the secondary to hang outside the plate, and
     that overhang was the thing whose shadow got cut off. */
  .feature-art .art-plate .art-phone-secondary { width: 46%; left: 0; }
  /* Slightly larger than the 380px desktop cap: alone and centered in a
     full-width column, the plate can afford more presence than it could
     sharing a row with the text. */
  .feature-art .art-plate { max-width: 440px; }
}

.feature-art .float-tag {
  position: absolute; z-index: 3; background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; padding: 8px 12px; font-size: 0.76rem; font-weight: 700;
  box-shadow: 0 10px 22px -14px rgba(var(--shadow), 0.35); display: flex; align-items: center; gap: 6px;
}
.float-tag .uic { font-size: 15px; color: var(--primary); }
/* Same 1024px breakpoint as the art sizing above -- these two must stay
   in lockstep, since the art proportions above assume a full-width,
   single-column plate. */
@media (max-width: 1024px) {
  .feature-row, .feature-row.is-reverse { grid-template-columns: 1fr; }
  /* Desktop alternates the screenshot left/right via .is-reverse's order:2
     (see line 623) -- on mobile that same rule was inherited as order:-1
     here, which put the screenshot ABOVE its text on every other row while
     normal rows kept it below, so the page read as an inconsistent mix.
     Resetting order to the default (0) makes every row follow plain source
     order: text first, screenshot below, regardless of desktop's zig-zag. */
  .feature-row.is-reverse .feature-art { order: 0; }
  .feature-art { margin-top: 8px; }
  /* Restore a reading measure. `.feature-row .lede` sets `max-width: none`
     (see that rule) because in the two-column desktop layout the column
     itself already constrained the line length -- but once the row is a
     single full-width column, nothing does, and measured line lengths ran
     to 84ch for the lede and 92ch for the checklist items at 1024px.
     Every other text block on the site caps its own measure (hero lede
     50ch, section ledes 46ch, FAQ answers 68ch), so the feature rows were
     the one place opting out of the site's own convention. Capping the
     shared parent keeps the heading, lede and checklist on one measure
     rather than three slightly different ones. */
  .feature-copy { max-width: 62ch; }
}

/* --- shared floating-mockup card shell --- */
.mock-card {
  position: absolute; bottom: -7%; left: -11%; width: 236px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 20px;
  padding: 16px; box-shadow: 0 22px 40px -18px rgba(var(--shadow), 0.4);
}
/* 1024px too -- .mock-card is absolutely positioned at left:-11%, i.e. the
   same "hangs outside its container" pattern that clipped the secondary
   screenshot's shadow above, so it has to unstick at the same width the
   row collapses at rather than 244px later. */
@media (max-width: 1024px) { .mock-card { position: static; width: 100%; margin-top: 14px; } }

/* --- meal-card mockup, ported from meal_card.dart --- */
.mock-meal-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.mock-meal-icon { width: 44px; height: 44px; border-radius: 12px; background: color-mix(in srgb, var(--primary-container) 40%, var(--surface)); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.mock-meal-icon .uic { font-size: 22px; color: var(--primary); }
.mock-meal-title-row { display: flex; align-items: center; gap: 6px; }
.mock-meal-title { font-weight: 700; font-size: 0.92rem; }
.mock-meal-count { font-size: 0.66rem; font-weight: 700; color: var(--text-muted); background: var(--surface-2); padding: 1px 7px; border-radius: 10px; }
.mock-meal-sub { font-size: 0.7rem; color: var(--text-muted); margin-top: 2px; }
.mock-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.mock-pill { font-size: 0.68rem; font-weight: 700; padding: 4px 9px; border-radius: 999px; }

/* --- blood-spot chart mockup, ported from blood_spot_trend_card.dart --- */
.mock-chart-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.mock-chart-icon { width: 40px; height: 40px; border-radius: 12px; background: color-mix(in srgb, var(--tertiary) 15%, transparent); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.mock-chart-icon .uic { font-size: 19px; color: var(--tertiary); }
.mock-chart-title { font-size: 0.86rem; font-weight: 700; }
.mock-chart-avg { font-size: 0.72rem; font-weight: 800; color: var(--secondary); opacity: 0.85; margin-top: 1px; }
.mock-chart-svg { width: 100%; height: 60px; display: block; }

/* --- AI Label scan mockup: a tiny "receipt" of values pulled straight
   off a product's own nutrition-facts table. --- */
.mock-label-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.mock-label-icon { width: 36px; height: 36px; border-radius: 10px; background: color-mix(in srgb, var(--tertiary-container) 70%, transparent); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.mock-label-icon .uic { font-size: 17px; color: var(--tertiary); }
.mock-label-title { font-weight: 700; font-size: 0.86rem; }
.mock-label-sub { font-size: 0.68rem; color: var(--text-muted); }
.mock-label-rows { display: flex; flex-direction: column; gap: 6px; }
.mock-label-row { display: flex; align-items: center; justify-content: space-between; font-size: 0.76rem; padding-bottom: 6px; border-bottom: 1px dashed var(--border); }
.mock-label-row:last-child { border-bottom: none; padding-bottom: 0; }
.mock-label-row .k { color: var(--text-muted); font-weight: 600; }
.mock-label-row .v { font-weight: 700; }

/* --- home-screen-widget mockup: a plain widget tile, not another chart --- */
.mock-widget-top { display: flex; align-items: center; gap: 7px; font-size: 0.68rem; font-weight: 700; color: var(--text-muted); margin-bottom: 12px; }
.mock-widget-top .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--primary); flex-shrink: 0; }
.mock-widget-number { font-size: 1.7rem; font-weight: 800; color: var(--text); line-height: 1; }
.mock-widget-number span { font-size: 0.9rem; font-weight: 600; color: var(--text-muted); margin-left: 2px; }
.mock-widget-caption { font-size: 0.76rem; color: var(--text-muted); margin-top: 6px; }

/* -------------------------------- conditions ------------------------------ */
.section-head { max-width: 620px; margin-bottom: 48px; }
.section-head .eyebrow { margin-bottom: 16px; }
.section-head h2 { margin-bottom: 14px; }

.condition-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; }
.condition-card {
  padding: 22px 18px; border-radius: var(--radius); background: var(--surface);
  border: 1px solid var(--border); border-top: 6px solid var(--accent, var(--primary));
  transition: transform .2s ease, box-shadow .2s ease;
}
.condition-card:hover { transform: translateY(-6px); box-shadow: 0 20px 34px -18px color-mix(in srgb, var(--accent, var(--primary)) 45%, transparent); }
.condition-icon { width: 40px; height: 40px; margin-bottom: 10px; }
.condition-icon svg { width: 100%; height: 100%; }
.condition-card .tag {
  font-size: 1.55rem; font-weight: 800; color: var(--accent, var(--primary)); letter-spacing: -0.02em;
}
.condition-card .full { display: block; font-weight: 700; font-size: 0.88rem; margin-top: 6px; }
.condition-card .sub { display: block; font-size: 0.82rem; color: var(--text-muted); margin-top: 8px; line-height: 1.45; }
@media (max-width: 980px) { .condition-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px) { .condition-grid { grid-template-columns: repeat(2, 1fr); } }

/* --------------------------------- grid features --------------------------- */
.grid-features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.grid-card { padding: 26px; border-radius: var(--radius); background: var(--surface); border: 1px solid var(--border); }
.grid-card .icon-badge {
  width: 46px; height: 46px; border-radius: 13px; display: flex; align-items: center; justify-content: center;
  background: var(--bg-icon, var(--primary-container)); color: var(--fg-icon, var(--on-primary-container)); margin-bottom: 16px;
}
.grid-card .icon-badge .uic { font-size: 22px; }
.grid-card h4 { font-size: 1.05rem; margin-bottom: 8px; }
.grid-card p { font-size: 0.9rem; color: var(--text-muted); }

/* mini trend-chart preview for the "Nutrition trend analysis" grid card */
.mock-trend { margin-top: 16px; border-radius: 14px; padding: 12px 14px; background: var(--bg); border: 1px solid var(--border); }
.mock-trend-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.mock-trend-label { font-size: 0.7rem; font-weight: 700; color: var(--text-muted); }
.mock-trend-delta { font-size: 0.7rem; font-weight: 800; color: var(--primary); }
.mock-trend-svg { width: 100%; height: 44px; display: block; }
@media (max-width: 900px) { .grid-features { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .grid-features { grid-template-columns: 1fr; } }

/* ------------------------------ how it works ---------------------------- */
.steps-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; position: relative; }
.step-card { position: relative; padding: 26px 24px; border-radius: var(--radius); background: var(--surface); border: 1px solid var(--border); }
.step-number {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 10px; margin-bottom: 16px;
  background: linear-gradient(135deg, var(--primary-light), var(--primary));
  color: var(--on-primary); font-weight: 800; font-size: 0.95rem;
}
.step-card h4 { font-size: 1.02rem; margin-bottom: 8px; }
.step-card p { font-size: 0.9rem; color: var(--text-muted); }
.step-connector { position: absolute; top: 34px; left: 100%; width: 20px; height: 2px; background: var(--border); }
@media (max-width: 900px) { .steps-grid { grid-template-columns: 1fr; } .step-connector { display: none; } }

/* ---------------------------------- family ---------------------------------- */
.family-band { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: clamp(32px, 6vw, 72px); align-items: center; }
.avatar-cluster { position: relative; display: grid; place-items: center; min-height: 300px; }
/* The real Switch Profile screen, staged behind the illustrated avatar
   cluster -- it shows the very people (Alex, Emma, Liam) the orbs
   represent, so the two reinforce the same idea instead of competing:
   drawn family up front, real screen proving the feature behind it. */
.family-phone {
  position: relative; z-index: 0; width: 230px; height: auto;
  border-radius: var(--phone-radius);
  box-shadow: 0 30px 44px -32px rgba(var(--shadow), 0.48),
              0 30px 46px -20px rgba(var(--shadow), 0.32);
}
@media (max-width: 700px) { .family-phone { width: 190px; } }
.avatar-orb {
  position: absolute; border-radius: 50%; overflow: hidden; background: var(--surface-2);
  border: 4px solid var(--surface); box-shadow: 0 14px 26px -14px rgba(var(--shadow), 0.35);
}
.avatar-orb img { width: 100%; height: 100%; object-fit: cover; }
.avatar-orb.a1 { width: 132px; height: 132px; top: 6%; left: 4%; }
.avatar-orb.a2 { width: 168px; height: 168px; top: 30%; right: 2%; }
.avatar-orb.a3 { width: 116px; height: 116px; bottom: 4%; left: 22%; }
.avatar-orb.a4 { width: 92px; height: 92px; top: 62%; right: 24%; }
@media (max-width: 780px) { .family-band { grid-template-columns: 1fr; } .avatar-cluster { min-height: 240px; } }

/* --------------------------------- pricing ----------------------------------- */
.pricing-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: stretch; }
.price-card { padding: 34px; border-radius: var(--radius-lg); background: var(--surface); border: 1px solid var(--border); display: flex; flex-direction: column; position: relative; }
.price-card.is-pro {
  border: 2.5px solid var(--primary); background: linear-gradient(165deg, color-mix(in srgb, var(--primary) 12%, var(--surface)), var(--surface) 55%);
  box-shadow: 0 24px 48px -24px color-mix(in srgb, var(--primary) 55%, transparent);
}
@media (min-width: 761px) { .price-card.is-pro { transform: scale(1.045); } }
.price-card .badge {
  position: absolute; top: -14px; right: 28px; background: linear-gradient(135deg, var(--primary-light), var(--primary));
  color: var(--on-primary); font-size: 0.76rem; font-weight: 800; padding: 6px 14px; border-radius: 999px;
  letter-spacing: 0.04em; text-transform: uppercase; box-shadow: 0 8px 18px -8px rgba(13,148,136,.5);
}
.price-card .plan-name { font-weight: 700; font-size: 1.1rem; margin-bottom: 6px; }
.price-card .plan-sub { color: var(--text-muted); font-size: 0.9rem; margin-bottom: 22px; }
.price-figure { display: flex; align-items: baseline; gap: 6px; margin-bottom: 4px; }
.price-figure .amount { font-size: 2.6rem; font-weight: 800; }
.price-figure .period { color: var(--text-muted); font-weight: 600; font-size: 0.95rem; }
.price-note { font-size: 0.82rem; color: var(--text-muted); margin-bottom: 24px; min-height: 1.2em; }
.price-card ul { display: flex; flex-direction: column; gap: 12px; margin-bottom: 28px; flex: 1; }
.price-card li { display: flex; align-items: flex-start; gap: 10px; font-size: 0.92rem; }
.price-card li .uic { font-size: 17px; color: var(--primary); flex-shrink: 0; margin-top: 1px; }
.price-card li.muted { color: var(--text-muted); }
.price-card li.muted .uic { color: var(--text-muted); }
.price-toggle { display: inline-flex; padding: 4px; background: var(--surface-2); border-radius: 999px; margin: 0 auto 36px; border: 1px solid var(--border); }
.price-toggle button { padding: 9px 20px; border-radius: 999px; font-weight: 700; font-size: 0.88rem; color: var(--text-muted); }
.price-toggle button.is-active { background: var(--surface); color: var(--text); box-shadow: 0 4px 12px -6px rgba(var(--shadow), 0.3); }
.save-tag { background: var(--secondary-container); color: var(--on-secondary-container); font-size: 0.72rem; font-weight: 800; padding: 2px 8px; border-radius: 999px; margin-left: 8px; }
@media (max-width: 760px) { .pricing-grid { grid-template-columns: 1fr; } }

/* ----------------------------------- faq ------------------------------------- */
.faq-list { display: flex; flex-direction: column; gap: 12px; max-width: 800px; margin-inline: auto; }
.faq-item { border: 1px solid var(--border); border-radius: 16px; background: var(--surface); overflow: hidden; }
.faq-q {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 20px 22px; text-align: left; font-weight: 700; font-size: 1rem;
}
.faq-q .plus { width: 22px; height: 22px; border-radius: 50%; background: var(--surface-2); flex-shrink: 0; position: relative; transition: transform .25s ease, background .25s ease; }
.faq-q .plus::before, .faq-q .plus::after { content: ""; position: absolute; background: var(--text); border-radius: 2px; top: 50%; left: 50%; }
.faq-q .plus::before { width: 10px; height: 2px; transform: translate(-50%, -50%); }
.faq-q .plus::after { width: 2px; height: 10px; transform: translate(-50%, -50%); transition: opacity .2s ease; }
.faq-item[open] .faq-q .plus { background: var(--primary-container); transform: rotate(90deg); }
.faq-item[open] .faq-q .plus::after { opacity: 0; }
.faq-a { padding: 0 22px 22px; color: var(--text-muted); font-size: 0.95rem; max-width: 68ch; }
.faq-item summary { list-style: none; cursor: pointer; }
.faq-item summary::-webkit-details-marker { display: none; }

/* ---------------------------------- cta band ---------------------------------- */
.cta-band {
  border-radius: var(--radius-lg); background: linear-gradient(135deg, var(--primary-strong), var(--primary));
  color: var(--on-primary); padding: clamp(40px, 6vw, 72px); display: grid; grid-template-columns: 1.3fr 0.7fr; align-items: center; gap: 32px; position: relative; overflow: hidden;
}
.cta-band h2 { color: var(--on-primary); }
.cta-band .lede { color: color-mix(in srgb, var(--on-primary) 82%, transparent); max-width: 42ch; }
.cta-band .store-badge { background: rgba(0,0,0,0.35); border-color: rgba(255,255,255,0.25); }
.cta-band-art { display: flex; justify-content: flex-end; }
.cta-band-art img { width: min(220px, 100%); }
@media (max-width: 760px) { .cta-band { grid-template-columns: 1fr; text-align: center; } .cta-band .lede { margin-inline: auto; } .cta-band-art { justify-content: center; order: -1; } .cta-band-art img { width: 140px; } .cta-band .store-badges { justify-content: center; } }

/* ---------------------------------- footer ------------------------------------ */
.site-footer { border-top: 1px solid var(--border); background: var(--surface); }
.footer-grid { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: 32px; padding-block: 56px 32px; }
.footer-brand .brand { margin-bottom: 12px; }
.footer-brand p { color: var(--text-muted); font-size: 0.9rem; max-width: 32ch; }
.footer-col h5 { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 14px; }
.footer-col ul { display: flex; flex-direction: column; gap: 10px; }
.footer-col a { font-size: 0.92rem; color: var(--text); font-weight: 500; }
.footer-col a:hover { color: var(--primary-strong); }
.footer-bottom {
  border-top: 1px solid var(--border); padding-block: 20px; display: flex; flex-wrap: wrap; gap: 12px;
  align-items: center; justify-content: space-between; font-size: 0.82rem; color: var(--text-muted);
}
.footer-bottom .uic { font-size: 0.95em; color: var(--primary); vertical-align: -0.08em; }
.footer-langs { display: flex; gap: 14px; }
.footer-langs a.is-active { color: var(--primary-strong); font-weight: 700; }
@media (max-width: 760px) { .footer-grid { grid-template-columns: repeat(2, 1fr); } }

/* ---------------------------------- legal / simple pages ----------------------- */
.page-hero { padding-block: clamp(48px, 7vw, 84px) 24px; text-align: center; }
.page-hero .eyebrow { justify-content: center; margin-bottom: 16px; }
.page-hero .lede { margin-inline: auto; }

.legal-doc { max-width: 780px; margin-inline: auto; padding-bottom: 40px; }
.legal-doc .updated { color: var(--text-muted); font-size: 0.88rem; margin-bottom: 40px; display: block; text-align: center; }
.legal-doc section { margin-bottom: 34px; }
.legal-doc h2 { font-size: 1.15rem; font-weight: 700; margin-bottom: 12px; }
.legal-doc p { color: var(--text-muted); font-size: 0.96rem; line-height: 1.7; }
.legal-doc a { color: var(--primary-strong); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }

.legal-nav { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-bottom: 48px; }
.legal-nav a { padding: 9px 16px; border-radius: 999px; border: 1px solid var(--border); font-weight: 600; font-size: 0.88rem; background: var(--surface); }
.legal-nav a.is-active { background: var(--primary-container); color: var(--on-primary-container); border-color: transparent; }

/* ---------------------------------- support page -------------------------------- */
.support-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: var(--space-section); }
.support-card { padding: 28px; border-radius: var(--radius); border: 1px solid var(--border); background: var(--surface); }
.support-card .icon-badge { width: 44px; height: 44px; border-radius: 12px; background: var(--primary-container); color: var(--on-primary-container); display: flex; align-items: center; justify-content: center; margin-bottom: 14px; }
.support-card .icon-badge .uic { font-size: 21px; }
.support-card h3 { font-size: 1.05rem; margin-bottom: 8px; }
.support-card p { color: var(--text-muted); font-size: 0.92rem; margin-bottom: 14px; }
.support-card a.link { color: var(--primary-strong); font-weight: 700; font-size: 0.9rem; display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 700px) { .support-grid { grid-template-columns: 1fr; } }

.support-panel { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; background: var(--surface-2); border-radius: var(--radius-lg); padding: clamp(28px, 5vw, 52px); margin-bottom: var(--space-section); }
.support-panel img { width: min(220px, 100%); margin-inline: auto; }
@media (max-width: 760px) { .support-panel { grid-template-columns: 1fr; text-align: center; } }

/* ---------------------------------- misc ------------------------------------ */
.divider-note { text-align: center; color: var(--text-muted); font-size: 0.85rem; margin-top: 18px; }
/* `transform: none` rather than `translateY(0)` in the settled state, so a
   finished reveal leaves no stacking context or compositing layer behind.
   `translateY(18px)` -> `none` still animates -- an absent transform
   interpolates as the identity matrix -- so the slide is unchanged.

   This is tidiness, not a bug fix. The iOS screenshot-shadow artifacts
   were once blamed on this animation compositing its subtree, and the
   reveal was moved around to suit; that theory was wrong and the change
   has been reverted. The cause was `filter: drop-shadow` itself -- see
   the phone-shadows note above. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .7s ease, transform .7s ease; }
.reveal.in-view { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; } }
