/* ================================================================
   Factual — landing page
   Desktop: single non-scrolling stage with floating bubbles + hover.
   Mobile : scrolling page (light hero + dark feature sections).
   ================================================================ */

:root {
  --accent: #e97232;          /* brand dark-orange */
  --ink: #111111;             /* primary text on light */
  --ink-soft: #2b2b2b;
  --paper: #ffffff;           /* light background */
  --dark: #0e0e0e;            /* mobile dark sections */
  --dark-ink: #f4f1ea;        /* text on dark */
  --dark-soft: #b9b4ab;
  --serif: "Literata", Georgia, "Times New Roman", serif;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --dim: 0.1;                 /* opacity of everything else on hover */
}

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

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* shared accent */
.accent { color: var(--accent); }

/* ---------- shared: app icon (NO shadow per design) ---------- */
.app-icon {
  width: 64px; height: 64px;
  border-radius: 16px;
  display: block;
  flex: none;
}

/* ---------- shared: App Store badge ---------- */
.appstore { display: inline-block; text-decoration: none; line-height: 0; }
.appstore-badge {
  display: block;
  width: 140px; height: auto;
  transition: transform .15s ease, opacity .15s ease;
}
.appstore:hover .appstore-badge { transform: translateY(-1px); }

/* ---------- shared: real screenshot (transparent phone mockup, NO shadow) ---------- */
.shot {
  display: block;
  width: auto;
  height: auto;
}

/* placeholder box (used where a screenshot is not supplied yet) */
.shot-ph {
  position: relative;
  aspect-ratio: 295 / 600;
  border-radius: 38px;
  background: #1b1b1b;
  border: 1px solid rgba(255,255,255,.08);
  overflow: hidden;
}
.shot-ph::after {
  content: attr(data-label);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--sans);
  font-size: 13px; letter-spacing: .08em; text-transform: uppercase;
  color: #6f6a62;
}

/* ================================================================
   DESKTOP STAGE
   ================================================================ */
.stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--paper);
}

/* animated grain — kept subtle so the blobs stay vivid */
.grain {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: .28;
  mix-blend-mode: soft-light;
  pointer-events: none;
  z-index: 5;
}

/* generic dim behaviour: anything .dimmable fades when a bubble is hovered */
.dimmable { transition: opacity .35s ease; }
.stage:has(.bubble:hover) .dimmable { opacity: var(--dim); }
/* keep the hovered bubble fully visible */
.stage .bubble:hover { opacity: 1; }

/* ---- hero ---- */
.hero {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  width: min(860px, 90vw);
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}
.hero .app-icon { margin-bottom: 36px; }
.hero .headline { margin: 0; }
.hero .appstore { margin-top: 30px; }

/* intro sequence (desktop): words first (app onboarding timings), then
   the app icon + App Store badge together, then the footer — and the
   bubbles fly out from the centre last. */
.stage .hero .app-icon { animation: riseUp .7s cubic-bezier(.16,1,.3,1) 7.5s backwards; }
.stage .hero .appstore { animation: dropDown .7s cubic-bezier(.16,1,.3,1) 7.5s backwards; }
.stage .stage-header,
.stage .stage-footer   { animation: wordIn .6s ease-out 7.9s backwards; }

.headline {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(28px, 3.0vw, 43px);
  line-height: 1.18;
  letter-spacing: -.005em;
  color: var(--ink);
}
/* per-word reveal — each .w carries its own --d delay inline, matching
   the app's onboarding schedule. inline-block so blur/offset transform. */
.headline .w {
  display: inline-block;
  animation: wordIn .5s ease-out var(--d, 0s) backwards;
}

/* ================================================================
   FLOATING BUBBLES + BLOBS
   Each feature's blob and text label drift together (they share the
   same per-feature drift vars), ~20-30px, in their own direction.
   On hover of any bubble the whole scene freezes in place
   (animation-play-state: paused) so the hovered bubble stops exactly
   where it was.
   ================================================================ */

/* per-feature drift vector + timing — applied to BOTH the blob and the
   text label of that feature (both carry the same data-f), so they move
   in perfect lockstep.
   --fromx/--fromy = vector from the resting spot back to viewport centre
   (50vw-X, 50vh-Y), used by the intro fly-out so each bubble starts
   stacked at the centre and flies to its place. */
