/* =============================================================================
   Roona — homepage
   Layered on /roona.css, which owns the tokens, faces and shared chrome.
   ========================================================================== */

body { overflow-x: hidden; }
main { overflow: clip; }
section { scroll-margin-top: 104px; }

/* The floor used to be 72px, which on a phone meant 144px of empty space
   between every pair of sections — a sixth of the whole page was gaps. */
.section { padding: clamp(54px, 9vw, 128px) 0; }
.section-lead {
  max-width: 46ch;
  margin: 16px 0 0;
  color: var(--muted);
  font-size: 17px;
  line-height: 1.72;
}

/* --- Floating navigation -------------------------------------------------- */
.site-header {
  position: fixed;
  inset: 14px 0 auto;
  z-index: 100;
  pointer-events: none;
}

.navbar {
  min-height: 62px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 9px 10px 9px 14px;
  border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
  border-radius: 999px;
  background: var(--nav);
  box-shadow: var(--shadow-sm);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  pointer-events: auto;
  transition:
    border-color var(--dur-menu) ease,
    box-shadow var(--dur-menu) ease,
    backdrop-filter var(--dur-menu) ease;
}

/* Once the page has moved, the pill sits over content rather than empty
   background, so it earns a firmer edge to keep the text under it legible. */
body.scrolled .navbar {
  border-color: var(--line);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(26px) saturate(160%);
  -webkit-backdrop-filter: blur(26px) saturate(160%);
}

.nav-links { display: flex; align-items: center; gap: 1px; }
.nav-links a {
  padding: 9px 13px;
  border-radius: 999px;
  color: var(--muted);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 650;
  transition: color var(--dur-hover) ease, background-color var(--dur-hover) ease;
}
.nav-links a:hover,
.nav-links a:focus-visible {
  color: var(--r700);
  background: var(--soft);
  outline: none;
}
body.dark .nav-links a:hover,
body.dark .nav-links a:focus-visible { color: var(--r300); }

.nav-actions { display: flex; align-items: center; gap: 8px; }
.mobile-menu-button { display: none; }
.mobile-menu { display: none; }

/* --- Hero ----------------------------------------------------------------- */
/* The photograph is the hero, not a device render. The one piece of product UI
   is a single journal entry laid over it — the actual artifact the product
   makes, at a size you can read. The phone lives once, further down, in the
   section where you can drive it. */
/* Top padding only has to clear the floating nav (8px inset + 56px tall on a
   phone), so the old 104px floor was 40px of dead space above the first line. */
.hero { padding: clamp(84px, 12vw, 132px) 0 clamp(36px, 5vw, 64px); }

.hero-grid {
  display: grid;
  /* The photograph is the larger object but not the wider column — giving the
     copy the extra width keeps the whole hero inside one viewport, which it
     wasn't at 0.98fr. */
  grid-template-columns: 1.14fr 0.86fr;
  gap: clamp(32px, 5vw, 76px);
  align-items: center;
}

.hero h1 {
  margin: 20px 0 0;
  max-width: 11ch;
}

.hero h1 em {
  font-style: normal;
  display: block;
  color: transparent;
  background: var(--gradient);
  background-clip: text;
  -webkit-background-clip: text;
  /* background-clip:text paints only inside the element's box, and a 0.98
     line-height box is shorter than Fraunces' ascent+descent — so the tails of
     "y" and "g" were being sliced off. Pad the paint box down, pull the same
     amount back off the layout box so nothing below moves. */
  padding-block-end: 0.2em;
  margin-block-end: -0.2em;
}

.hero-lead {
  max-width: 44ch;
  margin: 24px 0 0;
  color: var(--muted);
  font-size: clamp(16px, 1.7vw, 18.5px);
  line-height: 1.75;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 30px 0 0;
}

.hero-note {
  display: flex;
  align-items: center;
  gap: 11px;
  margin: 26px 0 0;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 600;
}

.avatar-stack { display: flex; padding-left: 8px; }
.avatar-stack span {
  width: 26px; height: 26px; margin-left: -8px;
  border: 2px solid var(--background);
  border-radius: 50%;
  background:
    radial-gradient(circle at 55% 38%, #f8c7bd 0 17%, transparent 18%),
    linear-gradient(135deg, var(--r200), var(--r500));
}
.avatar-stack span:nth-child(2) {
  background:
    radial-gradient(circle at 48% 40%, #e8b18f 0 17%, transparent 18%),
    linear-gradient(135deg, #d4a281, #713721);
}
.avatar-stack span:nth-child(3) {
  background:
    radial-gradient(circle at 52% 40%, #80543e 0 17%, transparent 18%),
    linear-gradient(135deg, #2c1c20, #b25f6d);
}

/* --- Hero figure ---------------------------------------------------------- */
.hero-figure { position: relative; }

.hero-photo {
  width: 100%;
  /* Required: the `height` attribute on <img> is a presentational hint that
     sets the CSS height, and `aspect-ratio` only sizes the box when height is
     auto. Without this the photo rendered at its full 1211px intrinsic height
     and the hero ran to 1,400px. */
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 22%;
  border-radius: clamp(20px, 3vw, 34px);
  background: var(--soft);
  box-shadow: var(--shadow-lg);
}

/* One journal entry, overlapping the photograph's lower-left corner. */
.entry-card {
  position: absolute;
  left: clamp(-40px, -3vw, -16px);
  bottom: clamp(-18px, -2vw, -10px);
  width: min(268px, 68%);
  padding: 16px 17px 15px;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--card-solid);
  box-shadow: var(--shadow-lg);
}

.entry-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 11px;
  border-bottom: 1px solid var(--border);
}
.entry-head .kicker { font-size: 9.5px; letter-spacing: 0.14em; }
.entry-count {
  color: var(--muted);
  font-size: 10px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.entry-step {
  display: grid;
  grid-template-columns: 22px 1fr 16px;
  gap: 9px;
  align-items: center;
  padding: 9px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  font-size: 12px;
  font-weight: 650;
}
.entry-step i {
  display: grid;
  place-items: center;
  width: 22px; height: 22px;
  border-radius: 7px;
  background: var(--soft);
  color: var(--r700);
  font-style: normal;
  font-size: 11px;
}
body.dark .entry-step i { color: var(--r300); }
.entry-check {
  display: grid; place-items: center;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--success); color: #fff;
  font-size: 9px; font-weight: 800;
}
.entry-step.todo .entry-check { background: var(--border); color: var(--muted); }

.entry-reading { padding-top: 12px; }
.entry-reading strong {
  display: block;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 500;
  font-size: 21px;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 3px 0 2px;
}
.entry-reading small { color: var(--muted); font-size: 10px; font-weight: 700; }

/* --- Streak ribbon (signature) -------------------------------------------- */
/* A month of showing up, drifting past. Gaps included on purpose — the product
   promise is consistency, not a perfect record, and a ribbon with no empty days
   would be selling the opposite. Constant motion, so `linear` is correct here.*/
.streak {
  position: relative;
  padding: clamp(26px, 4vw, 42px) 0 clamp(36px, 5vw, 56px);
}

.streak-track {
  display: flex;
  width: max-content;
  gap: 9px;
  animation: streak-drift 96s linear infinite;
  /* Fade both ends so the band reads as a continuous run rather than a list
     that starts and stops at the viewport edge. */
  mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}

@keyframes streak-drift {
  to { transform: translateX(-50%); }
}

.streak:hover .streak-track { animation-play-state: paused; }

.day-tile {
  flex: none;
  width: 54px;
  padding: 10px 0 9px;
  border: 1px solid var(--border);
  border-radius: 13px;
  background: var(--card-solid);
  text-align: center;
}
.day-tile b {
  display: block;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--muted);
  text-transform: uppercase;
}
.day-tile span {
  display: block;
  margin-top: 1px;
  font-size: 14px;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.day-dots {
  display: flex;
  justify-content: center;
  gap: 3px;
  height: 5px;
  margin-top: 8px;
}
.day-dots i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--r500);
}
.day-tile.rest { background: transparent; border-style: dashed; }
.day-tile.rest span, .day-tile.rest b { opacity: 0.45; }
.day-tile.today {
  border-color: var(--r500);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--r500) 14%, transparent);
}

