@import url('tokens.css');
@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600;9..144,900&family=Inter:wght@400;500;600;700&display=swap');

/* ── Reset ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
h1, h2, h3, p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

@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; }
}

.wrap {
  max-width: 1180px;
  margin-inline: auto;
  padding-inline: var(--space-4);
}

.serif { font-family: var(--font-serif); }

.eyebrow {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--text-xs);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

/* ── Buttons — same tactile mechanic as the app's NeoButton: a hard, ────────
   hue-tinted offset shadow that shrinks on press ────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--text-base);
  padding: 0.9rem 1.6rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  cursor: pointer;
  transform: translate(0, 0);
  transition: transform var(--duration-fast) var(--ease-out-expo), box-shadow var(--duration-fast) var(--ease-out-expo);
}
.btn:active { transform: translate(4px, 4px); }
.btn:disabled { opacity: 0.5; cursor: default; }
.btn:disabled:active { transform: translate(0, 0); }

.btn-primary {
  background: var(--color-primary);
  color: var(--color-primary-text);
  box-shadow: 4px 4px 0 var(--color-primary-shadow);
}
.btn-primary:active { box-shadow: 0 0 0 var(--color-primary-shadow); }

.btn-ghost {
  background: var(--color-surface);
  color: var(--color-ink);
  border: 1px solid var(--color-hairline-strong);
  box-shadow: 3px 3px 0 rgba(45, 43, 38, 0.14);
}
.btn-ghost:active { box-shadow: 0 0 0 rgba(45, 43, 38, 0.14); }

/* ── Nav ───────────────────────────────────────────────────────────────── */
.nav {
  position: sticky;
  top: 0;
  z-index: 40;
  /* Solid, not translucent: the scenario section's large serif headlines
     scroll directly underneath this bar, and a blurred/semi-transparent
     background left them legible right through it, overlapping the
     wordmark and nav links mid-scroll. */
  background: var(--color-bg);
  border-bottom: 1px solid var(--color-hairline);
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: var(--space-3);
}
.wordmark {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 1.5rem;
  color: var(--color-ink);
}
.nav-links {
  display: none;
  gap: var(--space-5);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-ink-muted);
}
@media (min-width: 760px) {
  .nav-links { display: flex; }
}
.nav-links a { transition: color var(--duration-fast); }
.nav-links a:hover { color: var(--color-ink); }
.nav-cta { display: none; }
@media (min-width: 540px) {
  .nav-cta { display: inline-flex; padding: 0.6rem 1.2rem; font-size: var(--text-sm); }
}

/* ── Hero ──────────────────────────────────────────────────────────────── */
.hero {
  padding-block: var(--space-8) var(--space-6);
  position: relative;
}
.hero-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: center;
}
@media (min-width: 900px) {
  .hero-grid { grid-template-columns: 1.05fr 0.95fr; gap: var(--space-5); }
}

.hero-copy .eyebrow { margin-bottom: var(--space-3); display: flex; align-items: center; gap: var(--space-2); }
.hero-copy .eyebrow::before {
  content: '';
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--color-good);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--color-good) 25%, transparent);
}

.hero-title {
  font-size: var(--text-hero);
  line-height: 0.98;
  letter-spacing: -0.01em;
  color: var(--color-ink);
  max-width: 13ch;
}
.hero-title em {
  font-style: italic;
  color: var(--color-primary);
}

.hero-sub {
  margin-top: var(--space-4);
  font-size: var(--text-md);
  color: var(--color-ink-muted);
  max-width: 38ch;
  line-height: 1.6;
}

