/* ============================================================================
   Karmanya — site styles
   ----------------------------------------------------------------------------
   Colours are lifted from the app's own theme (ui/theme/Color.kt) rather than
   re-invented, so the site and the product read as one thing: Indigo for the
   quiet work, Saffron for warmth, Karma Green for the contribution grid, on the
   same near-black ground the app was designed for.

   Motion is deliberately restrained and always opt-out: every animation here is
   disabled under prefers-reduced-motion, and nothing animates that the reader
   needs in order to use the page.
   ========================================================================= */

:root {
  /* Brand — from the app */
  --indigo-90: #e1d8ff;
  --indigo-80: #c3b4ff;
  --indigo-60: #8e7bef;
  --indigo-50: #6c5ad6;
  --indigo-40: #4a3fa8;
  --indigo-20: #221c5c;
  --saffron: #f5a524;
  --karma-green: #4ade80;

  /* Ground — the app's window background */
  --ink-900: #060509;
  --ink-850: #0b0912;
  --ink-800: #12101d;
  --ink-700: #1c1930;
  --ink-600: #2a2545;

  --text: #f2f0f7;
  --text-dim: #a9a4bd;
  /* Lightened from #6f6a87, which sat at ~4.3:1 on the ink ground -- fine for large
     text but failing WCAG AA for the small text it is actually used on (footer
     meta, captions, the "Coming to Google Play" line). This is ~5.9:1. */
  --text-faint: #8d88a6;

  --radius: 18px;
  --radius-lg: 28px;
  --maxw: 1120px;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  /* Fraunces for display (a variable serif with real optical sizing, which is
     what gives the headline its weight) and Inter Tight for everything else.
     Both are vendored — see tools/fonts.mjs. The fallbacks after them are not
     decoration: they are what renders during the swap, and on a page whose
     headline is 68px that moment is visible. */
  --font-serif: "Fraunces", "FrauncesLocal", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --font-sans: "Inter Tight", "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* Aliases, so motion.css and premium.css can keep naming them by role. */
  --font-display: var(--font-serif);
  --font-ui: var(--font-sans);

  color-scheme: dark;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink-900);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* height:auto is load-bearing, not decoration. The <img> width/height attributes (kept for
   layout stability) map to presentational hints, so max-width alone constrains the width
   while the literal height sticks -- the phone screenshots rendered 171x2340, a stretched
   near-black column that read as an empty page. */
img { max-width: 100%; height: auto; display: block; }
/* Browsers give <figure> a 40px side margin by default, which was silently eating 80px
   out of every screenshot grid column (a 253px column rendered a 173px image). */
figure { margin: 0; }
a { color: var(--indigo-80); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--indigo-90); }

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }
.narrow { max-width: 760px; }

/* ---------------------------------------------------------------- ambient mesh
   A slow, hand-built gradient mesh instead of a static image: three blurred
   radial blobs drifting on long, offset cycles. Cheap (no JS, no bitmap) and it
   gives the page the same "glow on near-black" feel as the app's cards. */