[data-f="headlines"]  { --dx:22px;  --dy:-16px; --dur:13s; --fromx:26.8vw;  --fromy:28.2vh; }
[data-f="digest"]     { --dx:-18px; --dy:20px;  --dur:15s; --fromx:33.1vw;  --fromy:19vh; }
[data-f="read-later"] { --dx:24px;  --dy:14px;  --dur:14s; --fromx:-17.6vw; --fromy:35.7vh; }
[data-f="translate"]  { --dx:-20px; --dy:-22px; --dur:16s; --fromx:-40.8vw; --fromy:-1.5vh; }
[data-f="summarize"]  { --dx:18px;  --dy:23px;  --dur:12s; --fromx:-37.6vw; --fromy:-13.9vh; }
[data-f="factcheck"]  { --dx:-24px; --dy:-14px; --dur:15s; --fromx:22.8vw;  --fromy:-33.3vh; }
[data-f="reading"]    { --dx:20px;  --dy:-20px; --dur:13s; --fromx:-23.2vw; --fromy:-34.4vh; }

/* the drift uses the standalone `translate` property so it composes on
   top of the `transform: translate(-50%,-50%)` centering without
   overriding it. */
@keyframes drift {
  0%, 100% { translate: 0 0; }
  50%      { translate: var(--dx, 20px) var(--dy, -16px); }
}

/* intro: word / icon / badge reveal (mirrors the app's onboarding:
   opacity 0->1, blur 6->0, slight upward settle, ease-out 0.5s). */
@keyframes wordIn {
  from { opacity: 0; filter: blur(6px); transform: translateY(-6px); }
  to   { opacity: 1; filter: blur(0);   transform: translateY(0); }
}

/* icon rises from below; badge descends from above — both blur->sharp. */
@keyframes riseUp {
  from { opacity: 0; filter: blur(8px); transform: translateY(42px); }
  to   { opacity: 1; filter: blur(0);   transform: translateY(0); }
}
@keyframes dropDown {
  from { opacity: 0; filter: blur(8px); transform: translateY(-42px); }
  to   { opacity: 1; filter: blur(0);   transform: translateY(0); }
}

/* intro: bubbles + blobs fly out from the centre and slow to a stop —
   no overshoot/bounce; a strong-deceleration easing (applied on the
   animation) gives the "dive into water" feel. They're blurred in
   flight and sharpen to their resting blur by the end. Uses individual
   `translate`/`scale` so it composes with the `transform:
   translate(-50%,-50%)` centering; `backwards` fill keeps them
   collapsed/invisible until their delay, and releases cleanly to base
   afterwards so the hover-dim opacity still works and `drift` takes
   over the `translate`. */
@keyframes flyOut {
  0%   { translate: var(--fromx,0) var(--fromy,0); scale: .5; opacity: 0; filter: blur(var(--flyblur-start, 8px)); pointer-events: none; }
  28%  { opacity: 1; }
  100% { translate: 0 0; scale: 1; opacity: 1; filter: blur(var(--flyblur-end, 0px)); pointer-events: auto; }
}

/* ---- blobs ---- */
.blobs { position: absolute; inset: 0; z-index: 1; }
.blob {
  position: absolute;
  left: var(--x); top: var(--y);
  width: 380px; height: 320px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  filter: blur(40px);
  opacity: 1;
  /* in flight: extra-blurred, settling back to the resting 40px haze */
  --flyblur-start: 80px;
  --flyblur-end: 40px;
  will-change: translate, scale, filter;
  animation: flyOut 1.9s cubic-bezier(.12, .8, .2, 1) 8.3s backwards,
             drift var(--dur, 14s) ease-in-out 10.2s infinite;
}
.blob[data-f="headlines"]  { --x:23.2%; --y:21.8%;
  background:
    radial-gradient(closest-side, rgba(96,130,255,.95), transparent 72%) -45px -10px / 70% 80% no-repeat,
    radial-gradient(closest-side, rgba(255,201,74,.95), transparent 72%) 85px 18px / 66% 72% no-repeat,
    radial-gradient(closest-side, rgba(168,108,255,.7), transparent 72%) 28px 42px / 56% 60% no-repeat; }