.hero-actions {
  margin-top: var(--space-5);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.hero-note {
  margin-top: var(--space-4);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
}

/* ── Hero entrance — tactile spring choreography (hero.js) ────────────────
   .js is set synchronously in <head>, before first paint. Without it (JS
   disabled, or hero.js failing to load) these elements simply never enter
   this state: they're just themselves, fully visible, same as always.
   hero.js is what opts them into a pre-entrance state and springs them out
   of it — there's no CSS transition here because the spring writes opacity
   and transform directly, every frame. */
.js .hero-enter {
  opacity: 0;
  transform: translateY(16px) scale(0.98);
}
@media (prefers-reduced-motion: reduce) {
  .js .hero-enter { opacity: 1; transform: none; }
  /* The phone's 4deg tilt is a static design choice, not motion — reduced
     motion should skip the spring, not straighten the phone. */
  .js .phone.hero-enter { transform: rotate(4deg); }
}

/* ── Phone mockup — a faithful, live-CSS recreation of the app's real Home
   screen, not stock imagery or a fabricated UI. Tilted for asymmetry. On a
   fine pointer, hero.js takes over this tilt entirely, springing it toward
   the cursor as if you'd reached out and picked it up; the hover rule below
   is what mobile/coarse-pointer/no-JS visitors get instead. ───────────── */
.phone-stage {
  display: flex;
  justify-content: center;
  perspective: 1400px;
}
.phone {
  width: min(300px, 78vw);
  background: var(--color-bg);
  border-radius: 40px;
  box-shadow: var(--shadow-hero), 0 0 0 10px var(--color-ink);
  overflow: hidden;
  transform: rotate(4deg);
  transition: transform var(--duration-slow) var(--ease-out-expo);
}
.phone-stage:hover .phone { transform: rotate(1deg) translateY(-4px); }

.phone-notch {
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.phone-notch::before {
  content: '';
  width: 90px; height: 18px;
  background: var(--color-ink);
  border-radius: var(--radius-pill);
}

.phone-screen { padding: var(--space-1) var(--space-3) var(--space-4); }

.phone-masthead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding-block: 6px 10px;
}
.phone-masthead .serif { font-size: 1.15rem; }
.phone-avatar {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--color-vivid);
  color: var(--color-vivid-text);
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700;
  box-shadow: 0 2px 0 var(--color-vivid-shadow);
}

.phone-headline {
  font-size: 1.2rem;
  line-height: 1.12;
  margin-top: 2px;
}
.phone-subtext {
  font-size: 0.6rem;
  color: var(--color-ink-muted);
  margin-top: 4px;
}

.phone-triage {
  margin-top: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-hairline);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-2) var(--space-1);
  display: flex;
}
.phone-col { flex: 1; text-align: center; padding-inline: 4px; }
.phone-col-label {
  font-size: 0.5rem;
  font-weight: 600;
  color: var(--color-ink-muted);
  display: flex; align-items: center; justify-content: center; gap: 3px;
  margin-bottom: 6px;
}
.phone-dot { width: 4px; height: 4px; border-radius: 50%; display: inline-block; }
.phone-col-value {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 0.95rem;
}
.phone-col-sub { font-size: 0.45rem; color: var(--color-ink-muted); margin-top: 2px; }

.phone-rail {
  margin-top: var(--space-3);
  display: flex;
  gap: 6px;
}
.phone-rail-btn {
  flex: 1;
  height: 30px;
  border-radius: var(--radius-pill);
  display: flex; align-items: center; justify-content: center;
  font-size: 0.55rem; font-weight: 600;
}
.phone-rail-btn.is-primary {
  background: var(--color-primary);
  color: var(--color-primary-text);
  box-shadow: 0 2px 0 var(--color-primary-shadow);
  flex: 1.4;
}
.phone-rail-btn.is-ghost {
  background: var(--color-surface);
  border: 1px solid var(--color-hairline-strong);
  color: var(--color-ink);
}

/* ── Voice marquee ─────────────────────────────────────────────────────── */
.voice {
  padding-block: var(--space-5);
  border-block: 1px solid var(--color-hairline);
  background: var(--color-surface);
  /* .marquee is deliberately wider than the viewport (width: max-content,
     for the infinite-scroll ticker) — contain it here too, right at the
     source, in addition to the html/body backstop below. */
  overflow-x: hidden;
}
.marquee {
  display: flex;
  width: max-content;
  animation: scroll-left 34s linear infinite;
}
.voice:hover .marquee { animation-play-state: paused; }
.marquee-track { display: flex; gap: var(--space-6); padding-right: var(--space-6); }
.marquee-item {
  font-family: var(--font-serif);
  font-size: var(--text-lg);
  color: var(--color-ink-muted);
  white-space: nowrap;
}
.marquee-item b { color: var(--color-ink); font-weight: 600; }

@keyframes scroll-left {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ── Features intro — heading + tag used above the scenario steps ────────── */
.features-head { max-width: 42ch; margin-bottom: var(--space-6); }
.features-head h2 { font-size: var(--text-display); line-height: 1.02; }
.features-head p { margin-top: var(--space-3); color: var(--color-ink-muted); font-size: var(--text-md); max-width: 40ch; }

.feature-tag {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-primary);
}

/* ── Final CTA ─────────────────────────────────────────────────────────── */
.cta {
  padding-block: var(--space-8);
}
.cta-panel {
  background: var(--color-ink);
  color: var(--color-bg);
  border-radius: var(--radius-xl);
  padding: var(--space-6) var(--space-5);
  display: grid;
  gap: var(--space-5);
  position: relative;
  overflow: hidden;
}
@media (min-width: 860px) {
  .cta-panel { grid-template-columns: 1.2fr 1fr; align-items: center; padding-inline: var(--space-8); }
}
.cta-panel h2 {
  font-family: var(--font-serif);
  font-size: var(--text-display);
  line-height: 1.03;
  max-width: 14ch;
}
.cta-panel .hero-sub { color: color-mix(in oklab, var(--color-bg) 70%, transparent); }