.mesh {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.mesh span {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.5;
  will-change: transform;
}
.mesh .b1 {
  width: 46vw; height: 46vw; left: -8vw; top: -10vw;
  background: radial-gradient(circle at 30% 30%, var(--indigo-50), transparent 70%);
  animation: drift1 32s var(--ease-out) infinite alternate;
}
.mesh .b2 {
  width: 38vw; height: 38vw; right: -6vw; top: 12vh;
  background: radial-gradient(circle at 60% 40%, #7b3fa8, transparent 70%);
  animation: drift2 41s var(--ease-out) infinite alternate;
}
.mesh .b3 {
  width: 34vw; height: 34vw; left: 34vw; bottom: -14vw;
  background: radial-gradient(circle at 50% 50%, var(--saffron), transparent 72%);
  opacity: 0.22;
  animation: drift3 37s var(--ease-out) infinite alternate;
}
@keyframes drift1 { to { transform: translate3d(7vw, 6vh, 0) scale(1.15); } }
@keyframes drift2 { to { transform: translate3d(-8vw, 10vh, 0) scale(1.1); } }
@keyframes drift3 { to { transform: translate3d(4vw, -8vh, 0) scale(1.2); } }

/* A faint grain layer, so the large flat areas don't band on cheap panels. */
.grain {
  position: fixed; inset: 0; z-index: -1; pointer-events: none; opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------------------------------------------------------------- nav */
.nav {
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: blur(14px);
  background: color-mix(in oklab, var(--ink-900) 78%, transparent);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.nav .wrap { display: flex; align-items: center; gap: 18px; height: 64px; }
.brand { display: flex; align-items: center; gap: 10px; font-weight: 650; letter-spacing: -0.01em; text-decoration: none; color: var(--text); }
.brand .lamp { font-size: 20px; filter: drop-shadow(0 0 10px rgba(245, 165, 36, 0.55)); }
.nav nav { margin-left: auto; display: flex; gap: 22px; align-items: center; }
.nav nav a { color: var(--text-dim); text-decoration: none; font-size: 15px; }
.nav nav a:hover { color: var(--text); }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 13px 22px; border-radius: 999px;
  font-weight: 600; font-size: 15px; text-decoration: none;
  border: 1px solid transparent; cursor: pointer;
  transition: transform 0.18s var(--ease-out), box-shadow 0.18s var(--ease-out), background 0.18s;
}
.btn-primary {
  color: #fff;
  background: linear-gradient(135deg, var(--indigo-50), var(--indigo-40));
  box-shadow: 0 8px 30px -10px rgba(108, 90, 214, 0.85);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 40px -12px rgba(108, 90, 214, 0.95); color: #fff; }
.btn-ghost { color: var(--text); background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.12); }
.btn-ghost:hover { background: rgba(255, 255, 255, 0.09); transform: translateY(-2px); color: var(--text); }
.btn:focus-visible { outline: 2px solid var(--indigo-80); outline-offset: 3px; }

/* ---------------------------------------------------------------- hero */
.hero { padding: clamp(64px, 11vw, 132px) 0 72px; text-align: center; }
.lamp-xl {
  font-size: clamp(52px, 9vw, 84px); line-height: 1;
  filter: drop-shadow(0 0 42px rgba(245, 165, 36, 0.42));
  animation: flicker 6s ease-in-out infinite;
}
@keyframes flicker {
  0%, 100% { filter: drop-shadow(0 0 42px rgba(245, 165, 36, 0.42)); }
  50%      { filter: drop-shadow(0 0 58px rgba(245, 165, 36, 0.62)); }
}
/* If the reader already has Fraunces installed, use it and skip the download
   entirely. Costs one rule and saves 66 KB for the people it applies to. */
@font-face { font-family: "FrauncesLocal"; src: local("Fraunces"); font-display: swap; }

body { letter-spacing: -0.005em; }
h3, .brand { font-family: var(--font-serif); }
/* Fraunces' own axes. SOFT rounds the terminals slightly and WONK enables the
   canted forms, which is what stops a large serif reading as stock Georgia. */
h1, h2 { font-optical-sizing: auto; font-variation-settings: "SOFT" 20, "WONK" 1; }

.verse {
  font-family: var(--font-serif); font-style: italic;
  color: var(--indigo-80); font-size: clamp(17px, 2.2vw, 21px);
  margin: 22px auto 6px; max-width: 26ch;
}
h1 {
  font-family: var(--font-serif);
  font-size: clamp(38px, 6.6vw, 68px); line-height: 1.06;
  letter-spacing: -0.025em; margin: 14px auto 18px; max-width: 20ch;
  font-weight: 600;
}
h1 .grad {
  background: linear-gradient(100deg, var(--indigo-80), var(--saffron) 70%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.lede { color: var(--text-dim); font-size: clamp(17px, 2.1vw, 20px); max-width: 56ch; margin: 0 auto 32px; }
.cta-row { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/* The promise strip — the thing that differentiates the product. */
.promises {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
  margin-top: 38px;
}
.promise {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13.5px; font-weight: 600; letter-spacing: 0.02em;
  padding: 9px 16px; border-radius: 999px;
  color: var(--karma-green);
  background: rgba(74, 222, 128, 0.08);
  border: 1px solid rgba(74, 222, 128, 0.22);
}
.promise svg { width: 14px; height: 14px; flex: none; }

/* ---------------------------------------------------------------- sections */
section { padding: clamp(56px, 8vw, 104px) 0; }
.eyebrow {
  text-transform: uppercase; letter-spacing: 0.16em; font-size: 12px;
  font-weight: 700; color: var(--indigo-60); margin-bottom: 14px;
}
h2 {
  font-family: var(--font-serif); font-weight: 600;
  font-size: clamp(28px, 4.2vw, 42px); line-height: 1.15;
  letter-spacing: -0.02em; margin: 0 0 16px; max-width: 24ch;
}
h3 { font-size: 19px; margin: 0 0 8px; letter-spacing: -0.01em; }
.section-lede { color: var(--text-dim); max-width: 62ch; margin: 0 0 44px; }
.center { text-align: center; }
.center h2, .center .section-lede { margin-left: auto; margin-right: auto; }

/* ---------------------------------------------------------------- cards */
.grid { display: grid; gap: 18px; }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

.card {
  position: relative; overflow: hidden;
  padding: 26px;
  border-radius: var(--radius);
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.018));
  border: 1px solid rgba(255, 255, 255, 0.08);
  transition: transform 0.28s var(--ease-out), border-color 0.28s, box-shadow 0.28s;
}
.card::after {
  /* A soft aura, mirroring habitCardAura() in the app. */
  content: ""; position: absolute; inset: -40% 40% 55% -20%;
  background: radial-gradient(circle, rgba(142, 123, 239, 0.14), transparent 70%);
  pointer-events: none;
}
.card:hover { transform: translateY(-4px); border-color: rgba(142, 123, 239, 0.34); box-shadow: 0 20px 50px -28px rgba(0, 0, 0, 0.9); }
.card p { color: var(--text-dim); margin: 0; font-size: 15.5px; }
.card .ico { font-size: 24px; margin-bottom: 14px; display: block; }

/* ---------------------------------------------------------------- shots */
.shots { display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.shot {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: var(--ink-850);
  box-shadow: 0 30px 70px -40px rgba(0, 0, 0, 1);
  transition: transform 0.3s var(--ease-out);
}
.shot:hover { transform: translateY(-6px) scale(1.015); }
.shot figcaption { padding: 12px 16px 15px; font-size: 13.5px; color: var(--text-faint); border-top: 1px solid rgba(255,255,255,0.06); }

/* ---------------------------------------------------------------- compare */
.compare { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.col {
  padding: 26px; border-radius: var(--radius);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.col.bad { background: rgba(239, 68, 68, 0.045); border-color: rgba(239, 68, 68, 0.2); }
.col.good { background: rgba(74, 222, 128, 0.05); border-color: rgba(74, 222, 128, 0.24); }
.col h3 { font-size: 15px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-faint); }
.col.good h3 { color: var(--karma-green); }
.col ul { list-style: none; padding: 0; margin: 14px 0 0; }
.col li { display: flex; gap: 11px; align-items: flex-start; padding: 7px 0; color: var(--text-dim); font-size: 15.5px; }
.col li b { color: var(--text); font-weight: 600; }
.mark { flex: none; margin-top: 4px; width: 15px; height: 15px; }

/* ---------------------------------------------------------------- prose (legal) */
.prose { max-width: 760px; }
.prose h1 { font-size: clamp(32px, 5vw, 46px); text-align: left; margin-left: 0; max-width: none; }
.prose h2 { font-size: 24px; margin-top: 44px; }
.prose h3 { font-size: 18px; margin-top: 28px; color: var(--indigo-80); }
.prose p, .prose li { color: var(--text-dim); }
.prose strong { color: var(--text); }
.prose ul { padding-left: 22px; }
.prose li { margin: 7px 0; }
.prose code {
  background: var(--ink-700); padding: 2px 6px; border-radius: 6px;
  font-size: 14px; color: var(--indigo-90);
}
.meta { color: var(--text-faint); font-size: 14.5px; }
.callout {
  margin: 26px 0; padding: 18px 22px;
  border-left: 3px solid var(--indigo-50);
  background: rgba(108, 90, 214, 0.09);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.callout p { margin: 0; color: var(--text); }

/* ---------------------------------------------------------------- footer */
footer {
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  padding: 52px 0 60px; margin-top: 40px;
  color: var(--text-faint); font-size: 14.5px;
}
footer .cols { display: flex; flex-wrap: wrap; gap: 40px; justify-content: space-between; }
footer a { color: var(--text-dim); text-decoration: none; display: block; padding: 4px 0; }
footer a:hover { color: var(--text); }
footer h4 { color: var(--text); font-size: 14px; margin: 0 0 8px; letter-spacing: 0.02em; }

/* ---------------------------------------------------------------- reveal
   Scroll-triggered reveal. The .reveal class only *adds* a transform, and
   site.js removes it as elements enter view — so with JS disabled or broken the
   content is simply visible, never stuck invisible. */
/* The hidden state is scoped to .js-reveal, which an inline script in <head> adds and then
   unconditionally removes after a short floor. Consequences, all deliberate:
     - JS disabled  -> .js-reveal is never added, content is simply visible, no effect.
     - site.js 404s -> the inline script still removes the class, so content appears anyway.
     - happy path   -> site.js adds .in per element as it scrolls into view.
   The previous version hid content in plain CSS and relied on site.js to un-hide it, which
   means any failure to load that one file left the whole page blank. */
.js-reveal .reveal { opacity: 0; transform: translateY(18px); }
.js-reveal .reveal.in { opacity: 1; transform: none; transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .mesh span, .lamp-xl { animation: none !important; }
  .js-reveal .reveal, .js-reveal .reveal.in { opacity: 1; transform: none; transition: none; }
  .card:hover, .shot:hover, .btn:hover { transform: none; }
}

@media (max-width: 640px) {
  .nav nav { gap: 14px; }
  .nav nav a.hide-sm { display: none; }
  body { font-size: 16px; }
}

/* A button is a target, not a paragraph. Without this the header CTA wrapped
   "Get the app" onto three lines at 390px once the SOON badge was added to it,
   which pushed the whole bar out of shape. */
.btn { white-space: nowrap; }

@media (max-width: 430px) {
  /* At this width the brand, one link and the CTA no longer all fit. The CTA is
     the only one of the three that has to survive, and the link it would push
     out is reachable from the page itself a screen further down. */
  .nav nav a:not(.btn) { display: none; }
  .nav .wrap { gap: 12px; }
}