.streak-caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 14px;
  margin-top: clamp(20px, 3vw, 30px);
  color: var(--muted);
  font-size: 13.5px;
}
.streak-caption strong { color: var(--text); font-weight: 700; }

/* --- Feature bento -------------------------------------------------------- */
/* Two cards that show something, four that say something. A grid of six
   identical cards is what this was, and it read as a spec sheet. */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-top: 40px;
}

.feature-card {
  display: flex;
  flex-direction: column;
  /* The media block bleeds to the card edge, so the card has to clip it or the
     photograph squares off the rounded corner. */
  overflow: hidden;
  padding: 24px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--card-solid);
  box-shadow: var(--shadow-sm);
  transition:
    transform var(--dur-menu) var(--ease-out),
    box-shadow var(--dur-menu) var(--ease-out),
    border-color var(--dur-menu) ease;
}

@media (hover: hover) and (pointer: fine) {
  .feature-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-md);
    border-color: color-mix(in srgb, var(--r700) 20%, var(--border));
  }
}

.feature-card.wide { grid-column: span 2; }

/* The anchor tile. Two columns AND two rows, so the photograph gets real
   height instead of the 170px letterbox every other media block gets — the
   grid stops reading as "two big, four small" and starts having a subject. */
.feature-card.tall { grid-row: span 2; }
.feature-card.tall .feature-media {
  flex: 1;
  min-height: 210px;
  margin-block-start: 22px;
}
.feature-card.tall .feature-media img { height: 100%; }

.feature-icon {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  margin-bottom: 18px;
  border-radius: 12px;
  color: var(--r700);
  background: var(--soft);
}
body.dark .feature-icon { color: var(--r300); }
.feature-card.ai .feature-icon { color: var(--ai); background: color-mix(in srgb, var(--ai) 12%, transparent); }
.feature-card.ok .feature-icon { color: var(--success); background: color-mix(in srgb, var(--success) 12%, transparent); }

.feature-card h3 {
  margin: 0 0 9px;
  font-size: 17.5px;
  font-weight: 750;
  letter-spacing: -0.024em;
}
.feature-card.wide h3 { font-size: 21px; }
.feature-card p {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.68;
}

.feature-media {
  margin: 20px -24px -24px;
  overflow: hidden;
  border-top: 1px solid var(--border);
}
.feature-media img { width: 100%; height: 170px; object-fit: cover; }

/* Bars grow rather than state their value — the card is about progress
   accumulating, so the visual should accumulate. */
/* margin-top:auto pins the chart to the card's floor, so the slack from the
   taller card beside it opens up above the bars rather than below them. */
.chart {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  height: 118px;
  margin: 28px 0 0;
  margin-top: auto;
  padding-top: 24px;
}
.chart span {
  flex: 1;
  border-radius: 5px 5px 2px 2px;
  background: linear-gradient(180deg, var(--rose), var(--r700));
  transform-origin: bottom;
  scale: 1 0.07;
}
.chart span:nth-child(1) { height: 34%; }
.chart span:nth-child(2) { height: 46%; }
.chart span:nth-child(3) { height: 40%; }
.chart span:nth-child(4) { height: 61%; }
.chart span:nth-child(5) { height: 72%; }
.chart span:nth-child(6) { height: 84%; }
.chart span:nth-child(7) { height: 96%; }

.reveal.visible .chart span { animation: bar-grow 620ms var(--ease-out) both; }
@keyframes bar-grow { from { scale: 1 0.07; } to { scale: 1 1; } }
.reveal.visible .chart span:nth-child(1) { animation-delay: 170ms; }
.reveal.visible .chart span:nth-child(2) { animation-delay: 225ms; }
.reveal.visible .chart span:nth-child(3) { animation-delay: 280ms; }
.reveal.visible .chart span:nth-child(4) { animation-delay: 335ms; }
.reveal.visible .chart span:nth-child(5) { animation-delay: 390ms; }
.reveal.visible .chart span:nth-child(6) { animation-delay: 445ms; }
.reveal.visible .chart span:nth-child(7) { animation-delay: 500ms; }

@media (max-width: 980px) {
  .feature-grid { grid-template-columns: repeat(2, 1fr); }
  .feature-card.wide { grid-column: span 2; }
  /* At two columns a row-span would strand a gap beside it. */
  .feature-card.tall { grid-row: auto; }
  .feature-card.tall .feature-media { flex: none; min-height: 0; }
  .feature-card.tall .feature-media img { height: 170px; }
}
@media (max-width: 620px) {
  .feature-grid { grid-template-columns: 1fr; }
  .feature-card.wide { grid-column: auto; }
}

/* --- Pill eyebrows -------------------------------------------------------- */
/* The section labels were bare tracked caps, which read as a caption rather
   than a marker. As pills they become objects on the page — the same atom the
   nav button, the plan badge and the tags use, so the whole page shares one
   vocabulary. Scoped to .kicker-pill so card-level kickers stay small text. */
.kicker-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 13px 6px 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card-solid);
  box-shadow: var(--shadow-sm);
  white-space: nowrap;
}
.pill-dot {
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--r500);
}
body.dark .pill-dot { background: var(--r400); }

.kicker-solid {
  border-color: transparent;
  background: var(--r700);
  color: #fff5f8;
}
body.dark .kicker-solid { background: var(--r600); color: #fff5f8; }
.kicker-solid .pill-dot { background: var(--r200); }

/* --- Hero additions ------------------------------------------------------- */
/* Two soft blooms bleeding off the canvas. Every reference in the moodboard
   does this; without it a near-white page reads as a document, not a product. */
.hero::before,
.hero::after {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 50%;
  filter: blur(70px);
  pointer-events: none;
}
.hero::before {
  inset-block-start: -6%;
  inset-inline-end: -6%;
  width: 46vw;
  max-width: 620px;
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(243, 161, 143, 0.38), transparent 68%);
}
.hero::after {
  inset-block-start: 34%;
  inset-inline-start: -12%;
  width: 38vw;
  max-width: 520px;
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(217, 108, 135, 0.24), transparent 68%);
}
.hero { position: relative; isolation: isolate; }
body.dark .hero::before { background: radial-gradient(circle, rgba(243, 161, 143, 0.17), transparent 68%); }
body.dark .hero::after { background: radial-gradient(circle, rgba(217, 108, 135, 0.15), transparent 68%); }