.cta-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.cta-form-row {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}
.cta-input {
  flex: 1;
  min-width: 200px;
  background: var(--color-bg);
  color: var(--color-ink);
  border: none;
  border-radius: var(--radius-pill);
  padding: 0.9rem 1.3rem;
  font-family: var(--font-sans);
  font-size: var(--text-base);
}
.cta-input::placeholder { color: var(--color-ink-faint); }
.cta-form-note {
  font-size: var(--text-xs);
  color: color-mix(in oklab, var(--color-bg) 55%, transparent);
}
.cta-success {
  display: none;
  align-items: center;
  gap: var(--space-2);
  font-weight: 600;
  color: var(--color-good);
}
.cta-success.is-visible { display: flex; }

/* ── Footer ────────────────────────────────────────────────────────────── */
.site-footer {
  padding-block: var(--space-5);
  border-top: 1px solid var(--color-hairline);
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* ── Scenario scroller ─────────────────────────────────────────────────────
   Base state (below) is a plain stacked article: every step's copy
   immediately followed by its own screenshot, and is what renders with no
   JS, reduced motion, narrower than 860px, or if the GSAP CDN import fails.
   scenarios.js upgrades this progressively past 860px: it moves each
   .scenario-step-visual into the shared .scenario-stage and pins
   .scenario-stage-wrap for the scroll duration via GSAP ScrollTrigger's
   real pin mechanism (not a hand-rolled position:sticky), one trigger per
   step for the content swap. Position while pinned is managed entirely by
   ScrollTrigger's inline styles; nothing here sets position on the wrap. ── */
.scenario-track { display: flex; flex-direction: column; }

.scenario-step {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: start;
  padding-block: var(--space-6);
  border-bottom: 1px solid var(--color-hairline);
}
.scenario-step:last-child { border-bottom: none; }
@media (min-width: 860px) {
  .scenario-step { grid-template-columns: 0.95fr 1.05fr; gap: var(--space-8); }
}

.scenario-step-copy h3 { font-size: var(--text-display); line-height: 1.05; margin-top: var(--space-2); max-width: 14ch; }
.scenario-step-copy p:not(.feature-tag) { margin-top: var(--space-4); color: var(--color-ink-muted); font-size: var(--text-md); max-width: 42ch; line-height: 1.6; }

.scenario-stage { display: none; }
.scenario-stage-wrap { display: none; }

/* ── Scrolly upgrade (JS-added) ───────────────────────────────────────────
   Only ever applied past the 860px breakpoint (scenarios.js gates it the
   same way), so no separate mobile override is needed. ─────────────────── */
.scenario-scroller.is-scrolly {
  display: grid;
  grid-template-columns: 0.95fr 1.05fr;
  gap: var(--space-8);
  align-items: start;
}
.scenario-scroller.is-scrolly .scenario-step {
  display: flex;
  align-items: center;
  min-height: 82vh;
  padding-block: 0;
  border-bottom: none;
}
.scenario-scroller.is-scrolly .scenario-stage-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  position: relative;
  /* The glow below bleeds ~10% of this box's own width past each side —
     harmless most places, but at some viewport widths that's enough to
     push the page into real horizontal overflow, not just a visual bleed.
     Clipping here contains it to a still-generous glow without that risk. */
  overflow: hidden;
  padding-block: var(--space-4);
}
/* A soft, warm glow behind the pinned stage: the "Committed" color strategy
   for this surface specifically, the rest of the site stays Restrained. */
.scenario-scroller.is-scrolly .scenario-stage-wrap::before {
  content: '';
  position: absolute;
  inset: -15% -10%;
  background: radial-gradient(circle at 50% 45%, color-mix(in oklab, var(--color-vivid) 14%, transparent), transparent 70%);
  z-index: -1;
  pointer-events: none;
}
.scenario-scroller.is-scrolly .scenario-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 640px;
  width: 100%;
}
/* #scenario-stage (id), not .scenario-stage (class): the scan step's
   visual also matches .scenario-step-visual:has([data-screenshot]) further
   below, which sets position:relative at equal (0,2,0) class specificity,
   a tie that source order would resolve the wrong way. The id selector
   below outranks that regardless of order. */
#scenario-stage > .scenario-step-visual {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
}
#scenario-stage > .scenario-step-visual.is-active {
  position: relative;
  opacity: 1;
  pointer-events: auto;
}