.blob[data-f="digest"]     { --x:16.9%; --y:31.0%; width:330px; height:270px;
  background:
    radial-gradient(closest-side, rgba(86,140,255,.92), transparent 72%) -30px -10px / 70% 80% no-repeat,
    radial-gradient(closest-side, rgba(255,140,52,.95), transparent 72%) 52px 30px / 66% 72% no-repeat; }
.blob[data-f="read-later"] { --x:67.6%; --y:14.3%;
  background:
    radial-gradient(closest-side, rgba(255,214,74,.95), transparent 72%) -30px -10px / 70% 76% no-repeat,
    radial-gradient(closest-side, rgba(86,200,120,.9), transparent 72%) 52px 30px / 66% 72% no-repeat; }
.blob[data-f="translate"]  { --x:90.8%; --y:51.5%;
  background:
    radial-gradient(closest-side, rgba(255,130,52,.95), transparent 72%) 0 0 / 76% 80% no-repeat,
    radial-gradient(closest-side, rgba(255,82,96,.85), transparent 72%) 28px 42px / 62% 66% no-repeat; }
.blob[data-f="summarize"]  { --x:87.6%; --y:63.9%;
  background:
    radial-gradient(closest-side, rgba(255,82,96,.95), transparent 72%) -10px -10px / 70% 76% no-repeat,
    radial-gradient(closest-side, rgba(150,96,255,.9), transparent 72%) 52px 52px / 66% 72% no-repeat; }
.blob[data-f="factcheck"]  { --x:27.2%; --y:83.3%;
  background:
    radial-gradient(closest-side, rgba(82,196,120,.95), transparent 74%) 0 0 / 82% 82% no-repeat; }
.blob[data-f="reading"]    { --x:73.2%; --y:84.4%;
  background:
    radial-gradient(closest-side, rgba(178,138,255,.9), transparent 72%) -10px 0 / 76% 80% no-repeat,
    radial-gradient(closest-side, rgba(255,170,120,.72), transparent 72%) 40px 20px / 62% 66% no-repeat; }

/* ---- bubbles (text labels) ---- */
/* The container spans the whole stage (inset:0) above the hero, so it must
   stay click-through — otherwise it swallows clicks meant for the hero's
   App Store badge below it. Only the bubbles themselves are interactive. */