.hero-stats {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(18px, 3vw, 36px);
  margin: 26px 0 0;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.hero-stats div { display: flex; flex-direction: column; gap: 1px; }
.hero-stats dt {
  font-family: var(--font-display);
  font-size: clamp(21px, 2.6vw, 27px);
  font-weight: 600;
  color: var(--text);
  line-height: 1.1;
}
.hero-stats dd {
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
}

/* Tags orbit the figure. Absolute so they can overlap the photo's edge — a
   chip fully inside the frame reads as a caption, one straddling the edge
   reads as a layer above it. */
.hero-figure { position: relative; }
.hero-tags { list-style: none; margin: 0; padding: 0; }
.hero-tags li {
  position: absolute;
  z-index: 3;
  padding: 5px 11px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card-solid);
  box-shadow: var(--shadow-sm);
  font-size: 12px;
  font-weight: 600;
  color: var(--r600);
  white-space: nowrap;
}
body.dark .hero-tags li { color: var(--r300); }
/* Only the left edge may straddle: that side opens onto the copy column, which
   has slack. The right edge is the container edge, so a negative inset there
   hangs the chip off the viewport at anything under ~1360px. */
.hero-tags .tag-a { inset-block-start: 4%; inset-inline-start: -7%; }
.hero-tags .tag-b { inset-block-start: 17%; inset-inline-end: 3%; }
.hero-tags .tag-c { inset-block-start: 40%; inset-inline-start: -9%; }
.hero-tags .tag-d { inset-block-end: 21%; inset-inline-end: 2%; }
/* Bottom-left belongs to the entry card — a chip there lands on the reading. */
.hero-tags .tag-e { inset-block-start: -3%; inset-inline-end: 26%; }

.hero-figure .hero-tags li {
  animation: tag-in 520ms var(--ease-out) both;
}
.hero-tags .tag-a { animation-delay: 620ms; }
.hero-tags .tag-b { animation-delay: 690ms; }
.hero-tags .tag-c { animation-delay: 760ms; }
.hero-tags .tag-d { animation-delay: 830ms; }
.hero-tags .tag-e { animation-delay: 900ms; }
@keyframes tag-in {
  from { opacity: 0; scale: 0.92; }
  to { opacity: 1; scale: 1; }
}

@media (max-width: 1180px) {
  /* Below this the figure is too narrow to hold five chips without one of
     them landing on the entry card. Cheaper to drop them than to reflow. */
  .hero-tags { display: none; }
}

/* --- Problem -------------------------------------------------------------- */
.section-problem { padding-top: clamp(10px, 2vw, 20px); }

.problem-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  margin-top: 30px;
}

.problem-card {
  padding: 22px 22px 24px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card-solid);
  box-shadow: var(--shadow-sm);
}
.problem-num {
  display: block;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  color: var(--r400);
  margin-bottom: 10px;
}
.problem-card h3 {
  margin: 0 0 8px;
  font-size: clamp(15.5px, 1.8vw, 17px);
  line-height: 1.3;
  color: var(--text);
}
.problem-card p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--muted);
}

.problem-turn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  max-width: var(--measure);
  margin: 26px 0 0;
  font-size: clamp(15px, 1.7vw, 17px);
  line-height: 1.6;
  color: var(--text);
}

.reveal.visible .problem-card {
  animation: compare-in 480ms var(--ease-out) both;
}
.reveal.visible .problem-card:nth-of-type(1) { animation-delay: 100ms; }
.reveal.visible .problem-card:nth-of-type(2) { animation-delay: 155ms; }
.reveal.visible .problem-card:nth-of-type(3) { animation-delay: 210ms; }

@media (max-width: 860px) {
  .problem-grid { grid-template-columns: 1fr; }
}

/* --- Compare -------------------------------------------------------------- */
/* Two dated entries with the elapsed time stated between them. The gap is the
   point of the section, so it gets its own column rather than being implied by
   whitespace. Deliberately NOT a wipe slider: these are two separate sittings,
   and sliding one over the other would imply a precision the journal doesn't
   claim. */
.compare-frame {
  margin-top: 30px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: start;
  gap: clamp(10px, 2.4vw, 26px);
  max-width: 720px;
}

.compare-entry { margin: 0; }

.compare-shot {
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card-solid);
  box-shadow: var(--shadow-sm);
}
.compare-shot img { display: block; width: 100%; height: auto; }

.compare-entry figcaption {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 11px 2px 0;
}
.compare-date {
  font-family: var(--font-display);
  font-size: clamp(15px, 1.9vw, 18px);
  font-weight: 500;
  color: var(--text);
}
.compare-note {
  font-size: clamp(11px, 1.5vw, 12.5px);
  color: var(--muted);
}

/* The elapsed-time column: a hairline the eye reads as a span, labelled. */
.compare-gap {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding-top: 6px;
}
.compare-gap::after {
  content: "";
  flex: 1;
  width: 1px;
  background: linear-gradient(var(--line), transparent);
}
.compare-span {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(11.5px, 1.6vw, 13.5px);
  color: var(--r600);
  white-space: nowrap;
  writing-mode: vertical-rl;
  rotate: 180deg;
  letter-spacing: 0.02em;
}
body.dark .compare-span { color: var(--r300); }

.compare-disclaimer {
  margin-top: 16px;
  max-width: var(--measure);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--muted);
}

/* Entries settle in from the outside toward the gap between them, so the
   elapsed span is the last thing to land. */
.reveal.visible .compare-entry {
  animation: compare-in var(--dur-reveal) var(--ease-out) both;
}
.reveal.visible .compare-entry:nth-of-type(1) { animation-delay: 120ms; }
.reveal.visible .compare-entry:nth-of-type(2) { animation-delay: 175ms; }
.reveal.visible .compare-gap {
  animation: compare-gap-in 420ms var(--ease-out) 300ms both;
}
@keyframes compare-in {
  from { opacity: 0; translate: 0 14px; }
  to { opacity: 1; translate: 0 0; }
}
@keyframes compare-gap-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (max-width: 520px) {
  /* Vertical text needs more height than a short caption gives it; below this
     width the label reads better lying down between the two shots. */
  .compare-span { writing-mode: horizontal-tb; rotate: none; }
  .compare-gap::after { display: none; }
  .compare-gap { padding-top: 0; align-self: center; }
}

/* --- Experience / demo ---------------------------------------------------- */
.demo-grid {
  display: grid;
  grid-template-columns: 0.82fr 1.18fr;
  gap: clamp(32px, 4vw, 56px);
  align-items: center;
  margin-top: 40px;
}

.demo-tabs { display: grid; gap: 8px; }
.demo-tab {
  width: 100%;
  display: grid;
  grid-template-columns: 42px 1fr auto;
  gap: 13px;
  align-items: center;
  padding: 14px;
  border: 1px solid transparent;
  border-radius: 16px;
  color: var(--text);
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition:
    border-color var(--dur-hover) ease,
    background-color var(--dur-hover) ease,
    box-shadow var(--dur-hover) ease,
    transform var(--dur-press) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .demo-tab:hover { background: var(--soft); }
}
.demo-tab.active {
  border-color: var(--line);
  background: var(--card-solid);
  box-shadow: var(--shadow-sm);
}
.demo-tab:active { transform: scale(0.985); transition-duration: 100ms; }