/* ── Progress dots ─────────────────────────────────────────────────────────
   Orientation cue for the pinned stage: without one, a section that stops
   scrolling normally reads as "is this stuck?" rather than "this is
   deliberate." Purely a JS-driven indicator, hidden until upgraded. ────── */
.scenario-progress { display: none; }
.scenario-scroller.is-scrolly .scenario-progress {
  display: flex;
  gap: var(--space-2);
}
.scenario-progress-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-hairline-strong);
  transition: background var(--duration-base) var(--ease-out-expo), transform var(--duration-base) var(--ease-out-expo);
}
.scenario-progress-dot.is-active {
  background: var(--color-primary);
  transform: scale(1.4);
}

.scenario-toggle {
  margin-top: var(--space-5);
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  background: var(--color-surface-sunken);
  border-radius: var(--radius-pill);
}
.scenario-toggle-btn {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius-pill);
  transition: background var(--duration-fast), color var(--duration-fast);
}
.scenario-toggle-btn.is-active { background: var(--color-surface); color: var(--color-ink); box-shadow: var(--shadow-raised); }

.scenario-step-visual { display: flex; justify-content: center; }

/* Portrait phone-shaped screenshots — same bezel language as the hero .phone,
   so a real capture and the hand-CSS mockup read as the same object. */
.scenario-screenshot {
  position: relative;
  width: min(300px, 78vw);
  aspect-ratio: 390 / 844;
  border-radius: 36px;
  overflow: hidden;
  box-shadow: var(--shadow-hero), 0 0 0 10px var(--color-ink);
  transition: opacity var(--duration-base) var(--ease-out-expo);
}
.scenario-screenshot img { width: 100%; height: 100%; object-fit: cover; }

/* Toggle pair (scan step): stack in the same box, cross-fade between them */
.scenario-step-visual:has([data-screenshot]) { position: relative; }
[data-screenshot] { position: absolute; inset: 0; opacity: 0; pointer-events: none; }
[data-screenshot].is-active { position: relative; opacity: 1; pointer-events: auto; }

.scenario-screenshot-small { width: min(220px, 60vw); }

/* Caption sits below the bezel, never over the real screenshot content —
   the bezel's own overflow:hidden would clip an overlaid label anyway. */
.scenario-screenshot-figure { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.scenario-screenshot-label {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  white-space: nowrap;
}

.scenario-step-visual-audit {
  flex-direction: column;
  gap: var(--space-6);
  align-items: center;
}
@media (min-width: 640px) {
  .scenario-step-visual-audit { flex-direction: row; align-items: flex-end; justify-content: center; }
}

.scenario-step-visual-empty { width: 100%; }
.scenario-screenshot-wide {
  width: 100%;
  max-width: 460px;
  aspect-ratio: 1050 / 297;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  margin-inline: auto;
}
.scenario-screenshot-wide img { width: 100%; height: 100%; object-fit: cover; }

/* ── Audit card stack — an honest, disclosed interactive recreation, not a
   screenshot (see HTML comment). Same tokens and shadow language as the
   rest of the site; driven by --drag-x from scenarios.js. ─────────────── */
.audit-stack {
  position: relative;
  width: min(240px, 68vw);
  height: 150px;
}
.audit-card {
  position: absolute;
  inset: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  cursor: grab;
  touch-action: pan-y;
  --drag-x: 0;
  --stack-offset: 0;
  transform:
    translateX(calc(var(--drag-x, 0) * 1px))
    translateY(calc(var(--stack-offset, 0) * 10px))
    scale(calc(1 - var(--stack-offset, 0) * 0.05))
    rotate(calc(var(--drag-x, 0) * 0.04deg));
  transition: transform var(--duration-base) var(--ease-out-expo);
}
.audit-card:active { cursor: grabbing; }
.audit-card.is-dragging { transition: none; }
.audit-card.is-leaving { transition: transform var(--duration-base) var(--ease-out-expo), opacity var(--duration-base); opacity: 0; }
.audit-card[data-expiry="urgent"] { border-color: color-mix(in oklab, var(--color-urgent) 40%, var(--color-hairline)); }

.audit-card-row { display: flex; align-items: center; gap: var(--space-2); }
.audit-card-name { font-family: var(--font-serif); font-size: var(--text-lg); font-weight: 600; }
.audit-card-when {
  align-self: flex-start;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  background: var(--color-surface-sunken);
  padding: 0.35rem 0.7rem;
  border-radius: var(--radius-pill);
}
.audit-card-when.is-urgent {
  color: var(--color-urgent-text);
  background: var(--color-urgent);
}

/* ── Scroll-reveal ─────────────────────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--duration-slow) var(--ease-out-expo), transform var(--duration-slow) var(--ease-out-expo);
}
.reveal.is-visible { opacity: 1; transform: none; }