.bubbles { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.bubble {
  position: absolute;
  left: var(--x); top: var(--y);
  transform: translate(-50%, -50%);
  appearance: none; border: 0; background: none; padding: 6px 10px;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.3;
  color: var(--ink);
  text-align: center;
  cursor: pointer;
  pointer-events: auto;
  white-space: nowrap;
  /* in flight: blurred, sharpening to crisp text by the end */
  --flyblur-start: 7px;
  --flyblur-end: 0px;
  will-change: translate, scale, filter;
  animation: flyOut 1.9s cubic-bezier(.12, .8, .2, 1) 8.3s backwards,
             drift var(--dur, 14s) ease-in-out 10.2s infinite;
}

/* FREEZE: while any bubble is hovered, pause every blob and bubble so
   the hovered one stops exactly where it was. */
.stage:has(.bubble:hover) .blob,
.stage:has(.bubble:hover) .bubble { animation-play-state: paused; }

/* ---- hover overlays ---- */
.overlays { position: absolute; inset: 0; z-index: 6; pointer-events: none; }
.overlay {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(.98);
  margin: 0;
  display: flex; flex-direction: column; align-items: center;
  gap: 20px;
  width: min(90vw, 540px);
  max-height: 100vh;
  opacity: 0;
  transition: opacity .3s ease, transform .3s ease;
}
.overlay .shot { height: min(66vh, 640px); width: auto; max-width: 90vw; }
.overlay figcaption { text-align: center; max-width: 460px; }
.overlay h2 {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(22px, 2vw, 28px); line-height: 1.2;
  margin: 0 0 8px; color: var(--ink);
}
.overlay p {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(15px, 1.2vw, 17px); line-height: 1.45;
  margin: 0; color: var(--ink-soft);
}

/* show the matching overlay while its bubble is hovered */
.stage:has(.bubble[data-f="headlines"]:hover)  .overlay[data-f="headlines"],
.stage:has(.bubble[data-f="digest"]:hover)     .overlay[data-f="digest"],
.stage:has(.bubble[data-f="read-later"]:hover) .overlay[data-f="read-later"],
.stage:has(.bubble[data-f="translate"]:hover)  .overlay[data-f="translate"],
.stage:has(.bubble[data-f="summarize"]:hover)  .overlay[data-f="summarize"],
.stage:has(.bubble[data-f="factcheck"]:hover)  .overlay[data-f="factcheck"],
.stage:has(.bubble[data-f="reading"]:hover)    .overlay[data-f="reading"] {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* ---- stage header (top-right Support link) ---- */
.stage-header {
  position: absolute; top: 26px; right: 32px;
  z-index: 4;
  font-family: var(--sans); font-size: 14px;
}

/* ---- stage footer ---- */
.stage-footer {
  position: absolute; left: 0; right: 0; bottom: 26px;
  z-index: 4;
  display: flex; justify-content: space-between;
  padding: 0 32px;
  font-family: var(--sans); font-size: 14px;
}
.stage-header a,
.stage-footer a {
  color: var(--muted, #9a958c);
  text-decoration: none;
  transition: color .15s ease;
}
.stage-header a:hover,
.stage-footer a:hover { color: var(--accent); text-decoration: none; }

/* centered "made by [in] Nikita Belousov" credit */
.stage-footer .made-by {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--muted, #9a958c);
  transition: color .15s ease;
}
.stage-footer .made-by:hover { color: var(--accent); text-decoration: none; }
.li-icon { width: 18.4px; height: 18.4px; display: block; flex: none; margin-right: -3px; }

/* ================================================================
   MOBILE PAGE — hidden on desktop
   ================================================================ */
.mobile { display: none; }

/* ================================================================
   BREAKPOINT: switch desktop stage -> mobile scroll
   ================================================================ */
@media (max-width: 900px) {
  html, body { position: static; overflow: visible; }
  .stage { display: none; }
  .mobile { display: block; }
}

/* ---- mobile hero (light) ---- */
.m-hero {
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 40px 28px;
  background: var(--paper);
}
.m-hero .app-icon { margin-bottom: 36px; }
.m-hero .headline {
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(28px, 8vw, 40px); line-height: 1.18;
  margin: 0 0 36px; color: var(--ink);
}
.m-hero .appstore { align-self: flex-start; }

/* ---- mobile dark feature sections ---- */
.m-dark {
  background: var(--dark);
  color: var(--dark-ink);
  padding: 16px 28px 40px;
}
.m-feature, .m-closing {
  padding: 60px 0;
  text-align: center;
}
/* screenshots: NO shadow per design */
.m-feature .shot, .m-closing .shot {
  width: min(74%, 320px);
  height: auto;
  margin: 0 auto 34px;
}
.m-closing .shot-ph {
  width: min(72%, 300px);
  margin: 0 auto 34px;
  background: #1b1b1b;
  border-color: rgba(255,255,255,.08);
}
.m-feature h2, .m-closing h2 {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(18px, 4.9vw, 24px); line-height: 1.18;
  margin: 0 0 12px; color: var(--dark-ink);
}
.m-feature p, .m-closing p {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(15px, 4.2vw, 18px); line-height: 1.5;
  margin: 0 auto; max-width: 36ch; color: var(--dark-soft);
}
.m-closing .appstore { margin-top: 28px; }

.m-sep { border: 0; border-top: 1px solid rgba(255,255,255,.1); margin: 0; }

.m-footer {
  display: flex; justify-content: space-between;
  padding: 28px 0 6px;
  font-family: var(--sans); font-size: 14px;
}
.m-footer a { color: var(--accent); text-decoration: none; }
.m-footer a:hover { text-decoration: underline; }

/* ================================================================
   Reduced motion: stop the drift entirely
   ================================================================ */
@media (prefers-reduced-motion: reduce) {
  /* match the app's Reduce Motion: everything is simply present, no
     intro reveal, no drift, no fly-out. */
  .blob, .bubble,
  .headline .w,
  .stage .hero .app-icon,
  .stage .hero .appstore,
  .stage .stage-header,
  .stage .stage-footer { animation: none; }
  .grain animate { display: none; }
  .grain { opacity: .2; }
}