.demo-tab-icon {
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: 12px;
  color: var(--r700);
  background: var(--soft);
}
body.dark .demo-tab-icon { color: var(--r300); }
.demo-tab:nth-child(2) .demo-tab-icon { color: var(--ai); background: color-mix(in srgb, var(--ai) 12%, transparent); }
.demo-tab:nth-child(3) .demo-tab-icon { color: var(--success); background: color-mix(in srgb, var(--success) 12%, transparent); }

.demo-tab strong, .demo-tab small { display: block; }
.demo-tab strong { margin-bottom: 2px; font-size: 14px; font-weight: 700; letter-spacing: -0.015em; }
.demo-tab small { color: var(--muted); font-size: 12px; line-height: 1.5; }
.demo-tab-arrow {
  color: var(--muted); font-size: 17px;
  transition: color var(--dur-hover) ease, transform var(--dur-menu) var(--ease-out);
}
.demo-tab.active .demo-tab-arrow { color: var(--r700); transform: translateX(3px); }
body.dark .demo-tab.active .demo-tab-arrow { color: var(--r300); }

.demo-stage {
  position: relative;
  min-height: 640px;
  display: grid;
  place-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background:
    radial-gradient(circle at 50% 30%, color-mix(in srgb, var(--rose) 12%, transparent), transparent 58%),
    var(--surface);
}

.demo-phone {
  width: 282px;
  padding: 9px;
  border-radius: 40px;
  background: #1d1519;
  box-shadow: 0 30px 68px rgba(62, 18, 38, 0.26), 0 0 0 1px rgba(0, 0, 0, 0.2);
}
.demo-phone-screen {
  position: relative;
  height: 578px;
  overflow: hidden;
  border-radius: 32px;
  background: var(--background);
}

/* Panels are a stack in tab order, so they travel in tab order: going down the
   list, the new panel arrives from the right and the old one leaves left.
   `.from-left` (set in JS) flips that for going back up. The blur keeps two
   overlapping screens reading as one screen changing. */
.demo-view {
  position: absolute;
  inset: 0;
  padding: 32px 17px 18px;
  opacity: 0;
  transform: translateX(22px);
  filter: blur(4px);
  pointer-events: none;
  transition:
    opacity 220ms var(--ease-out),
    transform 280ms var(--ease-out),
    filter 220ms var(--ease-out);
}
.demo-view.from-left { transform: translateX(-22px); }
.demo-view.active {
  opacity: 1;
  transform: translateX(0);
  filter: blur(0);
  pointer-events: auto;
}

.phone-status {
  display: flex; justify-content: space-between;
  padding: 0 6px;
  color: var(--muted); font-size: 9px; font-weight: 800;
}
.demo-phone-title {
  display: flex; align-items: end; justify-content: space-between;
  margin: 18px 0 16px;
}
.demo-phone-title small { color: var(--muted); font-size: 9px; }
.demo-phone-title h3 {
  margin: 2px 0 0; font-size: 19px; letter-spacing: -0.03em; font-weight: 750;
}

.routine-list-card {
  margin-top: 8px;
  padding: 11px;
  border: 1px solid var(--border);
  border-radius: 15px;
  background: var(--card-solid);
}
.routine-list-card.completed {
  border-color: color-mix(in srgb, var(--success) 32%, var(--border));
  background: color-mix(in srgb, var(--success) 5%, var(--surface));
}
.routine-list-top { display: flex; align-items: center; gap: 9px; }
.routine-icon {
  width: 34px; height: 34px; flex: 0 0 34px;
  display: grid; place-items: center;
  border-radius: 11px;
  color: var(--r700); background: var(--soft);
}
body.dark .routine-icon { color: var(--r300); }
.routine-list-top div:nth-child(2) { flex: 1; min-width: 0; }
.routine-list-top strong, .routine-list-top small { display: block; }
.routine-list-top strong { font-size: 10px; }
.routine-list-top small { color: var(--muted); font-size: 8px; }
.check {
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: #fff; background: var(--success);
  font-size: 9px; font-weight: 800;
}
.schedule-pill {
  padding: 5px 8px; border-radius: 999px;
  color: var(--r700); background: var(--soft);
  font-size: 7.5px; font-weight: 800;
}
body.dark .schedule-pill { color: var(--r300); }

.section-line {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 20px 2px 9px;
  font-size: 10px; font-weight: 800;
}
.section-line span:last-child { color: var(--r700); font-size: 8.5px; }
body.dark .section-line span:last-child { color: var(--r300); }

.week-row { display: flex; justify-content: space-between; gap: 4px; margin-top: 13px; }
.day {
  flex: 1; padding: 8px 3px; border-radius: 9px;
  color: var(--muted); background: var(--surface);
  text-align: center; font-size: 7px; font-weight: 700;
}
.day.done { color: #fff; background: var(--r700); }

/* 356px put the capture button and the "not a diagnosis" line 25px past the
   bottom of the screen, where `overflow: hidden` cut them off. */
.camera-preview {
  position: relative; height: 328px; overflow: hidden;
  border-radius: 21px;
  background: url("/img/capture-face.webp") center / cover no-repeat;
}
.camera-frame {
  position: absolute; inset: 40px 30px 42px;
  background:
    linear-gradient(#fff, #fff) left top / 28px 2px no-repeat,
    linear-gradient(#fff, #fff) left top / 2px 28px no-repeat,
    linear-gradient(#fff, #fff) right top / 28px 2px no-repeat,
    linear-gradient(#fff, #fff) right top / 2px 28px no-repeat,
    linear-gradient(#fff, #fff) left bottom / 28px 2px no-repeat,
    linear-gradient(#fff, #fff) left bottom / 2px 28px no-repeat,
    linear-gradient(#fff, #fff) right bottom / 28px 2px no-repeat,
    linear-gradient(#fff, #fff) right bottom / 2px 28px no-repeat;
  border-radius: 22px; opacity: 0.88;
}
.camera-tip {
  position: absolute; right: 18px; bottom: 15px; left: 18px;
  padding: 9px; border-radius: 11px;
  color: #fff; background: rgba(30, 20, 25, 0.6);
  backdrop-filter: blur(8px);
  text-align: center; font-size: 8px; font-weight: 650;
}
.capture-button {
  width: 50px; height: 50px;
  display: grid; place-items: center;
  margin: 19px auto 0;
  border: 4px solid var(--r200); border-radius: 50%;
  background: var(--r700);
}
.capture-button::after { content: ""; width: 14px; height: 14px; border-radius: 50%; background: #fff; }
/* Was an inline style, which no media query could reach — and this is one of
   the strings that most needed to grow when the preview does. */
.capture-note {
  margin: 13px 14px 0;
  color: var(--muted);
  font-size: 8px;
  line-height: 1.55;
  text-align: center;
}

.report-hero {
  padding: 15px; border: 1px solid var(--border);
  border-radius: 19px; background: var(--card-solid);
}
.report-caption { color: var(--muted); font-size: 8px; }
.report-score { display: flex; align-items: flex-end; justify-content: space-between; margin: 8px 0 0; }
.report-score strong {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 500; font-size: 34px; line-height: 1; letter-spacing: -0.03em;
}
.report-score span { color: var(--success); font-size: 8.5px; font-weight: 750; }

.insight-row {
  display: flex; align-items: center; gap: 9px;
  margin-top: 8px; padding: 10px;
  border: 1px solid var(--border); border-radius: 13px; background: var(--card-solid);
}
.insight-dot {
  width: 32px; height: 32px; flex: 0 0 32px;
  display: grid; place-items: center; border-radius: 10px;
  color: var(--hydration); background: color-mix(in srgb, var(--hydration) 12%, transparent);
}
/* Was `.insight-row:nth-of-type(3)`, which counts every div sibling in the
   panel — the third of those is the report card, so the amber never landed and
   "worth a look" was drawn in the same calm blue as the other two. */
.insight-row.warn .insight-dot { color: var(--warning); background: color-mix(in srgb, var(--warning) 12%, transparent); }
.insight-row div:nth-child(2) { flex: 1; min-width: 0; }
.insight-row strong { display: block; font-size: 9px; }
.insight-row small { display: block; color: var(--muted); font-size: 7.5px; }
.insight-value { font-size: 8.5px; font-weight: 800; }

.scan-cta {
  width: 100%; min-height: 40px; margin-top: 13px;
  border: 0; border-radius: 12px;
  color: #fff; background: var(--r700);
  font-size: 9.5px; font-weight: 800; cursor: pointer;
  transition: transform var(--dur-press) var(--ease-out);
}
.scan-cta:active { transform: scale(0.97); transition-duration: 100ms; }

@media (max-width: 980px) {
  .demo-grid { grid-template-columns: 1fr; }
  .demo-stage { min-height: 610px; }
}

/* --- Steps (a real sequence, so the numbers mean something) ---------------- */
.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 3vw, 40px);
  margin-top: 44px;
  counter-reset: steps;
}
.step {
  counter-increment: steps;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.step::before {
  content: "0" counter(steps);
  display: block;
  margin-bottom: 18px;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 400;
  font-size: 34px;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--rose);
}
.step h3 { margin: 0 0 8px; font-size: 18px; font-weight: 750; letter-spacing: -0.025em; }
.step p { margin: 0; color: var(--muted); font-size: 14.5px; line-height: 1.7; }

.steps-figure {
  margin-top: clamp(40px, 5vw, 64px);
  overflow: hidden;
  border-radius: var(--radius-xl);
}
.steps-figure img { width: 100%; height: clamp(220px, 30vw, 380px); object-fit: cover; }

@media (max-width: 760px) {
  .steps { grid-template-columns: 1fr; gap: 26px; }
}

/* --- Plans ---------------------------------------------------------------- */
.plans {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-top: 40px;
}
.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 30px 28px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--card-solid);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-menu) var(--ease-out), box-shadow var(--dur-menu) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .plan:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
}
.plan.featured {
  border-color: transparent;
  background:
    linear-gradient(var(--card-solid), var(--card-solid)) padding-box,
    var(--gradient) border-box;
  box-shadow: var(--shadow-md);
}
.plan-tag {
  position: absolute; top: -12px; right: 24px;
  padding: 6px 13px; border-radius: 999px;
  color: #fff; background: var(--gradient);
  font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
}
.plan-price {
  margin: 12px 0 4px;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 500; font-size: 30px; line-height: 1.12; letter-spacing: -0.03em;
}
.plan-price small { display: block; margin-top: 7px; font-family: var(--font-body); font-size: 13px; font-weight: 600; color: var(--muted); letter-spacing: normal; }
.plan-sub { color: var(--muted); font-size: 14.5px; margin: 6px 0 22px; }
.plan-list { list-style: none; margin: 0 0 22px; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.plan-list li { display: flex; gap: 11px; align-items: flex-start; font-size: 14.5px; }
.plan-list i {
  flex: none; width: 19px; height: 19px; margin-top: 3px;
  display: grid; place-items: center; border-radius: 50%;
  font-size: 10px; font-style: normal; color: #fff; background: var(--success);
}
.plan-list li.ai i { background: var(--ai); }
.plan-note { margin-top: auto; padding-top: 6px; color: var(--muted); font-size: 12.5px; }

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

/* --- Privacy band --------------------------------------------------------- */
/* Full-bleed photograph with a plum scrim, rather than the gradient blob that
   was here. The claim is that your face data stays somewhere quiet and yours;
   a real room says that better than a blur. */
.privacy {
  position: relative;
  margin: clamp(60px, 8vw, 100px) 0 0;
  padding: clamp(64px, 9vw, 118px) 0;
  overflow: hidden;
  color: #fff;
  isolation: isolate;
}
.privacy::before {
  content: "";
  position: absolute; inset: 0; z-index: -2;
  background: url("/img/evening-shelf.webp") center / cover no-repeat;
  /* The shot groups its objects on the left, which is exactly where the copy
     sits. Mirrored, the shelf reads in the empty right half instead of being
     buried under text. */
  transform: scaleX(-1);
}
.privacy::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(100deg, rgba(35, 10, 20, 0.92) 0%, rgba(53, 16, 30, 0.74) 46%, rgba(84, 23, 46, 0.3) 100%);
}
.privacy .kicker { color: #ffd8df; }
.privacy h2 { color: #fff; max-width: 16ch; }
.privacy-lead { max-width: 44ch; margin: 18px 0 0; color: rgba(255, 255, 255, 0.78); font-size: 16px; line-height: 1.75; }
.privacy-list { display: grid; gap: 12px; margin: 28px 0 0; padding: 0; list-style: none; max-width: 52ch; }
.privacy-list li { display: flex; align-items: flex-start; gap: 11px; color: rgba(255, 255, 255, 0.9); font-size: 14.5px; }
.privacy-list i {
  flex: 0 0 20px; width: 20px; height: 20px; margin-top: 3px;
  display: grid; place-items: center; border-radius: 50%;
  color: var(--r800); background: #fff;
  font-style: normal; font-size: 10px; font-weight: 900;
}
.privacy-link {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 26px; color: #ffd8df; font-weight: 700; font-size: 14.5px; text-decoration: none;
  transition: gap var(--dur-hover) var(--ease-out);
}
.privacy-link:hover { gap: 11px; }

/* --- FAQ ------------------------------------------------------------------ */
.faq-grid {
  display: grid;
  grid-template-columns: 0.72fr 1.28fr;
  gap: clamp(30px, 5vw, 70px);
  align-items: start;
}
.faq-list { display: grid; gap: 8px; }
.faq-item {
  overflow: hidden;
  border-bottom: 1px solid var(--border);
  transition: border-color var(--dur-menu) ease;
}
.faq-item.open { border-color: color-mix(in srgb, var(--r700) 26%, var(--border)); }
.faq-question {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 20px 4px;
  border: 0; color: var(--text); background: transparent;
  cursor: pointer; text-align: left;
  font-size: 15px; font-weight: 700; letter-spacing: -0.015em;
  transition: color 140ms ease;
}
.faq-question:hover { color: var(--r700); }
body.dark .faq-question:hover { color: var(--r300); }
.faq-plus {
  position: relative;
  width: 24px; height: 24px; flex: 0 0 24px;
  display: grid; place-items: center; border-radius: 50%;
  color: var(--r700); background: var(--soft);
  transition: transform 260ms var(--ease-out), background-color var(--dur-hover) ease, color var(--dur-hover) ease;
  /* The mark is drawn, not typed. place-items centred the glyph's line box,
     not its ink, so the "+" sat high in the circle — invisible until the open
     state rotates it 135° and the offset becomes an off-centre "×". */
  font-size: 0;
}
.faq-plus::before,
.faq-plus::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  width: 10px;
  height: 1.6px;
  border-radius: 2px;
  background: currentColor;
  translate: -50% -50%;
}
.faq-plus::after { rotate: 90deg; }
body.dark .faq-plus { color: var(--r300); }
.faq-answer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 200ms var(--ease-out);
}
.faq-answer > div { overflow: hidden; }
.faq-answer p {
  margin: 0; padding: 0 4px 20px;
  color: var(--muted); font-size: 14.5px; line-height: 1.72;
  max-width: 62ch;
  /* Without this the text is hard-clipped by the row as it opens. */
  opacity: 0;
  translate: 0 -4px;
  transition: opacity 140ms ease, translate 200ms var(--ease-out);
}
/* Opening is deliberate; closing gets out of the way (200ms, from the base). */
.faq-item.open .faq-answer { grid-template-rows: 1fr; transition-duration: 260ms; }
.faq-item.open .faq-answer p { opacity: 1; translate: 0 0; transition-delay: 60ms; }
.faq-item.open .faq-plus { transform: rotate(135deg); color: #fff; background: var(--r700); }

@media (max-width: 860px) { .faq-grid { grid-template-columns: 1fr; } }

/* --- Closing call to action ----------------------------------------------- */
.cta { padding: clamp(80px, 10vw, 128px) 0 clamp(90px, 11vw, 140px); }
.cta-card {
  position: relative;
  overflow: hidden;
  padding: clamp(52px, 7vw, 84px) clamp(26px, 4vw, 40px);
  border-radius: var(--radius-xl);
  color: #fff;
  background: var(--gradient);
  box-shadow: var(--shadow-lg);
  text-align: center;
}
.cta-card::before, .cta-card::after {
  content: ""; position: absolute; border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
}
.cta-card::before { width: 280px; height: 280px; top: -190px; left: -70px; }
.cta-card::after { width: 350px; height: 350px; right: -170px; bottom: -250px; }
.cta-content { position: relative; z-index: 1; max-width: 640px; margin: 0 auto; }
.cta-card h2 { color: #fff; margin: 14px 0 0; }
.cta-card > .cta-content > p {
  max-width: 46ch; margin: 16px auto 0;
  color: rgba(255, 255, 255, 0.85); font-size: 15.5px; line-height: 1.7;
}
.cta .kicker { color: rgba(255, 255, 255, 0.82); }

.store-badges { display: flex; flex-wrap: wrap; justify-content: center; gap: 11px; margin: 28px 0 0; }
.store-badge {
  display: inline-flex; align-items: center; gap: 11px;
  padding: 11px 18px; border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(255, 255, 255, 0.12); color: #fff;
  transition: transform var(--dur-menu) var(--ease-out), background-color var(--dur-hover) ease;
}
@media (hover: hover) and (pointer: fine) {
  .store-badge:hover { transform: translateY(-2px); background: rgba(255, 255, 255, 0.2); }
}
.store-badge svg { width: 21px; height: 21px; flex: none; }
.store-badge span { display: flex; flex-direction: column; line-height: 1.15; text-align: left; }
.store-badge small { font-size: 10.5px; opacity: 0.85; }
.store-badge strong { font-size: 15px; font-weight: 700; }

.waitlist-form {
  display: flex; flex-wrap: wrap; gap: 9px; justify-content: center;
  margin: 28px auto 0; max-width: 440px;
  transition: opacity 180ms ease, translate 180ms var(--ease-out), filter 180ms ease;
}
.waitlist-form input[type="email"] {
  flex: 1 1 220px; min-width: 0; font-size: 16px;
  padding: 13px 18px; color: #fff;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 999px;
  transition: border-color var(--dur-hover) ease, background-color var(--dur-hover) ease;
}
.waitlist-form input[type="email"]::placeholder { color: rgba(255, 255, 255, 0.62); }
.waitlist-form input[type="email"]:hover { border-color: rgba(255, 255, 255, 0.55); }
.waitlist-form input[type="email"]:focus-visible {
  outline: none; border-color: #fff; background: rgba(255, 255, 255, 0.2);
}
.waitlist-form button {
  font-weight: 700; font-size: 15px; padding: 13px 24px; cursor: pointer;
  color: var(--r700); background: #fff; border: 0; border-radius: 999px;
  transition: opacity var(--dur-hover) ease, transform var(--dur-press) var(--ease-out);
}
.waitlist-form button:hover { opacity: 0.92; }
.waitlist-form button:active { transform: scale(0.97); transition-duration: 100ms; }
.waitlist-form button[disabled] { opacity: 0.6; cursor: default; transform: none; }

/* The form used to be yanked out of the DOM and the confirmation dropped in on
   the same frame. Letting it leave first makes the swap one movement. */
.waitlist-form.is-leaving { opacity: 0; translate: 0 -8px; filter: blur(4px); pointer-events: none; }
.waitlist-done {
  margin: 28px auto 0; max-width: 440px; font-size: 16.5px; font-weight: 600;
  animation: waitlist-done-in 420ms var(--ease-out) both;
}
@keyframes waitlist-done-in {
  from { opacity: 0; translate: 0 12px; filter: blur(4px); }
  to { opacity: 1; translate: 0 0; filter: none; }
}
.waitlist-note { margin: 14px 0 0; font-size: 13px; opacity: 0.88; }
.waitlist-note a, .cta-subnote a { color: #fff; text-decoration: underline; }
.cta-subnote { margin: 22px 0 0; font-size: 13.5px; opacity: 0.88; }
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --- Site footer ---------------------------------------------------------- */
.site-footer { padding: 0 0 40px; }
.footer-top {
  display: grid;
  grid-template-columns: 1.7fr repeat(4, 0.7fr);
  gap: 40px;
  padding: 52px 0;
  border-top: 1px solid var(--border);
}
.footer-brand p { max-width: 340px; margin: 16px 0 0; color: var(--muted); font-size: 13px; line-height: 1.7; }
.footer-social { display: flex; gap: 15px; margin-top: 20px; }
.footer-social a {
  display: inline-flex; color: var(--muted);
  transition: color var(--dur-hover) ease, transform var(--dur-press) var(--ease-out);
}
.footer-social a:hover { color: var(--r700); }
@media (hover: hover) and (pointer: fine) { .footer-social a:hover { transform: translateY(-2px); } }
.footer-social a:active { transform: scale(0.9); transition-duration: 100ms; }
.footer-social svg { width: 18px; height: 18px; fill: currentColor; }
.footer-column h3 {
  margin: 0 0 14px; font-size: 11px; font-weight: 800;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
}
.footer-column a {
  display: block; width: fit-content; margin-top: 9px;
  color: var(--text); text-decoration: none; font-size: 13.5px;
  transition: color var(--dur-hover) ease, translate var(--dur-hover) var(--ease-out);
}
.footer-column a:hover { color: var(--r700); }
body.dark .footer-column a:hover { color: var(--r300); }
@media (hover: hover) and (pointer: fine) { .footer-column a:hover { translate: 2px 0; } }
.footer-bottom {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  color: var(--muted); font-size: 11.5px;
}

/* --- Scroll reveals ------------------------------------------------------- */
/* Deliberately an `animation` on `opacity`/`translate`/`filter`, never
   `transform` — a transition on transform here silently killed every hover lift
   on the cards that also carry `.reveal`. Splitting the properties lets reveal,
   hover and press coexist on one element. */
@keyframes reveal-rise {
  from { opacity: 0; translate: 0 22px; filter: blur(6px); }
  to { opacity: 1; translate: 0 0; filter: none; }
}
.reveal { opacity: 0; }
.reveal.visible { animation: reveal-rise var(--dur-reveal) var(--ease-out) both; }
/* Retired on animationend: a `both`-filled `filter` resolves to blur(0px), not
   none, which would pin every revealed section to its own compositing layer. */
.reveal.revealed, .hero-intro > .revealed { opacity: 1; animation: none; }

.hero-intro > * { animation: reveal-rise 700ms var(--ease-out) both; }
.hero-intro > *:nth-child(1) { animation-delay: 60ms; }
.hero-intro > *:nth-child(2) { animation-delay: 130ms; }
.hero-intro > *:nth-child(3) { animation-delay: 200ms; }
.hero-intro > *:nth-child(4) { animation-delay: 270ms; }
.hero-intro > *:nth-child(5) { animation-delay: 340ms; }

.hero-figure { animation: hero-figure-in 900ms var(--ease-out) 180ms both; }
@keyframes hero-figure-in {
  from { opacity: 0; translate: 0 26px; scale: 0.98; }
  to { opacity: 1; translate: 0 0; scale: 1; }
}

.feature-grid > .reveal.visible:nth-child(2n) { animation-delay: 70ms; }
.plans > .reveal.visible:nth-child(2) { animation-delay: 70ms; }
.steps > .reveal.visible:nth-child(2) { animation-delay: 70ms; }
.steps > .reveal.visible:nth-child(3) { animation-delay: 140ms; }

/* --- Responsive ----------------------------------------------------------- */
@media (max-width: 1020px) {
  .nav-links { display: none; }
  .hero-grid { grid-template-columns: 1fr; }
  .hero h1 { max-width: 14ch; }
  .hero-figure { max-width: 520px; margin-top: 12px; }
}

@media (max-width: 760px) {
  .site-header { inset: calc(8px + env(safe-area-inset-top)) 0 auto; }
  .navbar { min-height: 56px; }
  .nav-actions > .button { display: none; }
  .mobile-menu-button { display: grid; }

  .mobile-menu {
    position: fixed;
    inset: calc(74px + env(safe-area-inset-top)) 12px auto;
    z-index: 99;
    display: grid;
    gap: 3px;
    padding: 11px;
    /* A short handset in landscape can't show six items plus a button; let the
       sheet scroll inside itself rather than run off the bottom. */
    max-height: calc(100dvh - 94px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--line);
    border-radius: 22px;
    background: var(--card-solid);
    box-shadow: var(--shadow-lg);
    opacity: 0;
    /* Scaling from the hamburger it hangs off, not its own middle — and from
       0.97, never 0: nothing real appears out of nothing. */
    transform: translateY(-8px) scale(0.97);
    transform-origin: top right;
    pointer-events: none;
    transition: opacity 170ms var(--ease-out), transform 170ms var(--ease-out);
  }
  .mobile-menu.open {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
    transition-duration: var(--dur-menu);
  }
  .mobile-menu a {
    padding: 13px; border-radius: 14px;
    color: var(--text); text-decoration: none; font-size: 14px; font-weight: 650;
    transition: color var(--dur-hover) ease, background-color var(--dur-hover) ease,
      transform var(--dur-press) var(--ease-out);
  }
  .mobile-menu a:hover { color: var(--r700); background: var(--soft); }
  .mobile-menu a:active { transform: scale(0.98); transition-duration: 100ms; }
  /* `.mobile-menu a` outspecifies `.button-primary`, which rendered the CTA
     muted-on-maroon. */
  .mobile-menu a.button-primary { color: #fff; justify-content: center; margin-top: 5px; }

  .entry-card { position: static; width: 100%; margin-top: -34px; }
  .hero-figure { max-width: none; }
  .footer-top { grid-template-columns: repeat(2, 1fr); gap: 32px 20px; }
  .footer-brand { grid-column: 1 / -1; }
  .footer-bottom { align-items: flex-start; flex-direction: column; }
}

@media (max-width: 520px) {
  .hero-actions { display: grid; }
  .hero-actions .button { width: 100%; }
  .day-tile { width: 48px; }
}

/* =============================================================================
   Phone
   -----------------------------------------------------------------------------
   Nearly all of this page's traffic arrives on a handset, so the phone layout
   is the one that has to be right and the desktop grid is the variation. What
   follows is the work that couldn't be expressed by narrowing the desktop
   design: a modal menu, a travelling call to action, a product preview at a
   size a thumb's-length away can actually read, and safe areas.
   ========================================================================== */

/* --- Menu as a modal ------------------------------------------------------ */
.menu-scrim {
  position: fixed;
  inset: 0;
  z-index: 98;
  background: rgba(28, 10, 18, 0.42);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-menu) ease;
}
body.menu-open .menu-scrim { opacity: 1; pointer-events: auto; }

/* Fixed rather than `overflow: hidden`, which iOS Safari ignores on <body>.
   The scroll offset is put back by JS on close. */
body.menu-open {
  position: fixed;
  inset-inline: 0;
  width: 100%;
  overflow: hidden;
}

/* --- Travelling call to action -------------------------------------------- */
.mobile-cta { display: none; }

@media (max-width: 760px) {
  .mobile-cta {
    position: fixed;
    z-index: 97;
    inset: auto 10px calc(10px + env(safe-area-inset-bottom));
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 9px 9px 9px 18px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--nav);
    box-shadow: var(--shadow-lg);
    backdrop-filter: blur(20px) saturate(150%);
    -webkit-backdrop-filter: blur(20px) saturate(150%);
    /* Parked below the fold rather than at opacity 0, so it never intercepts a
       tap while invisible. */
    opacity: 0;
    translate: 0 calc(100% + 20px);
    pointer-events: none;
    transition: opacity var(--dur-menu) ease, translate 320ms var(--ease-out);
  }
  .mobile-cta.is-visible { opacity: 1; translate: 0 0; pointer-events: auto; }
  /* One thing on screen at a time: the sheet is the modal, the bar can wait. */
  body.menu-open .mobile-cta { opacity: 0; translate: 0 calc(100% + 20px); pointer-events: none; }

  .mobile-cta-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
  .mobile-cta-text strong { font-size: 13.5px; font-weight: 750; letter-spacing: -0.015em; }
  .mobile-cta-text small { color: var(--muted); font-size: 11.5px; font-weight: 600; }
  .mobile-cta .button { flex: none; }

  /* Room for the bar at the very bottom of the page, so it never rests on the
     last line of the footer. */
  .site-footer { padding-bottom: calc(40px + env(safe-area-inset-bottom) + 62px); }
}

/* --- The product preview, at hand-held size ------------------------------- */
/* Every size in the preview was drawn for a 264px-wide mock inside a bezel on a
   desktop screen — which on an actual phone rendered a phone inside a phone,
   with 8px labels. Here the bezel thins out, the screen takes the full column,
   and the interface is redrawn at a size you'd accept in a real app. */
@media (max-width: 760px) {
  .demo-grid { gap: 24px; margin-top: 26px; }

  /* A stacked list of three descriptions above the screen read as more copy.
     As a segmented rail it reads as a control, and the panel it switches to is
     immediately below it. */
  .demo-tabs {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
    /* Snapping aligns to the scrollport edge, not the padding edge, so without
       this the rail settles with the first chip flush against the screen. */
    scroll-padding-inline: calc(var(--gutter) / 2);
    -webkit-overflow-scrolling: touch;
    /* Break the gutter so the first and last chip can sit against the edge. */
    margin-inline: calc(var(--gutter) / -2);
    padding-inline: calc(var(--gutter) / 2);
    /* Fade the trailing edge so a clipped chip reads as "there's more" rather
       than as a chip that got cut off. Same device as the blog's topic rail. */
    mask-image: linear-gradient(90deg, #000 86%, transparent);
    -webkit-mask-image: linear-gradient(90deg, #000 86%, transparent);
  }
  .demo-tabs::-webkit-scrollbar { display: none; }

  .demo-tab {
    flex: none;
    grid-template-columns: 32px auto;
    gap: 10px;
    padding: 8px 16px 8px 8px;
    border-color: var(--border);
    background: var(--card-solid);
    scroll-snap-align: start;
  }
  .demo-tab-icon { width: 32px; height: 32px; border-radius: 10px; }
  .demo-tab-icon svg { width: 17px; height: 17px; }
  .demo-tab small,
  .demo-tab-arrow { display: none; }
  .demo-tab strong { margin: 0; font-size: 13.5px; white-space: nowrap; }
  .demo-tab.active { border-color: color-mix(in srgb, var(--r700) 45%, var(--border)); }

  .demo-stage {
    min-height: 0;
    padding: 0;
    border: 0;
    background: none;
  }
  .demo-phone {
    width: 100%;
    max-width: 420px;
    padding: 5px;
    border-radius: 34px;
  }
  /* Sized to the tallest of the three panels — they are absolutely positioned,
     so the screen can't measure them itself. */
  .demo-phone-screen { height: 664px; border-radius: 30px; }
  .demo-view { padding: 34px 18px 18px; }

  .phone-status { font-size: 12px; padding-inline: 8px; }
  .demo-phone-title { margin: 22px 0 18px; }
  .demo-phone-title small { font-size: 12px; }
  .demo-phone-title h3 { font-size: 26px; }

  .routine-list-card { margin-top: 10px; padding: 14px; border-radius: 18px; }
  .routine-icon { width: 42px; height: 42px; flex-basis: 42px; border-radius: 13px; font-size: 17px; }
  .routine-list-top { gap: 12px; }
  .routine-list-top strong { font-size: 14px; }
  .routine-list-top small { font-size: 11.5px; }
  .check { width: 24px; height: 24px; font-size: 12px; }
  .schedule-pill { padding: 6px 11px; font-size: 10.5px; }

  .section-line { margin: 24px 3px 11px; font-size: 13px; }
  .section-line span:last-child { font-size: 11.5px; }
  .week-row { gap: 5px; margin-top: 15px; }
  .day { padding: 11px 3px; border-radius: 11px; font-size: 10px; }

  .camera-preview { height: 340px; border-radius: 24px; }
  .camera-tip { font-size: 11px; padding: 12px; border-radius: 14px; }
  .capture-button { width: 62px; height: 62px; margin-top: 24px; }
  .capture-button::after { width: 18px; height: 18px; }
  .capture-note { font-size: 11px; margin-top: 16px; }

  .report-hero { padding: 18px; border-radius: 22px; }
  .report-caption { font-size: 11.5px; }
  .report-score strong { font-size: 44px; }
  .report-score span { font-size: 12px; }

  .insight-row { margin-top: 10px; padding: 13px; border-radius: 16px; gap: 12px; }
  .insight-dot { width: 40px; height: 40px; flex-basis: 40px; border-radius: 13px; font-size: 17px; }
  .insight-row strong { font-size: 13px; }
  .insight-row small { font-size: 11px; }
  .insight-value { font-size: 11.5px; }
  .scan-cta { min-height: 50px; margin-top: 16px; border-radius: 15px; font-size: 13.5px; }
}

/* --- Phone housekeeping --------------------------------------------------- */
@media (max-width: 760px) {
  /* Two 70px blurs over most of the viewport is a real cost on a phone GPU,
     and at this size the blooms only need to be soft, not vast. */
  .hero::before, .hero::after { filter: blur(44px); }
  .hero::before { width: 72vw; }
  .hero::after { width: 64vw; }

  .feature-card { padding: 20px; }
  .feature-media { margin: 18px -20px -20px; }
  .plan { padding: 26px 22px; }

  /* Card copy is set small so six cards fit a desktop grid. Stacked one per
     row on a phone there is no such constraint, and 13.5px held at arm's
     length is where people start pinch-zooming. */
  .feature-card p { font-size: 15px; }
  .problem-card p { font-size: 14.5px; }

  /* Full width, because a centred auto-width button beside a full-width field
     reads as an afterthought. */
  .waitlist-form input[type="email"],
  .waitlist-form button { flex: 1 1 100%; }

  /* 19px tap targets sitting inside a paragraph. */
  .waitlist-note a, .cta-subnote a, .privacy-link { display: inline-block; padding-block: 10px; }
}

@media (max-width: 560px) {
  /* Three stats wrapped 2 + 1, which made the third read as a leftover. */
  .hero-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
  }
  .hero-stats dt { font-size: 21px; }
  .hero-stats dd { font-size: 11.5px; line-height: 1.35; }

  .hero-lead { margin-top: 20px; }
  .hero-note { margin-top: 22px; }
  .streak-caption { font-size: 14px; }
}

/* --- Reduced motion ------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .reveal, .hero-intro > *, .hero-figure {
    opacity: 1;
    animation: none !important;
  }
  /* The ribbon is the page's signature, but it's also the only thing here that
     never stops. Parked, it still reads as a run of days. */
  .streak-track { animation: none !important; }
  /* Nested inside .reveal, so these need naming directly — the rule above only
     reaches the container. Both entries and the span stay put and visible. */
  .compare-entry, .compare-gap, .problem-card, .hero-tags li {
    opacity: 1;
    translate: none;
    scale: none;
    animation: none !important;
  }
}
